diff -u --recursive --new-file v2.3.22/linux/CREDITS linux/CREDITS
--- v2.3.22/linux/CREDITS	Mon Oct  4 15:49:29 1999
+++ linux/CREDITS	Wed Oct 20 22:13:20 1999
@@ -860,7 +860,7 @@
 
 N: David Hinds
 E: dhinds@zen.stanford.edu
-W: http://hyper.stanford.edu/~dhinds
+W: http://tao.stanford.edu/~dhinds
 D: PCMCIA and CardBus stuff, PCMCIA-HOWTO, PCMCIA client drivers
 S: 2019 W. Middlefield Rd #1
 S: Mountain View, CA  94043
@@ -907,14 +907,14 @@
 S: United Kingdom
 
 N: Ron Holt
-E: ron@caldera.com
+E: ron@holt.org
 W: http://www.holt.org/
-P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A  40 E3 FB 71 D1 C8 0B 56
+W: http://www.ronholt.com/
 D: Kernel development
-D: Minor kernel modifications to support Wabi and Wine
-S: Caldera, Inc.
-S: 240 West Center Street
-S: Orem, Utah 84059-1920
+D: Kernel LDT modifications to support Wabi and Wine
+S: Holtron Internetics, Inc.
+S: 998 East 900 South, Suite 26
+S: Provo, Utah 84606-5607
 S: USA
 
 N: Rob W. W. Hooft
@@ -1323,11 +1323,11 @@
 S: Czech Republic
 
 N: Paul Mackerras
-E: paulus@cs.anu.edu.au
+E: paulus@linuxcare.com
 D: Linux port for PCI Power Macintosh
-S: Dept. of Computer Science
-S: Australian National University
-S: Canberra  ACT  0200
+S: Linuxcare, Inc.
+S: 24 Marcus Clarke Street
+S: Canberra ACT 2601
 S: Australia
 
 N: Pat Mackinlay
diff -u --recursive --new-file v2.3.22/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.22/linux/Documentation/Changes	Fri Oct 15 15:25:13 1999
+++ linux/Documentation/Changes	Wed Oct 20 21:33:12 1999
@@ -43,7 +43,7 @@
 encountered a bug!  If you're unsure what version you're currently
 running, the suggested command should tell you.
 
-- Kernel modutils	 2.3.5                   ; insmod -V
+- Kernel modutils	 2.3.6                   ; insmod -V
 - Gnu C 		 2.7.2.3                 ; gcc --version
 - Binutils		 2.8.1.0.23              ; ld -v
 - Linux libc5 C Library	 5.4.46                  ; ls -l /lib/libc*
@@ -60,7 +60,7 @@
 - NFS                    2.2beta40               ; showmount --version
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
-- Pcmcia-cs              3.0.7                   ; cardmgr -V
+- Pcmcia-cs              3.1.2                   ; cardmgr -V
 - PPP                    2.3.9                   ; pppd --version
 - Util-linux             2.9i                    ; chsh -v
 
@@ -567,8 +567,8 @@
 Modules utilities
 =================
 
-The 2.3.5 release:
-ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.5.tar.gz
+The 2.3.6 release:
+ftp://ftp.ocs.com.au/pub/modutils/v2.3/modutils-2.3.6.tar.gz
 
 Procps utilities
 ================
@@ -684,8 +684,8 @@
 Pcmcia-cs
 =========
 
-The 3.0.7 release:
-ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.7.tar.gz
+The 3.1.2 release:
+ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.2.tar.gz
 
 Setserial
 =========
diff -u --recursive --new-file v2.3.22/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.22/linux/Documentation/Configure.help	Fri Oct 15 15:25:13 1999
+++ linux/Documentation/Configure.help	Wed Oct 20 21:33:12 1999
@@ -175,18 +175,25 @@
   on the Alpha. The only time you would ever not say Y is to say M in
   order to debug the code. Say Y unless you know what you are doing.
 
-Big memory support
-CONFIG_BIGMEM
-  Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory.
-  If you are compiling a kernel which will never run on a machine with
-  more than 1 Gigabyte, answer N here. Otherwise, say Y.
-
-  The actual amount of physical memory should be specified using a
-  kernel command line option such as "mem=256M". (Try "man bootparam"
-  or see the documentation of your boot loader (lilo or loadlin) about
-  how to pass options to the kernel at boot time. The lilo procedure
-  is also explained in the SCSI-HOWTO, available from
-  http://metalab.unc.edu/mdw/linux.html#howto .)
+High Memory support
+CONFIG_NOHIGHMEM
+  If you are compiling a kernel which will never run on a machine
+  with more than 1 Gigabyte total physical RAM, answer "off"
+  here (default choice).
+
+  Linux can use up to 64 Gigabytes of physical memory on x86 systems.
+  High memory is all the physical RAM that could not be directly
+  mapped by the kernel - ie. 3GB if there is 4GB RAM in the system,
+  7GB if there is 8GB RAM in the system.
+
+  If 4 Gigabytes physical RAM or less is used then answer "4GB" here.
+
+  If more than 4 Gigabytes is used then answer "64GB" here. This
+  selection turns Intel PAE (Physical Address Extension) mode on.
+  PAE implements 3-level paging on IA32 processors. PAE is fully
+  supported by Linux, PAE mode is implemented on all recent Intel
+  processors (PPro and better). NOTE: The "64GB" kernel will not
+  boot CPUs that not support PAE!
 
 Normal PC floppy disk support
 CONFIG_BLK_DEV_FD
@@ -578,12 +585,6 @@
 
   If in doubt, say N.
 
-Winbond SL82c105 support
-CONFIG_BLK_DEV_SL82C105
-  If you have a Winbond SL82c105 IDE controller, say Y here to enable
-  special configuration for this chip. This is common on various CHRP
-  motherboards, but could be used elsewhere. If in doubt, say Y.
-
 Boot off-board chipsets first support
 CONFIG_BLK_DEV_OFFBOARD
   Normally, IDE controllers built into the motherboard (on-board
@@ -621,82 +622,32 @@
   It is normally safe to answer Y to this question unless your
   motherboard uses a VIA VP2 chipset, in which case you should say N.
 
-Other IDE chipset support
-CONFIG_IDE_CHIPSETS
-  Say Y here if you want to include enhanced support for various IDE
-  interface chipsets used on motherboards and add-on cards. You can
-  then pick your particular IDE chip from among the following options.
-  This enhanced support may be necessary for Linux to be able to
-  access the 3rd/4th drives in some systems. It may also enable
-  setting of higher speed I/O rates to improve system performance with
-  these chipsets. Most of these also require special kernel boot
-  parameters to actually turn on the support at runtime; you can find
-  a list of these in the file Documentation/ide.txt.
-  
-  People with SCSI-only systems can say N here. 
-
-Generic 4 drives/port support
-CONFIG_BLK_DEV_4DRIVES
-  Certain older chipsets, including the Tekram 690CD, use a single set
-  of I/O ports at 0x1f0 to control up to four drives, instead of the
-  customary two drives per port. Support for this can be enabled at
-  runtime using the "ide0=four" kernel boot parameter if you say Y
-  here.
-
-DTC-2278 support
-CONFIG_BLK_DEV_DTC2278
-  This driver is enabled at runtime using the "ide0=dtc2278" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the DTC-2278 card, and permits faster I/O speeds to be set as
-  well. See the Documentation/ide.txt and drivers/block/dtc2278.c
-  files for more info.
-
-Holtek HT6560B support
-CONFIG_BLK_DEV_HT6560B
-  This driver is enabled at runtime using the "ide0=ht6560b" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the Holtek card, and permits faster I/O speeds to be set as well.
-  See the Documentation/ide.txt and drivers/block/ht6560b.c files for
-  more info.
+AEC6210 chipset support
+CONFIG_BLK_DEV_AEC6210
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This add-on card is a bootable PCI UDMA controller. In
+  order to get this card to initialize correctly in some cases, you
+  should say Y here, and preferably also to "Use DMA by default when
+  available".
 
-PROMISE DC4030 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC4030
-  This driver provides support for the secondary IDE interface and
-  cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
-  is known to incur timeouts/retries during heavy I/O to drives
-  attached to the secondary interface. CDROM and TAPE devices are not
-  supported yet. This driver is enabled at runtime using the
-  "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
-  and drivers/block/pdc4030.c files for more info.
+  Please read the comments at the top of drivers/block/aec6210.c
 
-PS/2 ESDI hard disk support
-CONFIG_BLK_DEV_PS2
-  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
-  hard disk.
-  
-  If you want to compile the driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called ps2esdi.o.
+ALI M15x3 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_ALI15X3
+  This driver ensures (U)DMA support for ALI 1543 and 1543C,
+  1535, 1535D onboard chipsets.  It also tests for Simplex mode and
+  enables normal dual channel support.
 
-Tekram TRM290 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_TRM290
-  This driver adds support for bus master DMA transfers
-  using the Tekram TRM290 PCI IDE chip. Volunteers are
-  needed for further tweaking and development.
-  Please read the comments at the top of drivers/block/trm290.c.
+  If you say Y here, you also need to say Y to "Use DMA by default
+  when available", above.
 
-OPTi 82C621 enhanced support (EXPERIMENTAL)
-CONFIG_BLK_DEV_OPTI621
-  This is a driver for the OPTi 82C621 EIDE controller.
-  Please read the comments at the top of drivers/block/opti621.c.
+  Please read the comments at the top of drivers/block/alim15x3.c
 
-NS87415 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_NS87415
-  This driver adds detection and support for the NS87415 chip
-  (used in SPARC64, among others).
+  If unsure, say N.
 
-  Please read the comments at the top of drivers/block/ns87415.c.
+CMD646 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_CMD646
+  Say Y here if you have an IDE controller which uses this chipset.
 
 CY82C693 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_CY82C693
@@ -706,36 +657,80 @@
   If you say Y here, you need to say Y to "Use DMA by default
   when available" as well.
 
-VIA82C586 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_VIA82C586
-  Saying Y here adds initial timing settings for VIA (U)DMA onboard
-  IDE controllers that are ATA3 compliant. May work with ATA4 systems,
-  but not tested to date. To use some features of this chipset, you
-  will have to issue a kernel command line as described in the file
-  drivers/block/via82c586.c. Furthermore, if you also say Y to "/proc
-  filesystem support" and set DISPLAY_APOLLO_TIMINGS in via82c586.c,
-  you will be able to read information about the IDE controller from
-  the virtual file /proc/ide/via.
+HPT34X chipset support
+CONFIG_BLK_DEV_HPT34X
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT343 chipset in its current form is a non-bootable
+  controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
+  PCI UDMA controllers. This driver requires dynamic tuning of the
+  chipset during the ide-probe at boot time. It is reported to support
+  DVD II drives, by the manufacturer.
 
-  If you say Y here, you also need to say Y to "Use DMA by default
-  when available", above.
+HPT34X DMA support (EXPERIMENTAL)
+CONFIG_BLK_DEV_HPT34X_DMA
+  you need to say Y to "Use DMA by default when available" if you say
+  Y here.
+
+  Please read the comments at the top of drivers/block/hpt34x.c
+
+HPT366 chipset support
+CONFIG_BLK_DEV_HPT366
+  This is an Ultra DMA chipset for ATA-66.
+  
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. The HPT366 chipset in its current form is a non-bootable.
+  This driver requires dynamic tuning of the chipset during the
+  ide-probe at boot. It is reported to support DVD II drives, by the
+  manufacturer.
+
+  Please read the comments at the top of drivers/block/hpt366.c
+
+HPT366 (EXPERIMENTAL)
+CONFIG_BLK_DEV_HPT366_SHARED
+  This requires CONFIG_BLK_DEV_HPT366.
+  It appears that there are different versions or releases of this hardware
+  by ABit.  Since some cases the second channel of the onboard chipset works
+  and others fail, it is default disabled.  This is required to be set if you
+  want to attempt the setup of the second channel.
+
+  JUMBO WARNING, do not boot a kernel with this enabled if it is your only
+  one.  You may not be able to get back into your machine without physically
+  detaching the attached devices.
 
   If unsure, say N.
 
-CMD646 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_CMD646
-  Say Y here if you have an IDE controller which uses this chipset.
+NS87415 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_NS87415
+  This driver adds detection and support for the NS87415 chip
+  (used in SPARC64, among others).
 
-ALI M15x3 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_ALI15X3
-  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
-  onboard chipsets.  It also tests for Simplex mode and enables
-  normal dual channel support.
+  Please read the comments at the top of drivers/block/ns87415.c.
 
-  If you say Y here, you also need to say Y to "Use DMA by default
-  when available", above.
+OPTi 82C621 enhanced support (EXPERIMENTAL)
+CONFIG_BLK_DEV_OPTI621
+  This is a driver for the OPTi 82C621 EIDE controller.
+  Please read the comments at the top of drivers/block/opti621.c.
 
-  Please read the comments at the top of drivers/block/alim15x3.c
+Intel PIIXn chipsets support
+CONFIG_BLK_DEV_PIIX
+  This driver adds PIO mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly tune
+  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
+  via the standard end-user tool 'hdparm'.
+
+  Please read the comments at the top of drivers/block/piix.c
+
+  If unsure, say N.
+
+PIIXn Tuning support
+CONFIG_BLK_DEV_PIIX_TUNING
+  This driver extension adds DMA mode setting and tuning for all PIIX
+  IDE controllers by Intel. Since the BIOS can sometimes improperly
+  set up the device/adapter combination and speed limits, it has
+  become a necessity to back/forward speed devices as needed.
+
+  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
+  2 if the BIOS can not perform this task at initialization.
 
   If unsure, say N.
 
@@ -767,7 +762,7 @@
 
   If unsure, say N.
 
-Special UDMA Feature (EXPERIMENTAL)
+Special UDMA Feature
 PDC202XX_FORCE_BURST_BIT
   For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally
   for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
@@ -777,71 +772,97 @@
 
   If unsure, say N.
 
-Special Mode Feature (DANGEROUS)
+Special Mode Feature (EXPERIMENTAL)
 PDC202XX_FORCE_MASTER_MODE
   For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for
   possible Hardware RAID 0,1 for the FastTrak Series.
 
   Say N. 
 
-AEC6210 chipset support
-CONFIG_BLK_DEV_AEC6210
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. This add-on card is a bootable PCI UDMA controller. In
-  order to get this card to initialize correctly in some cases, you
-  should say Y here, and preferably also to "Use DMA by default when
-  available".
+Winbond SL82c105 support
+CONFIG_BLK_DEV_SL82C105
+  If you have a Winbond SL82c105 IDE controller, say Y here to enable
+  special configuration for this chip. This is common on various CHRP
+  motherboards, but could be used elsewhere. If in doubt, say Y.
 
-  Please read the comments at the top of drivers/block/aec6210.c
+Tekram TRM290 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_TRM290
+  This driver adds support for bus master DMA transfers
+  using the Tekram TRM290 PCI IDE chip. Volunteers are
+  needed for further tweaking and development.
+  Please read the comments at the top of drivers/block/trm290.c.
 
-HPT366 chipset support
-CONFIG_BLK_DEV_HPT366
-  This is an Ultra DMA chipset for ATA-66.
-  
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT366 chipset in its current form is a non-bootable.
-  This driver requires dynamic tuning of the chipset during the
-  ide-probe at boot. It is reported to support DVD II drives, by the
-  manufacturer.
- 
-Intel PIIXn chipsets support
-CONFIG_BLK_DEV_PIIX
-  This driver adds PIO mode setting and tuning for all PIIX IDE
-  controllers by Intel.  Since the BIOS can sometimes improperly tune
-  PIO 0-4 mode settings, this allows dynamic tuning of the chipset
-  via the standard end-user tool 'hdparm'.
+VIA82CXXX chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_VIA82CXXX
+   This allows you to to configure your chipset for a better use while
+   running (U)DMA: it will allow you to enable efficiently the second
+   channel dma usage, as it is may not be set by BIOS. It allows you to
+   run a kernel command line at boot time in order to set fifo config.
+   If no command line is provided, it will try to set fifo configuration
+   at its best. It will allow you to get a proc/ide/via display
+  (while running a "cat") provided you enabled "proc" support.
+  Please read the comments at the top of drivers/block/via82cxxx.c
 
-  Please read the comments at the top of drivers/block/piix.c
+  If you say Y here, you also need to say Y to "Use DMA by default
+  when available", above.
 
   If unsure, say N.
 
-PIIXn Tuning support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PIIX_TUNING
-  This driver extension adds DMA mode setting and tuning for all PIIX
-  IDE controllers by Intel. Since the BIOS can sometimes improperly
-  set up the device/adapter combination and speed limits, it has
-  become a necessity to back/forward speed devices as needed.
+Other IDE chipset support
+CONFIG_IDE_CHIPSETS
+  Say Y here if you want to include enhanced support for various IDE
+  interface chipsets used on motherboards and add-on cards. You can
+  then pick your particular IDE chip from among the following options.
+  This enhanced support may be necessary for Linux to be able to
+  access the 3rd/4th drives in some systems. It may also enable
+  setting of higher speed I/O rates to improve system performance with
+  these chipsets. Most of these also require special kernel boot
+  parameters to actually turn on the support at runtime; you can find
+  a list of these in the file Documentation/ide.txt.
+  
+  People with SCSI-only systems can say N here. 
 
-  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode
-  2 if the BIOS can not perform this task at initialization.
+Generic 4 drives/port support
+CONFIG_BLK_DEV_4DRIVES
+  Certain older chipsets, including the Tekram 690CD, use a single set
+  of I/O ports at 0x1f0 to control up to four drives, instead of the
+  customary two drives per port. Support for this can be enabled at
+  runtime using the "ide0=four" kernel boot parameter if you say Y
+  here.
 
-  If unsure, say N.
+ALI M14xx support
+CONFIG_BLK_DEV_ALI14XX
+  This driver is enabled at runtime using the "ide0=ali14xx" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
+  I/O speeds to be set as well. See the files Documentation/ide.txt
+  and drivers/block/ali14xx.c for more info.
 
-HPT34X chipset support
-CONFIG_BLK_DEV_HPT34X
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT343 chipset in its current form is a non-bootable
-  controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
-  PCI UDMA controllers. This driver requires dynamic tuning of the
-  chipset during the ide-probe at boot time. It is reported to support
-  DVD II drives, by the manufacturer.
+DTC-2278 support
+CONFIG_BLK_DEV_DTC2278
+  This driver is enabled at runtime using the "ide0=dtc2278" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the DTC-2278 card, and permits faster I/O speeds to be set as
+  well. See the Documentation/ide.txt and drivers/block/dtc2278.c
+  files for more info.
 
-HPT34X DMA support (DANGEROUS)
-CONFIG_BLK_DEV_HPT34X_DMA
-  you need to say Y to "Use DMA by default when available" if you say
-  Y here.
+Holtek HT6560B support
+CONFIG_BLK_DEV_HT6560B
+  This driver is enabled at runtime using the "ide0=ht6560b" kernel
+  boot parameter. It enables support for the secondary IDE interface
+  of the Holtek card, and permits faster I/O speeds to be set as well.
+  See the Documentation/ide.txt and drivers/block/ht6560b.c files for
+  more info.
 
-  Please read the comments at the top of drivers/block/hpt343.c
+PROMISE DC4030 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PDC4030
+  This driver provides support for the secondary IDE interface and
+  cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver
+  is known to incur timeouts/retries during heavy I/O to drives
+  attached to the secondary interface. CDROM and TAPE devices are not
+  supported yet. This driver is enabled at runtime using the
+  "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt
+  and drivers/block/pdc4030.c files for more info.
 
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
@@ -858,13 +879,15 @@
   See the files Documentation/ide.txt and drivers/block/umc8672.c for
   more info.
 
-ALI M14xx support
-CONFIG_BLK_DEV_ALI14XX
-  This driver is enabled at runtime using the "ide0=ali14xx" kernel
-  boot parameter. It enables support for the secondary IDE interface
-  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
-  I/O speeds to be set as well. See the files Documentation/ide.txt
-  and drivers/block/ali14xx.c for more info.
+PS/2 ESDI hard disk support
+CONFIG_BLK_DEV_PS2
+  Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
+  hard disk.
+  
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called ps2esdi.o.
 
 Amiga builtin Gayle IDE interface support
 CONFIG_BLK_DEV_GAYLE
@@ -1809,20 +1832,41 @@
 
   If unsure, say Y.
 
-PCMCIA/Cardbus support
+PCMCIA/CardBus support
 CONFIG_PCMCIA
-  Say Y here if you want to attach PCMCIA's (PC-cards) to your Linux
-  computer. These are credit-card size devices such as network cards,
-  modems or hard drives popular with laptops.
+  Include kernel support for PCMCIA and CardBus devices.  Because
+  PCMCIA support requires additional components that are not part of
+  the kernel (i.e., the pcmcia-cs package), building PCMCIA into the
+  kernel is generally not recommended unless you have a specific
+  need.  If unsure, 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).
+  When compiled this way, there will be modules called pcmcia_core.o
+  and ds.o.  If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
 
   You will also need David Hinds' pcmcia-cs package (see the file
-  Documentation/Changes for location).
+  Documentation/Changes for location).  For more information, see the
+  PCMCIA-HOWTO.
 
 CardBus support
 CONFIG_CARDBUS
-  CardBus is a bus mastering architecture for PC-cards (it allows
-  PC-cards to talk to the rest of the stuff inside your computer). If
-  unsure, say Y.
+  There are two types of PCMCIA devices: 16-bit PC Cards, and higher
+  performance 32-bit CardBus devices.  Use this option to include
+  support for CardBus devices.  If unsure, say Y.
+
+i82365/Yenta compatible bridge support
+CONFIG_I82365
+  Include support for PCMCIA and CardBus host bridges that are
+  register compatible with the Intel i82365 and/or the Yenta
+  specification: this includes virtually all modern PCMCIA bridges.
+  If unsure, say Y.
+
+Databook TCIC host bridge support
+CONFIG_TCIC
+  Include support for the Databook TCIC family of PCMCIA host bridges.
+  These are only found on a handful of old systems.  If unsure, say N.
 
 System V IPC
 CONFIG_SYSVIPC
@@ -5455,10 +5499,48 @@
   say M here and read Documentation/modules.txt. The module will be
   called x25_asy.o. If unsure, say N.
 
-PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...)
+PCMCIA network device support
+CONFIG_NET_PCMCIA
+  Say Y if you would like to include support for any PCMCIA network
+  adapters.  If unsure, say N.
+
+3Com 3c589 PCMCIA support
+CONFIG_PCMCIA_3C589
+  Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
+  (PC-card) Ethernet card to your computer.
+
+  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 will be called 3c589_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+3Com 3c574 PCMCIA support
+CONFIG_PCMCIA_3C574
+  Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
+  (PC-card) Fast Ethernet card to your computer.
+
+  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 will be called 3c574_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+Fujitsu FMV-J18x PCMCIA support
+CONFIG_PCMCIA_FMVJ18X
+  Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
+  PCMCIA (PC-card) Ethernet card to your computer.
+
+  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 will be called fmvj18x_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+NE2000 compatible PCMCIA support
 CONFIG_PCMCIA_PCNET
   Say Y here if you intend to attach an NE2000 compatible PCMCIA
-  (PC-card) Ethernet networking card to your computer.
+  (PC-card) Ethernet or Fast Ethernet card to your computer.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5466,18 +5548,40 @@
   module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
-3Com 3c589 PCMCIA card
-CONFIG_PCMCIA_3C589
-  Say Y here if you intend to attach a 3Com 3c589 PCMCIA
-  (PC-card) Ethernet networking card to your computer.
+New Media PCMCIA support
+CONFIG_PCMCIA_NMCLAN
+  Say Y here if you intend to attach a New Media Ethernet or LiveWire
+  PCMCIA (PC-card) Ethernet card to your computer.
 
   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 will be called 3c589_cs.o. If you want to compile it as a
+  The module will be called nmclan_cs.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
-Aviator/Raytheon 2.4MHz wireless
+SMC 91Cxx PCMCIA support
+CONFIG_PCMCIA_SMC91C92
+  Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
+  (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+  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 will be called smc91c92_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+Xircom 16-bit PCMCIA support
+CONFIG_PCMCIA_XIRC2PS
+  Say Y here if you intend to attach a Xircom 16-bit PCMCIA
+  (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+  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 will be called xirc2ps_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+Aviator/Raytheon 2.4MHz wireless support
 CONFIG_PCMCIA_RAYCS
   Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
   (PC-card) wireless Ethernet networking card to your computer.
@@ -5488,6 +5592,29 @@
   module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
+Xircom Netwave AirSurfer wireless support
+CONFIG_PCMCIA_NETWAVE
+  Say Y here if you intend to attach a Xircom Netwave AirSurfer PCMCIA
+  (PC-card) wireless Ethernet networking card to your computer.
+
+  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 will be called netwave_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
+AT&T/Lucent Wavelan wireless support
+CONFIG_PCMCIA_WAVELAN
+  Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA
+  (PC-card) wireless Ethernet networking card to your computer.  This
+  driver is for the non-IEEE-802.11 Wavelan cards.
+
+  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 will be called wavelan_cs.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
+
 PLIP (parallel port) support
 CONFIG_PLIP
   PLIP (Parallel Line Internet Protocol) is used to create a
@@ -12164,18 +12291,44 @@
 CONFIG_ARCH_NETWINDER
   Say Y here if you intend to run this kernel on the NetWinder.
 
-Maximum Physical Memory
+Virtual/Physical Memory Split
 CONFIG_1GB
-  Linux can use up to 2 Gigabytes (= 2^31 bytes) of physical memory.
-  If you are compiling a kernel which will never run on a machine with
-  more than 1 Gigabyte, answer "1GB" here. Otherwise, say "2GB".
-
-  The actual amount of physical memory should be specified using a
-  kernel command line option such as "mem=256M". (Try "man bootparam"
-  or see the documentation of your boot loader (lilo or loadlin) about
-  how to pass options to the kernel at boot time. The lilo procedure
-  is also explained in the SCSI-HOWTO, available from
-  http://metalab.unc.edu/mdw/linux.html#howto .)
+  If you are compiling a kernel which will never run on a machine
+  with more than 1 Gigabyte total physical RAM, answer "3GB/1GB"
+  here (default choice).
+
+  On 32-bit x86 systems Linux can use up to 64 Gigabytes of physical
+  memory. However 32-bit x86 processors have only 4 Gigabytes of
+  virtual memory space. This option specifies the maximum amount of
+  virtual memory space one process can potentially use. Certain types
+  of applications (eg. database servers) perform better if they have
+  as much virtual memory per process as possible.
+
+  The remaining part of the 4G virtual memory space is used by the
+  kernel to 'permanently map' as much physical memory as possible.
+  Certain types of applications perform better if there is more
+  'permanently mapped' kernel memory.
+
+  [WARNING! Certain boards do not support PCI DMA to physical addresses
+  bigger than 2 Gigabytes. Non-DMA-able memory must not be permanently
+  mapped by the kernel, thus a 1G/3G split will not work on such boxes.]
+
+  As you can see there is no 'perfect split' - the fundamental
+  problem is that 4G of 32-bit virtual memory space is short. So
+  you'll have to pick your own choice - depending on the application
+  load of your box. A 2G/2G split is typically a good choice for a
+  generic Linux server with lots of RAM.
+
+  Any potentially remaining (not permanently mapped) part of physical
+  memory is called 'high memory'. How much total high memory the kernel
+  can handle is influenced by the (next) High Memory configuration option.
+
+  The actual amount of total physical memory will either be
+  autodetected or can be forced by using a kernel command line option
+  such as "mem=256M". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time. The lilo procedure is also explained in the
+  SCSI-HOWTO, available from http://metalab.unc.edu/mdw/linux.html#howto .)
 
 Math emulation
 CONFIG_NWFPE
@@ -12786,7 +12939,7 @@
 # LocalWords:  KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb
 # LocalWords:  dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS
 # LocalWords:  nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
-# LocalWords:  Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs BIGMEM DAC IRQ's
+# LocalWords:  Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs HIGHMEM DAC IRQ's
 # LocalWords:  IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
 # LocalWords:  unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS
 # LocalWords:  BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Brutus linux/Documentation/arm/SA1100/Brutus
--- v2.3.22/linux/Documentation/arm/SA1100/Brutus	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/Brutus	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,36 @@
+Brutus is an evaluation platform for the SA1100 manufactured by Intel.  
+For more details, see:
+
+http://developer.intel.com/design/strong/applnots/sa1100lx/getstart.htm
+
+To compile for Brutus, you must issue the following comands:
+
+	make brutus_config
+	make config
+	[accept all the defaults]
+	make dep
+	make zImage
+
+The resulting kernel will end up in linux/arch/arm/boot/zImage.  This file
+must be loaded at 0xc0008000 in Brutus's memory and execution started at
+0xc0008000 as well.
+
+But prior to execute the kernel, a ramdisk image must also be loaded in
+memory.  Use memory address 0x00800000 for this.
+
+Currently supported:
+	- RS232 serial ports
+	- audio output
+	- LCD screen
+	- keyboard (needs to be cleaned up badly... any volunteer?)
+	
+A full PCMCIA support is still missing, although it's possible to hack
+some drivers in order to drive already inserted cards at boot time with
+little modifications.
+
+Any contribution is welcome.
+
+Please send patches to nico@cam.org
+
+Have Fun !
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Itsy linux/Documentation/arm/SA1100/Itsy
--- v2.3.22/linux/Documentation/arm/SA1100/Itsy	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/Itsy	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,12 @@
+Itsy is a research project done by the Western Research Lab, and Systems
+Research Center in Palo Alto, CA. The Itsy project is one of several
+research projects at Compaq that are related to pocket computing.
+
+Itsy support has yet to be fully integrated in this kernel.  Linux 2.0.x
+support is available though.
+
+For more information, see:
+
+	http://www.research.digital.com/wrl/itsy/index.html
+
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/LART linux/Documentation/arm/SA1100/LART
--- v2.3.22/linux/Documentation/arm/SA1100/LART	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/LART	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,17 @@
+Linux Advanced Radio Terminal (LART)
+------------------------------------
+
+The LART is a small (7.5 x 10cm) SA-1100 board, designed for embedded
+applications. It has 32 MB DRAM, 4MB Flash ROM, double RS232 and all
+other StrongARM-gadgets. Almost all SA signals are directly accessible
+through a number of connectors. The powersupply accepts voltages
+between 3.5V and 16V and is overdimensioned to support a range of
+daughterboards. A quad Ethernet / IDE / PS2 / sound daughterboard
+is under development, with plenty of others in different stages of
+planning.
+
+The designs for this board are to be released under a GPL-like license;
+we're working on the details.
+
+Contact: J.D. Bakker <bakker@thorgal.et.tudelft.nl>;
+pictures at http://www-ict.its.tudelft.nl/~erik/open-source/LART/
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/PLEB linux/Documentation/arm/SA1100/PLEB
--- v2.3.22/linux/Documentation/arm/SA1100/PLEB	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/PLEB	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,11 @@
+The PLEB project was started as a student initiative at the School of
+Computer Science and Engineering, University of New South Wales to make a
+pocket computer capable of running the Linux Kernel.
+
+PLEB support has yet to be fully integrated.
+
+For more information, see:
+
+	http://www.cse.unsw.edu.au/~pleb/
+
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Tifon linux/Documentation/arm/SA1100/Tifon
--- v2.3.22/linux/Documentation/arm/SA1100/Tifon	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/Tifon	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,7 @@
+Tifon
+-----
+
+More info has to come...
+
+Contact: Peter Danielsson <peter.danielsson@era-t.ericsson.se>
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/Victor linux/Documentation/arm/SA1100/Victor
--- v2.3.22/linux/Documentation/arm/SA1100/Victor	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/Victor	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,16 @@
+Victor is known as a "digital talking book player" manufactured by
+VisuAide, Inc. to be used by blind people.
+
+For more information related to Victor, see:
+
+	http://www.visuaide.com/victor
+
+Of course Victor is using Linux as its main operating system.
+The Victor implementation for Linux is maintained by Nicolas Pitre:
+
+	nico@visuaide.com
+	nico@cam.org
+
+For any comments, please feel free to contact me through the above
+addresses.
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/SA1100/empeg linux/Documentation/arm/SA1100/empeg
--- v2.3.22/linux/Documentation/arm/SA1100/empeg	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/SA1100/empeg	Wed Oct 20 16:29:07 1999
@@ -0,0 +1,2 @@
+See ../empeg/README
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/Setup linux/Documentation/arm/Setup
--- v2.3.22/linux/Documentation/arm/Setup	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/Setup	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,121 @@
+Kernel initialisation parameters on ARM Linux
+---------------------------------------------
+
+The following document describes the kernel initialisation parameter
+structure, otherwise known as 'struct param_struct' which is used
+for most ARM Linux architectures.
+
+This structure is used to pass initialisation parameters from the
+kernel loader to the Linux kernel proper, and may be short lived
+through the kernel initialisation process.  As a general rule, it
+should not be referenced outside of arch/arm/kernel/setup.c:setup_arch().
+
+There are a lot of parameters listed in there, and they are described
+below:
+
+ page_size
+
+   This parameter must be set to the page size of the machine, and
+   will be checked by the kernel.
+
+ nr_pages
+
+   This is the total number of pages of memory in the system.  If
+   the memory is banked, then this should contain the total number
+   of pages in the system.
+
+   If the system contains separate VRAM, this value should not
+   include this information.
+
+ ramdisk_size
+
+   This is now obsolete, and should not be used.
+
+ flags
+
+   Various kernel flags, including:
+    bit 0 - 1 = mount root read only
+    bit 1 - unused
+    bit 2 - 0 = load ramdisk
+    bit 3 - 0 = prompt for ramdisk
+
+ rootdev
+
+   major/minor number pair of device to mount as the root filesystem.
+
+ video_num_cols
+ video_num_rows
+
+   These two together describe the character size of the dummy console,
+   or VGA console character size.  They should not be used for any other
+   purpose.
+
+   It's generally a good idea to set these to be either standard VGA, or
+   the equivalent character size of your fbcon display.  This then allows
+   all the bootup messages to be displayed correctly.
+
+ video_x
+ video_y
+
+   This describes the character position of cursor on VGA console, and
+   is otherwise unused. (should not used for other console types, and
+   should not be used for other purposes).
+
+ memc_control_reg
+
+   MEMC chip control register for Acorn Archimedes and Acorn A5000
+   based machines.  May be used differently by different architectures.
+
+ sounddefault
+
+   Default sound setting on Acorn machines.  May be used differently by
+   different architectures.
+
+ adfsdrives
+
+   Number of ADFS/MFM disks.  May be used differently by different
+   architectures.
+
+ bytes_per_char_h
+ bytes_per_char_v
+
+   These are now obsolete, and should not be used.
+
+ pages_in_bank[4]
+
+   Number of pages in each bank of the systems memory (used for RiscPC).
+   This is intended to be used on systems where the physical memory
+   is non-contiguous from the processors point of view.
+
+ pages_in_vram
+
+   Number of pages in VRAM (used on Acorn RiscPC).  This value may also
+   be used by loaders if the size of the video RAM can't be obtained
+   from the hardware.
+
+ initrd_start
+ initrd_size
+
+   This describes the kernel virtual start address and size of the
+   inital ramdisk.
+
+ rd_start
+
+   Start address in sectors of the ramdisk image on a floppy disk.
+
+ system_rev
+
+   system revision number.
+
+ system_serial_low
+ system_serial_high
+
+   system 64-bit serial number
+
+ paths[8][128]
+
+   These are now obsolete, and should not be used.
+
+ commandline
+
+   Kernel command line parameters.  Details can be found elsewhere.
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/empeg/README linux/Documentation/arm/empeg/README
--- v2.3.22/linux/Documentation/arm/empeg/README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/empeg/README	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,13 @@
+Empeg, Ltd's Empeg MP3 Car Audio Player
+
+The initial design is to go in your car, but you can use it at home, on a
+boat... almost anywhere. The principle is to store CD-quality music using
+MPEG technology onto a hard disk in the unit, and use the power of the
+embedded computer to serve up the music you want.
+
+For more details, see:
+
+	http://www.empeg.com
+
+
+
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/empeg/ir.txt linux/Documentation/arm/empeg/ir.txt
--- v2.3.22/linux/Documentation/arm/empeg/ir.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/empeg/ir.txt	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,49 @@
+Infra-red driver documentation.
+
+Mike Crowe <mac@empeg.com>
+(C) Empeg Ltd 1999
+
+Not a lot here yet :-)
+
+The Kenwood KCA-R6A remote control generates a sequence like the following:
+
+Go low for approx 16T (Around 9000us)
+Go high for approx 8T (Around 4000us)
+Go low for less than 2T (Around 750us)
+
+For each of the 32 bits
+  Go high for more than 2T (Around 1500us) == 1
+  Go high for less than T (Around 400us) == 0
+  Go low for less than 2T (Around 750us)
+
+Rather than repeat a signal when the button is held down certain buttons
+generate the following code to indicate repitition.
+
+Go low for approx 16T
+Go high for approx 4T
+Go low for less than 2T
+
+(By removing the <2T from the start of the sequence and placing at the end
+ it can be considered a stop bit but I found it easier to deal with it at
+ the start).
+
+The 32 bits are encoded as XxYy where x and y are the actual data values
+while X and Y are the logical inverses of the associated data values. Using 
+LSB first yields sensible codes for the numbers.
+
+All codes are of the form b9xx
+
+The numeric keys generate the code 0x where x is the number pressed.
+
+Tuner		1c
+Tape		1d
+CD		1e
+CD-MD-CH	1f
+Track-		0a
+Track+		0b
+Rewind		0c
+FF		0d
+DNPP		5e
+Play/Pause	0e
+Vol+		14
+Vol-		15
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/empeg/mkdevs linux/Documentation/arm/empeg/mkdevs
--- v2.3.22/linux/Documentation/arm/empeg/mkdevs	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/empeg/mkdevs	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,11 @@
+#!/bin/sh
+mknod /dev/display c 244 0
+mknod /dev/ir c 242 0
+mknod /dev/usb0 c 243 0
+mknod /dev/audio c 245 4
+mknod /dev/dsp c 245 3
+mknod /dev/mixer c 245 0
+mknod /dev/empeg_state c 246 0
+mknod /dev/radio0 c 81 64
+ln -sf radio0 radio
+ln -sf usb0 usb
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/nwfpe/README linux/Documentation/arm/nwfpe/README
--- v2.3.22/linux/Documentation/arm/nwfpe/README	Sun May  2 09:51:16 1999
+++ linux/Documentation/arm/nwfpe/README	Wed Oct 20 16:29:08 1999
@@ -35,7 +35,7 @@
 remains to be done, and other ideas for the emulator.
 
 Bug reports, comments, suggestions should be directed to me at
-<scottb@corelcomputer.com>.  General reports of "this program doesn't
+<scottb@netwinder.com>.  General reports of "this program doesn't
 work correctly when your emulator is installed" are useful for
 determining that bugs still exist; but are virtually useless when
 attempting to isolate the problem.  Please report them, but don't
@@ -46,7 +46,7 @@
 Legal Notices
 -------------
 
-The NetWinder Floating Point Emulator is free software.  Everything Corel
+The NetWinder Floating Point Emulator is free software.  Everything Rebel.com
 has written is provided under the GNU GPL.  See the file COPYING for copying
 conditions.  Excluded from the above is the SoftFloat code.  John Hauser's 
 legal notice for SoftFloat is included below.
diff -u --recursive --new-file v2.3.22/linux/Documentation/arm/nwfpe/README.FPE linux/Documentation/arm/nwfpe/README.FPE
--- v2.3.22/linux/Documentation/arm/nwfpe/README.FPE	Sun May  2 09:51:16 1999
+++ linux/Documentation/arm/nwfpe/README.FPE	Wed Oct 20 16:29:08 1999
@@ -139,10 +139,10 @@
 
 Signalling:
 
-Signals are implemented.  However current ELF kernels produced by Corel
-Computer have a bug in them that prevents the module from generating a 
-SIGFPE.  This is caused by a failure to alias fp_current to the kernel
-variable current_set[0] correctly.
+Signals are implemented.  However current ELF kernels produced by Rebel.com
+have a bug in them that prevents the module from generating a SIGFPE.  This
+is caused by a failure to alias fp_current to the kernel variable
+current_set[0] correctly.
 
 The kernel provided with this distribution (vmlinux-nwfpe-0.93) contains
 a fix for this problem and also incorporates the current version of the
diff -u --recursive --new-file v2.3.22/linux/Documentation/pci.txt linux/Documentation/pci.txt
--- v2.3.22/linux/Documentation/pci.txt	Thu Jun 17 12:56:11 1999
+++ linux/Documentation/pci.txt	Fri Oct 15 18:55:26 1999
@@ -4,10 +4,19 @@
 
 		"What should you avoid when writing PCI drivers"
 
-	  by Martin Mares <mj@atrey.karlin.mff.cuni.cz> on 17-Jun-1999
+	  by Martin Mares <mj@atrey.karlin.mff.cuni.cz> on 09-Oct-1999
 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+0. Structure of PCI drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   Aa typical PCI device driver needs to perform the following actions:
+
+	1. Find PCI devices it's able to handle
+	2. Enable them
+	3. Access their configuration space
+	4. Discover addresses and IRQ numbers
+
 1. How to find PCI devices
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
    In case your driver wants to search for all devices with given vendor/device
@@ -19,6 +28,9 @@
 
    For class-based search, use pci_find_class(CLASS_ID, dev).
 
+   If you need to match by subsystem vendor/device ID, use
+pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev).
+
    You can use the constant PCI_ANY_ID as a wildcard replacement for
 VENDOR_ID or DEVICE_ID.  This allows searching for any device from a
 specific vendor, for example.
@@ -26,44 +38,57 @@
    In case you want to do some complex matching, look at pci_devices -- it's
 a linked list of pci_dev structures for all PCI devices in the system.
 
-   All these methods return a pointer to a pci_dev structure which is used as a
-parameter for many other PCI functions. The rest of them accept bus and
-device/function numbers which can be found in pci_dev->bus->number and
-pci_dev->devfn. Feel free to use all other fields of the pci_dev structure, but
-don't modify them.
+   The `struct pci_dev *' pointer serves as an identification of a PCI device
+and is passed to all other functions operating on PCI devices.
 
-   The pci_present() function can be used to test presence of PCI in the
-machine.
+2. Enabling devices
+~~~~~~~~~~~~~~~~~~~
+   Before you do anything with the device you've found, you need to enable
+it by calling pci_enable_device() which enables I/O and memory regions of
+the device, assigns missing resources if needed and wakes up the device
+if it was in suspended state. Please note that this function can fail.
+
+   If you want to use the device in bus mastering mode, call pci_set_master()
+which enables the bus master bit in PCI_COMMAND register and also fixes
+the latency timer value if it's set to something bogus by the BIOS.
 
-2. How to access PCI config space
+3. How to access PCI config space
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    You can use pci_(read|write)_config_(byte|word|dword) to access the config
-space of a device represented by pci_dev. All these functions return 0 when
-successful or an error code (PCIBIOS_...) which can be translated to a text
+space of a device represented by struct pci_dev *. All these functions return 0
+when successful or an error code (PCIBIOS_...) which can be translated to a text
 string by pcibios_strerror. Most drivers expect that accesses to valid PCI
 devices don't fail.
 
-   In case you want to address the devices by bus/device/function numbers,
-use pcibios_(read_write)_config_(byte|word|dword).
-
    If you access fields in the standard portion of the config header, please
 use symbolic names of locations and bits declared in <linux/pci.h>.
 
-3. Addresses and interrupts
+   If you need to access Extended PCI Capability registers, just call
+pci_find_capability() for the particular capability and it will find the
+corresponding register block for you.
+
+4. Addresses and interrupts
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Memory and port addresses and interrupt numbers should NOT be read from the
 config space. You should use the values in the pci_dev structure as they might
 have been remapped by the kernel.
 
-4. Obsolete functions
-~~~~~~~~~~~~~~~~~~~~~
-<linux/bios32.h> is obsolete and should not be included in new code.
+5. Other interesting functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+pci_find_slot()			Find pci_dev corresponding to given bus and
+				slot numbers.
+pci_set_power_state()		Set PCI Power Management state (0=D0 ... 3=D3)
 
-pcibios_find_(device|class) are also obsolete and should be replaced by
-pci_find_(device|class).
+6. Obsolete functions
+~~~~~~~~~~~~~~~~~~~~~
+There are several functions kept only for compatibility with old drivers
+not updated to the new PCI interface. Please don't use them in new code.
 
-5. Bus mastering
-~~~~~~~~~~~~~~~~
-   If you need to setup a bus-mastering card, just call pci_set_master(). It
-should set PCI_COMMAND_MASTER in the command register and adjust the latency
-timer if needed.
+pcibios_present()		Since ages, you don't need to test presence
+				of PCI subsystem when trying to talk with it.
+				If it's not there, the list of PCI devices
+				is empty and all functions for searching for
+				devices just return NULL.
+pcibios_(read|write)_*		Superseded by their pci_(read|write)_*
+				counterparts.
+pcibios_find_*			Superseded by their pci_find_* counterparts.
diff -u --recursive --new-file v2.3.22/linux/Documentation/vm/locking linux/Documentation/vm/locking
--- v2.3.22/linux/Documentation/vm/locking	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/vm/locking	Mon Oct 18 13:01:40 1999
@@ -0,0 +1,88 @@
+Started Oct 1999 by Kanoj Sarcar <kanoj@sgi.com>
+
+The intent of this file is to have an uptodate, running commentary 
+from different people about how locking and synchronization is done 
+in the Linux vm code.
+
+vmlist_access_lock/vmlist_modify_lock
+--------------------------------------
+
+Page stealers pick processes out of the process pool and scan for 
+the best process to steal pages from. To guarantee the existance 
+of the victim mm, a mm_count inc and a mmdrop are done in swap_out().
+Page stealers hold kernel_lock to protect against a bunch of races.
+The vma list of the victim mm is also scanned by the stealer, 
+and the vmlist_lock is used to preserve list sanity against the
+process adding/deleting to the list. This also gurantees existance
+of the vma. Vma existance gurantee while invoking the driver
+swapout() method in try_to_swap_out() also relies on the fact
+that do_munmap() temporarily gets lock_kernel before decimating
+the vma, thus the swapout() method must snapshot all the vma 
+fields it needs before going to sleep (which will release the
+lock_kernel held by the page stealer). Currently, filemap_swapout
+is the only method that depends on this shaky interlocking.
+
+Any code that modifies the vmlist, or the vm_start/vm_end/
+vm_flags:VM_LOCKED/vm_next of any vma *in the list* must prevent 
+kswapd from looking at the chain. This does not include driver mmap() 
+methods, for example, since the vma is still not in the list.
+
+The rules are:
+1. To modify the vmlist (add/delete or change fields in an element), 
+you must hold mmap_sem to guard against clones doing mmap/munmap/faults, 
+(ie all vm system calls and faults), and from ptrace, swapin due to 
+swap deletion etc.
+2. To modify the vmlist (add/delete or change fields in an element), 
+you must also hold vmlist_modify_lock, to guard against page stealers 
+scanning the list.
+3. To scan the vmlist (find_vma()), you must either 
+        a. grab mmap_sem, which should be done by all cases except 
+	   page stealer.
+or
+        b. grab vmlist_access_lock, only done by page stealer.
+4. While holding the vmlist_modify_lock, you must be able to guarantee
+that no code path will lead to page stealing. A better guarantee is
+to claim non sleepability, which ensures that you are not sleeping
+for a lock, whose holder might in turn be doing page stealing.
+5. You must be able to guarantee that while holding vmlist_modify_lock
+or vmlist_access_lock of mm A, you will not try to get either lock
+for mm B.
+
+The caveats are:
+1. find_vma() makes use of, and updates, the mmap_cache pointer hint.
+The update of mmap_cache is racy (page stealer can race with other code
+that invokes find_vma with mmap_sem held), but that is okay, since it 
+is a hint. This can be fixed, if desired, by having find_vma grab the
+vmlist lock.
+
+
+Code that add/delete elements from the vmlist chain are
+1. callers of insert_vm_struct
+2. callers of merge_segments
+3. callers of avl_remove
+
+Code that changes vm_start/vm_end/vm_flags:VM_LOCKED of vma's on
+the list:
+1. expand_stack
+2. mprotect
+3. mlock
+4. mremap
+
+It is advisable that changes to vm_start/vm_end be protected, although 
+in some cases it is not really needed. Eg, vm_start is modified by 
+expand_stack(), it is hard to come up with a destructive scenario without 
+having the vmlist protection in this case.
+
+The vmlist lock nests with the inode i_shared_lock and the kmem cache
+c_spinlock spinlocks. This is okay, since code that holds i_shared_lock 
+never asks for memory, and the kmem code asks for pages after dropping
+c_spinlock.
+
+The vmlist lock can be a sleeping or spin lock. In either case, care
+must be taken that it is not held on entry to the driver methods, since
+those methods might sleep or ask for memory, causing deadlocks.
+
+The current implementation of the vmlist lock uses the page_table_lock,
+which is also the spinlock that page stealers use to protect changes to
+the victim process' ptes. Thus we have a reduction in the total number
+of locks. 
diff -u --recursive --new-file v2.3.22/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.22/linux/MAINTAINERS	Fri Oct 15 15:25:13 1999
+++ linux/MAINTAINERS	Thu Oct 21 12:15:36 1999
@@ -396,6 +396,12 @@
 W:	http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 S:	Maintained
 
+i386 BOOT CODE
+P:	Riley H. Williams
+M:	rhw@memalpha.cx
+L:	Linux-Kernel@vger.rutgers.edu
+S:	Maintained
+
 IBM MCA SCSI SUBSYSTEM DRIVER
 P:	Michael Lang
 M:	langa2@kph.uni-mainz.de
@@ -502,8 +508,9 @@
 
 LINUX FOR POWER MACINTOSH
 P:	Paul Mackerras
-M:	paulus@cs.anu.edu.au
-L:	linux-pmac@samba.anu.edu.au
+M:	paulus@linuxcare.com
+W:	http://www.linuxppc.org/
+L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
 
 M68K
@@ -687,6 +694,7 @@
 P:	David Hinds
 M:	dhinds@zen.stanford.edu
 L:	linux-kernel@vger.rutgers.edu
+W:	http://pcmcia.sourceforge.org
 S:	Maintained
 
 PCNET32 NETWORK DRIVER
@@ -830,6 +838,16 @@
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
 W:	http://mosquitonet.Stanford.EDU/strip.html
 S:	Unsupported ?
+
+SUPERH
+P:	Niibe Yutaka
+M:	gniibe@chroot.org
+P:	Kazumoto Kojima
+M:	kkojima@rr.iij4u.or.jp
+L:	linux-sh@m17n.org
+W:	http://www.m17n.org/linux-sh/
+W:	http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html
+S:	Maintained
 
 SVGA HANDLING
 P:	Martin Mares
diff -u --recursive --new-file v2.3.22/linux/Makefile linux/Makefile
--- v2.3.22/linux/Makefile	Fri Oct 15 15:25:13 1999
+++ linux/Makefile	Fri Oct 15 15:25:27 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 22
+SUBLEVEL = 23
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.22/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.3.22/linux/arch/alpha/mm/init.c	Thu Jul 29 13:37:22 1999
+++ linux/arch/alpha/mm/init.c	Sat Oct 16 10:50:48 1999
@@ -166,6 +166,7 @@
 	printk("%ld pages shared\n",shared);
 	printk("%ld pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
diff -u --recursive --new-file v2.3.22/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.3.22/linux/arch/arm/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/Makefile	Wed Oct 20 16:29:08 1999
@@ -12,91 +12,101 @@
 #
 # Copyright (C) 1995-1999 by Russell King
 
-# GCC 2.7 uses different options to later compilers; sort out which we have
-CONFIG_GCC_NEW		:= $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi)
+LD		:= $(CROSS_COMPILE)ld
+OBJCOPY		:= $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+CPP		:= $(CC) -E
+PERL		:= perl
+LINKFLAGS	:= -X -T arch/arm/vmlinux.lds
+ARCHCC		:= $(word 1,$(CC))
+
+
+CFLAGS_PIPE	:= -pipe
+CFLAGS		:= $(CFLAGS) $(CFLAGS_PIPE)
+
+ifdef CONFIG_FRAME_POINTER
+CFLAGS		:= $(CFLAGS:-fomit-frame-pointer=)
+endif
+
+ifdef CONFIG_DEBUG_INFO
+CFLAGS		+= -g
+endif
 
-# See if this is ld "2.9.4" or later
-NEW_LINKER		:= $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi)
 
-# CFLAGS_PROC - processor dependent CFLAGS
-# PROCESSOR   - processor type
-# TEXTADDR    - Uncompressed kernel link text address
-# ZTEXTADDR   - Compressed kernel link text address
-# ZRELADDR    - Compressed kernel relocating address
-#	        (point at which uncompressed kernel is loaded).
+# GCC 2.7 uses different options to later compilers; sort out which we have
+NEW_GCC		:= $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi)
 
 #
 # select flags depending on the compiler
 #
-ifeq ($(CONFIG_GCC_NEW),y)
-  CFLAGS_PROC		:= -mshort-load-bytes -msoft-float
-  CFLAGS_PROC_CPU_26	:= -mcpu=arm3 -Os
-  CFLAGS_PROC_CPU_32v3	:= -march=armv3
-  CFLAGS_PROC_CPU_32v4	:= -march=armv4
-  CFLAGS_ARM6		:= -mtune=arm6
-  CFLAGS_ARM7		:= -mtune=arm7
-  CFLAGS_SA110		:= -mtune=strongarm110
+ifeq ($(NEW_GCC),y)
+CFLAGS			+= -mshort-load-bytes -msoft-float
+CFLAGS_PROC_CPU_26	:= -mcpu=arm3 -Os
+CFLAGS_PROC_CPU_32v3	:= -march=armv3
+CFLAGS_PROC_CPU_32v4	:= -march=armv4
+CFLAGS_ARM6		:= -mtune=arm6
+CFLAGS_ARM7		:= -mtune=arm7
+CFLAGS_SA110		:= -mtune=strongarm110
 else
-  CFLAGS_PROC		:=
-  CFLAGS_PROC_CPU_26	:= -m3
-  CFLAGS_PROC_CPU_32v3	:=
-  CFLAGS_PROC_CPU_32v4	:=
-  CFLAGS_ARM6		:= -m6
-  CFLAGS_ARM7		:= -m6
-  CFLAGS_SA110		:= -m6
+CFLAGS_PROC_CPU_26	:= -m3
+CFLAGS_PROC_CPU_32v3	:=
+CFLAGS_PROC_CPU_32v4	:=
+CFLAGS_ARM6		:= -m6
+CFLAGS_ARM7		:= -m6
+CFLAGS_SA110		:= -m6
 endif
 
+# See if this is ld "2.9.4" or later
+NEW_LINKER		:= $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi)
+
 ifeq ($(NEW_LINKER),y)
-  ASFLAGS_PROC		:= -mno-fpu
-  ASFLAGS_PROC_CPU_26	:= -mapcs-26
-  ASFLAGS_PROC_CPU_32v3	:= -mapcs-32 -marmv3m
-  ASFLAGS_PROC_CPU_32v4	:= -mapcs-32 -marmv4t
-  LINKFLAGS		:= -p
+AFLAGS			+= -mno-fpu
+AFLAGS_PROC_CPU_26	:= -mapcs-26
+AFLAGS_PROC_CPU_32v3	:= -mapcs-32 -marmv3m
+AFLAGS_PROC_CPU_32v4	:= -mapcs-32 -marmv4t
+LINKFLAGS		:= -p $(LINKFLAGS)
 else
-  ASFLAGS_PROC		:=
-  ASFLAGS_PROC_CPU_26	:= -m3
-  ASFLAGS_PROC_CPU_32v3	:= -m6
-  ASFLAGS_PROC_CPU_32v4	:= -m6
-  LINKFLAGS		:=
+AFLAGS_PROC_CPU_26	:= -m3
+AFLAGS_PROC_CPU_32v3	:= -m6
+AFLAGS_PROC_CPU_32v4	:= -m6
 endif
 
+#
+# Select CPU dependent flags
+#
 ifeq ($(CONFIG_CPU_26),y)
-  PROCESSOR		 = armo
-  TEXTADDR		 = 0x02080000
-  ZTEXTADDR		 = 0x01800000
-  ZRELADDR		 = 0x02080000
-  CFLAGS_PROC		+= $(CFLAGS_PROC_CPU_26)
-  ASFLAGS_PROC		+= $(ASFLAGS_PROC_CPU_26)
+ PROCESSOR	 = armo
+ TEXTADDR	 = 0x02080000
+ CFLAGS		+= $(CFLAGS_PROC_CPU_26)
+ AFLAGS		+= $(AFLAGS_PROC_CPU_26)
 endif
 
 ifeq ($(CONFIG_CPU_32),y)
-  PROCESSOR		 = armv
-  TEXTADDR		 = 0xC0008000
-  ifeq ($(CONFIG_CPU_32v4),y)
-    CFLAGS_PROC		+= $(CFLAGS_PROC_CPU_32v4)
-    ASFLAGS_PROC	+= $(ASFLAGS_PROC_CPU_32v4)
-  else
-    CFLAGS_PROC		+= $(CFLAGS_PROC_CPU_32v3)
-    ASFLAGS_PROC	+= $(ASFLAGS_PROC_CPU_32v3)
-  endif
-  #
-  # Exactly one of the following must be selected
-  #
-  ifeq ($(CONFIG_CPU_ARM6),y)
-    CFLAGS_PROC		+= $(CFLAGS_ARM6)
-  else
-  ifeq ($(CONFIG_CPU_ARM7),y)
-    CFLAGS_PROC		+= $(CFLAGS_ARM7)
-  else
-  ifeq ($(CONFIG_CPU_SA110),y)
-    CFLAGS_PROC		+= $(CFLAGS_SA110)
-  endif
-  endif
-  endif
+ PROCESSOR	 = armv
+ TEXTADDR	 = 0xC0008000
+ ifeq ($(CONFIG_CPU_32v4),y)
+  CFLAGS	+= $(CFLAGS_PROC_CPU_32v4)
+  AFLAGS	+= $(AFLAGS_PROC_CPU_32v4)
+ else
+  CFLAGS	+= $(CFLAGS_PROC_CPU_32v3)
+  AFLAGS	+= $(AFLAGS_PROC_CPU_32v3)
+ endif
+ #
+ # Exactly one of the following must be selected
+ #
+ ifeq ($(CONFIG_CPU_ARM6),y)
+  CFLAGS	+= $(CFLAGS_ARM6)
+ else
+ ifeq ($(CONFIG_CPU_ARM7),y)
+  CFLAGS	+= $(CFLAGS_ARM7)
+ else
+ ifeq ($(CONFIG_CPU_SA110),y)
+  CFLAGS	+= $(CFLAGS_SA110)
+ endif
+ endif
+ endif
 endif
 
-
-COMPRESSED_HEAD	 = head.o
+GCCLIB		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
 
 ifeq ($(CONFIG_ARCH_A5K),y)
 MACHINE		 = a5k
@@ -111,22 +121,16 @@
 ifeq ($(CONFIG_ARCH_RPC),y)
 MACHINE		 = rpc
 ARCHDIR		 = rpc
-ZTEXTADDR	 = 0x10008000
-ZRELADDR	 = 0x10008000
 endif
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 MACHINE		 = ebsa110
 ARCHDIR		 = ebsa110
-ZTEXTADDR	 = 0x00008000
-ZRELADDR	 = 0x00008000
 endif
 
 ifeq ($(CONFIG_FOOTBRIDGE),y)
 MACHINE		 = footbridge
 ARCHDIR		 = ebsa285
-ZTEXTADDR	 = 0x00008000
-ZRELADDR	 = 0x00008000
 endif
 
 ifeq ($(CONFIG_ARCH_CO285),y)
@@ -136,56 +140,31 @@
 ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
 MACHINE		 = nexuspci
 ARCHDIR		 = nexuspci
-ZTEXTADDR	 = 0x40200000
-ZRELADDR	 = 0x40008000
-COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o
-COMPRESSED_HEAD	 = head-nexuspci.o
 endif
 
-
-
-PERL		 = perl
-LD		 = $(CROSS_COMPILE)ld
-OBJCOPY		 = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-OBJDUMP		 = $(CROSS_COMPILE)objdump
-CPP		 = $(CC) -E
-ARCHCC		:= $(word 1,$(CC))
-GCCLIB		:= `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name`
-HOSTCFLAGS	:= $(CFLAGS:-fomit-frame-pointer=)
-ifeq ($(CONFIG_FRAME_POINTER),y)
-CFLAGS		:= $(CFLAGS:-fomit-frame-pointer=)
-endif
-CFLAGS		:= $(CFLAGS_PROC) $(CFLAGS) -pipe
-ASFLAGS		:= $(ASFLAGS_PROC) $(ASFLAGS)
-LINKFLAGS	+= -X -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext
-ZLINKFLAGS	 = -Ttext $(ZTEXTADDR)
-
-# If we're intending to debug the kernel, make sure it has line number
-# information.  This gets stripped out when building (z)Image so it doesn't
-# add anything to the footprint of the running kernel.
-ifeq ($(CONFIG_DEBUG_INFO),y)
-CFLAGS		+= -g
+ifeq ($(CONFIG_ARCH_SA1100),u)
+MACHINE		 = sa1100
+ARCHDIR		 = sa1100
 endif
 
 HEAD		:= arch/arm/kernel/head-$(PROCESSOR).o \
 		   arch/arm/kernel/init_task.o
-SUBDIRS		:= arch/arm/special $(SUBDIRS) arch/arm/lib arch/arm/kernel \
-		   arch/arm/mm arch/arm/nwfpe
+SUBDIRS		+= arch/arm/kernel arch/arm/mm arch/arm/lib \
+		   arch/arm/special arch/arm/nwfpe
 CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
 LIBS		:= arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
 DRIVERS		+= arch/arm/special/special.a
 
-ifeq ($(CONFIG_ARCH_ACORN),y)
-SUBDIRS		+= drivers/acorn/block drivers/acorn/char drivers/acorn/net \
-		   drivers/acorn/scsi
-DRIVERS		+= drivers/acorn/block/acorn-block.a \
-		   drivers/acorn/char/acorn-char.a \
-		   drivers/acorn/net/acorn-net.a \
-		   drivers/acorn/scsi/acorn-scsi.a
+ifeq ($(CONFIG_NWFPE),y)
+CORE_FILES	+= arch/arm/nwfpe/math-emu.o
 endif
 
-ifeq ($(CONFIG_NWFPE),y)
-DRIVERS		+= arch/arm/nwfpe/math-emu.a
+ifeq ($(CONFIG_ARCH_ACORN),y)
+SUBDIRS		+= drivers/acorn
+DRIVERS		+= drivers/acorn/block/acorn-block.a
+DRIVERS		+= drivers/acorn/char/acorn-char.a
+DRIVERS		+= drivers/acorn/net/acorn-net.a
+DRIVERS		+= drivers/acorn/scsi/acorn-scsi.a
 endif
 
 MAKEBOOT	 = $(MAKE) -C arch/$(ARCH)/boot
@@ -203,14 +182,9 @@
 	$(RM) include/asm-arm/arch include/asm-arm/proc
 	(cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc)
 
-# We need to rebuild the linker script
-# each time, in case the architecture has
-# changed.
-.PHONY: arch/arm/vmlinux-$(PROCESSOR).lds
-
-vmlinux: arch/arm/vmlinux-$(PROCESSOR).lds
+vmlinux: arch/arm/vmlinux.lds
 
-arch/arm/vmlinux-$(PROCESSOR).lds: $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds.in
+arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy
 	@sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@
 
 arch/arm/kernel: dummy
@@ -225,15 +199,13 @@
 zImage zinstall Image install: vmlinux
 	@$(MAKEBOOT) $@
 
-# Once we've finished integrating the sources, the @$(MAKE) will disappear
 archmrproper:
-	rm -f include/asm-arm/arch include/asm-arm/proc
 	@$(MAKE) -C arch/$(ARCH)/special mrproper
-	rm -f $(TOPDIR)/arch/arm/vmlinux-*.lds
+	$(RM) include/asm-arm/arch include/asm-arm/proc
 
 archclean:
 	@$(MAKEBOOT) clean
-	$(RM) arch/arm/lib/constants.h
+	$(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds
 
 archdep:
 	@$(MAKEBOOT) dep
@@ -244,6 +216,10 @@
 i:;	@$(MAKEBOOT) install
 zi:;	@$(MAKEBOOT) zinstall
 
+#
+# Configuration targets.  Use these to select a
+# configuration for your architecture
+#
 a5k_config:
 	$(RM) arch/arm/defconfig
 	cp arch/arm/def-configs/a5k arch/arm/defconfig
@@ -259,4 +235,17 @@
 rpc_config:
 	$(RM) arch/arm/defconfig
 	cp arch/arm/def-configs/rpc arch/arm/defconfig
+
+brutus_config:
+	$(RM) arch/arm/defconfig
+	cp arch/arm/def-configs/brutus arch/arm/defconfig
+
+victor_config:
+	$(RM) arch/arm/defconfig
+	cp arch/arm/def-configs/victor arch/arm/defconfig
+
+empeg_config:
+	$(RM) arch/arm/defconfig
+	cp arch/arm/def-configs/empeg arch/arm/defconfig
+
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
--- v2.3.22/linux/arch/arm/boot/compressed/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/boot/compressed/Makefile	Wed Oct 20 16:29:08 1999
@@ -2,47 +2,97 @@
 # linux/arch/arm/boot/compressed/Makefile
 #
 # create a compressed vmlinuz image from the original vmlinux
-#
-# With this config, max compressed image size = 640k
-# Uncompressed image size = 1.3M (text+data)
 
-SYSTEM	=$(TOPDIR)/vmlinux
-HEAD	=$(COMPRESSED_HEAD)
-OBJS	=$(HEAD) misc.o $(COMPRESSED_EXTRA)
-CFLAGS	=-O2 -DSTDC_HEADERS $(CFLAGS_PROC)
-ARFLAGS =rc
-FONTC	=$(TOPDIR)/drivers/video/font_acorn_8x8.c
+HEAD		 = head.o
+OBJS		 = misc.o
+SYSTEM		 = $(TOPDIR)/vmlinux
+CFLAGS		 = -O2 -DSTDC_HEADERS $(CFLAGS_PROC)
+FONTC		 = $(TOPDIR)/drivers/video/font_acorn_8x8.c
+ZLDFLAGS	 = -X -T vmlinux.lds
 
+#
+# Architecture dependencies
+#
 ifeq ($(CONFIG_ARCH_ACORN),y)
-OBJS	+= ll_char_wr.o font.o
+OBJS		+= ll_char_wr.o font.o
+endif
+
+ifeq ($(CONFIG_CPU_26),y)
+ZTEXTADDR	 = 0x02080000
+endif
+
+ifeq ($(CONFIG_ARCH_RPC),y)
+ZTEXTADDR	 = 0x10008000
+endif
+
+ifeq ($(CONFIG_ARCH_EBSA110),y)
+ZTEXTADDR	 = 0x00008000
+endif
+
+ifeq ($(CONFIG_FOOTBRIDGE),y)
+ZTEXTADDR	 = 0x00008000
+endif
+
+ifeq ($(CONFIG_ARCH_NETWINDER),y)
+OBJS		+= head-netwinder.o
 endif
 
-ifeq ($(NEW_LINKER),y)
-BINFMT	:= elf32-littlearm
+ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
+HEAD		 = head-nexuspci.o
+OBJS		+= $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o
+ZTEXTADDR	 = 0x40200000
+ZRELADDR	 = 0x40008000
+endif
+
+ifeq ($(CONFIG_ARCH_SA110),y)
+ifeq ($(CONFIG_SA1100_VICTOR),y)
+HEAD		 = head-victor.o
+ZTEXTADDR	 = 0x00002000
+ZBSSADDR	 = 0xc0100000
 else
-BINFMT	:= elf32-arm
+ZTEXTADDR	 = 0xc0008000
+endif
+ZRELADDR	 = 0xc0008000
+endif
+
+#
+# If you don't define ZRELADDR above,
+# then it defaults to ZTEXTADDR
+#
+ifeq ($(ZRELADDR),)
+ZRELADDR	= $(ZTEXTADDR)
 endif
 
+SEDFLAGS	= s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;
+
+ifneq ($(ZBSSADDR),)
+SEDFLAGS	+= s/BSS_START/$(ZBSSADDR)/
+else
+SEDFLAGS	+= s/BSS_START/ALIGN(4)/
+endif
 
 all:		vmlinux
 
-vmlinux:	$(OBJS) piggy.o
-		$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o
+vmlinux:	$(HEAD) $(OBJS) piggy.o vmlinux.lds
+		$(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux
 
 $(HEAD): 	$(HEAD:.o=.S)
-		$(CC) -traditional -DLOADADDR=$(ZRELADDR) -c $(HEAD:.o=.S)
+		$(CC) -traditional -c $(HEAD:.o=.S)
 
 piggy.o:	$(SYSTEM)
-		tmppiggy=_tmp_$$$$piggy; \
-		rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
-		$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
-		gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
-		echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-		$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b $(BINFMT) -T $$tmppiggy.lnk; \
-		rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk;
+		$(OBJCOPY) $(SYSTEM) piggy
+		gzip -9 < piggy > piggy.gz
+		$(LD) -r -o $@ -b binary piggy.gz
+		rm -f piggy piggy.gz
 
 font.o:		$(FONTC)
 		$(CC) -Dstatic= -c -o $@ $(FONTC)
 
-clean:;		rm -f vmlinux core
+vmlinux.lds:	vmlinux.lds.in
+		@sed "$(SEDFLAGS)" < vmlinux.lds.in > $@
+
+clean:;		rm -f vmlinux core piggy*
+
+.PHONY:	vmlinux.lds clean
 
+misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c
diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/head-netwinder.S linux/arch/arm/boot/compressed/head-netwinder.S
--- v2.3.22/linux/arch/arm/boot/compressed/head-netwinder.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/boot/compressed/head-netwinder.S	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,30 @@
+		.section	".start", #alloc, #execinstr
+
+		adr	r2, 1f
+		ldmdb	r2, {r7, r8}
+		and	r3, r2, #0xc000
+		teq	r3, #0x8000
+		beq	2f
+		bic	r3, r2, #0xc000
+		orr	r3, r3, #0x8000
+		mov	r0, r3
+		mov	r4, #64
+		sub	r5, r8, r7
+		b	1f
+
+		.word	_start
+		.word	__bss_start
+
+1:
+		.rept	4
+		ldmia	r2!, {r6, r7, r8, r9}
+		stmia	r3!, {r6, r7, r8, r9}
+		.endr
+		subs	r4, r4, #64
+		bcs	1b
+		movs	r4, r5
+		mov	r5, #0
+		movne	pc, r0
+
+		mov	r0, #0
+2:
diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/head-victor.S linux/arch/arm/boot/compressed/head-victor.S
--- v2.3.22/linux/arch/arm/boot/compressed/head-victor.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/boot/compressed/head-victor.S	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/arm/boot/compressed/head-victor.S
+ *
+ * Copyright (C) 1998 Nicolas Pitre <nico@visuaide.com>
+ */
+
+#include <linux/linkage.h>
+
+		.text
+		.globl	_start
+_start:
+		@ just in case we still use an a.out loader...
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+
+		@ load different addresses
+		adr	r2, LC0
+		ldmia	r2, {r4, r5, r6, sp}
+
+		@ clear BSS
+		mov	r2, #0
+1:		str	r2, [r5], #4
+		cmp	r5, r6
+		blt	1b
+
+		@ uncompress the kernel
+		mov	r8, r0		@ save cmdline ptr
+		mov	r0, r4		@ where to put uncompressed data
+		add	r1, r6, #31
+		bic	r1, r1, #31	@ free memory space
+		add	r2, r1, #65536	@ end of free mem space
+		bl	SYMBOL_NAME(decompress_kernel)
+		mov	r0, r8		@ retrieve cmdline ptr
+		mov	pc, r4		@ call via EXEC entry
+
+LC0:		.word	_load_addr
+		.word	__bss_start
+		.word	SYMBOL_NAME(_end)
+		.word	SYMBOL_NAME(user_stack)+4096
diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S
--- v2.3.22/linux/arch/arm/boot/compressed/head.S	Sat Jul 18 11:55:22 1998
+++ linux/arch/arm/boot/compressed/head.S	Wed Oct 20 16:29:08 1999
@@ -1,129 +1,232 @@
 /*
  * linux/arch/arm/boot/compressed/head.S
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
 #include <linux/linkage.h>
 
-		.text
+		.section ".start", #alloc, #execinstr
 /*
  * sort out different calling conventions
  */
 		.align
-		.globl	_start
-_start:
-start:		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
+start:
+		.type	start,#function
+		.rept	8
 		mov	r0, r0
+		.endr
+
 		b	1f
-		.word	0x016f2818			@ Magic numbers to help the loader
-		.word	_start	
+		.word	0x016f2818		@ Magic numbers to help the loader
+		.word	start	
+1:
+
+		/*
+		 * some architecture specific code can
+		 * be inserted by the linker here
+		 */
+
+		.text
 1:		teq	r0, #0
-		beq	2f
-		mov	r4, #0x02000000
-		add	r4, r4, #0x7C000
-		mov	r3, #0x4000
-		sub	r3, r3, #4
-1:		ldmia	r0!, {r5 - r12}
-		stmia	r4!, {r5 - r12}
-		subs	r3, r3, #32
-		bpl	1b
-2:		adr	r2, LC0
-		ldmia	r2, {r2, r3, r4, r5, r6, sp}
-		add	r2, r2, #3
-		add	r3, r3, #3
-		add	sp, sp, #3
-		bic	r2, r2, #3
-		bic	r3, r3, #3
-		bic	sp, sp, #3
-		adr	r7, start
-		sub	r6, r7, r6
-/*
- * Relocate pointers
- */
-		add	r2, r2, r6
-		add	r3, r3, r6
-		add	r5, r5, r6
-		add	sp, sp, r6
-/*
- * Clear zero-init
- */
-		mov	r6, #0
-1:		str	r6, [r2], #4
+		bne	1b
+		mov	r7, r1			@ save architecture ID
+		mrc	p15, 0, r6, c0, c0	@ get processor ID
+		adr	r2, LC0
+		ldmia	r2, {r2, r3, r4, r5, sp}
+
+		mov	r0, #0
+1:		str	r0, [r2], #4		@ clear bss
+		str	r0, [r2], #4
+		str	r0, [r2], #4
+		str	r0, [r2], #4
 		cmp	r2, r3
 		blt	1b
-		str	r1, [r5]		@ save architecture
-/*
- * Uncompress the kernel
- */
-		mov	r1, #0x8000
-		add	r3, r2, r1, lsl #1	@ Add 64k for malloc
-		sub	r1, r1, #1
-		add	r3, r3, r1
-		bic	r5, r3, r1		@ decompress kernel to after end of the compressed
+
+		mov	r1, sp			@ malloc space above stack
+		add	r2, sp, #0x10000	@ 64k max
+
+		teq	r4, r5			@ will we overwrite ourselves?
+		moveq	r5, r2
+		movne	r5, r4
+
 		mov	r0, r5
-		mov	r1, r2
-		mov	r2, r0
+		mov	r3, r7
 		bl	SYMBOL_NAME(decompress_kernel)
-		add	r0, r0, #7
-		bic	r2, r0, #7
+
+		teq	r4, r5			@ do we need to relocate
+		beq	call_kernel		@ the kernel?
+
+		add	r0, r0, #127
+		bic	r0, r0, #127		@ align the kernel length
 /*
- * Now move the kernel to the correct location (r5 -> r4, len r0)
- */
-		mov	r0, r4			@ r0 = start of real kernel
-		mov	r1, r5			@ r1 = start of kernel image
-		add	r3, r5, r2		@ r3 = end of kernel
-		adr	r4, movecode
-		adr	r5, movecodeend
-1:		ldmia	r4!, {r6 - r12, lr}
-		stmia	r3!, {r6 - r12, lr}
-		cmp	r4, r5
+ * r0     = decompressed kernel length
+ * r1-r3  = unused
+ * r4     = kernel execution address
+ * r5     = decompressed kernel start
+ * r6     = processor ID
+ * r7     = architecture ID
+ * r8-r14 = unused
+ */
+		add	r1, r5, r0		@ end of decompressed kernel
+		adr	r2, reloc_start
+		adr	r3, reloc_end
+1:		ldmia	r2!, {r8 - r13}		@ copy relocation code
+		stmia	r1!, {r8 - r13}
+		ldmia	r2!, {r8 - r13}
+		stmia	r1!, {r8 - r13}
+		cmp	r2, r3
 		blt	1b
-		mrc	p15, 0, r5, c0, c0
-		eor	r5, r5, #0x44 << 24
-		eor	r5, r5, #0x01 << 16
-		eor	r5, r5, #0xa1 << 8
-		movs	r5, r5, lsr #4
-		mov	r5, #0
-		mcreq	p15, 0, r5, c7, c5, 0	@ flush I cache
-		ldr	r5, LC0 + 12		@ get architecture
-		ldr	r5, [r5]
-		add	pc, r1, r2		@ Call move code
+
+		eor	r1, r6, #0x44 << 24	@ SA-110?
+		eor	r1, r1, #0x01 << 16
+		eor	r1, r1, #0xa1 << 8
+		movs	r1, r1, lsr #4
+		mcreq	p15, 0, r1, c7, c7, 0	@ flush I & D-cache
+		mcreq	p15, 0, r1, c7, c10, 4	@ drain WB
+		add	pc, r5, r0		@ call relocation code
 
 /*
- * r0 = length, r1 = to, r2 = from
- */
-movecode:	add	r3, r1, r2
-		mov	r4, r0
-1:		ldmia	r1!, {r6 - r12, lr}
-		stmia	r0!, {r6 - r12, lr}
-		cmp	r1, r3
+ * r0     = decompressed kernel length
+ * r1-r3  = unused
+ * r4     = kernel execution address
+ * r5     = decompressed kernel start
+ * r6     = processor ID
+ * r7     = architecture ID
+ * r8-r14 = unused
+ */
+reloc_start:	add	r8, r5, r0
+#if 0
+	mov r0, r6
+	mov r1, #8
+	bl phex
+	mov r0, #':'
+	bl putc
+	mov r0, r5
+	mov r1, #8
+	bl phex
+	mov r0, #'-'
+	bl putc
+	mov r0, r8
+	mov r1, #8
+	bl phex
+	mov r0, #'>'
+	bl putc
+	mov r0, r4
+	mov r1, #8
+	bl phex
+	mov r0, #'\n'
+	bl putc
+#endif
+		mov	r0, r8
+		mov	r1, r4
+1:
+		.rept	4
+		ldmia	r5!, {r2, r3, r8 - r13}	@ relocate kernel
+		stmia	r1!, {r2, r3, r8 - r13}
+		.endr
+
+		cmp	r5, r0
 		blt	1b
-		mrc	p15, 0, r0, c0, c0
-		eor	r0, r0, #0x44 << 24
+#if 0
+	mov r8, r0
+	mov r0, r5
+	mov r1, #8
+	bl phex
+	mov r0, #'-'
+	bl putc
+	mov r0, r8
+	mov r1, #8
+	bl phex
+	mov r0, #'\n'
+	bl putc
+	mov	r0, r4
+	bl	memdump
+#endif
+		eor	r0, r6, #0x44 << 24	@ SA-110?
 		eor	r0, r0, #0x01 << 16
 		eor	r0, r0, #0xa1 << 8
 		movs	r0, r0, lsr #4
+		mcreq	p15, 0, r0, c7, c7, 0	@ flush I cache
+		mcreq	p15, 0, r1, c7, c10, 4	@ drain WB
+
+call_kernel:	mov	r0, #0
+		mov	r1, r7			@ restore architecture number
+		mov	pc, r4			@ call kernel
+
+phexbuf:	.space	12
+
+phex:		adr	r3, phexbuf
+		mov	r2, #0
+		strb	r2, [r3, r1]
+1:		subs	r1, r1, #1
+		movmi	r0, r3
+		bmi	puts
+		and	r2, r0, #15
+		mov	r0, r0, lsr #4
+		cmp	r2, #10
+		addge	r2, r2, #7
+		add	r2, r2, #'0'
+		strb	r2, [r3, r1]
+		b	1b
+
+puts:		mov	r3, #0x7c000000
+1:		ldrb	r2, [r0], #1
+		teq	r2, #0
+		moveq	pc, lr
+2:		strb	r2, [r3, #0x3f8]
+		mov	r1, #0x00020000
+3:		subs	r1, r1, #1
+		bne	3b
+		teq	r2, #'\n'
+		moveq	r2, #'\r'
+		beq	2b
+		teq	r0, #0
+		bne	1b
+		mov	pc, lr
+putc:
+		mov	r2, r0
 		mov	r0, #0
-		mcreq	p15, 0, r0, c7, c5, 0	@ flush I cache
-		mov	r1, r5			@ call kernel correctly
-		mov	pc, r4			@ call via EXEC entry
-movecodeend:
-
-LC0:		.word	SYMBOL_NAME(_edata)
-		.word	SYMBOL_NAME(_end)
-		.word	LOADADDR
-		.word	SYMBOL_NAME(architecture)
-		.word	start
-		.word	SYMBOL_NAME(user_stack)+4096
-		.align
+		mov	r3, #0x7c000000
+		b	2b
 
-		.bss
-SYMBOL_NAME(architecture):
-		.space	4
+memdump:	mov	r12, r0
+		mov	r10, lr
+		mov	r1, #8
+		bl	phex
+		mov	r0, #'\n'
+		bl	putc
+		mov	r11, #0
+2:		mov	r0, r11, lsl #2
+		mov	r1, #4
+		bl	phex
+		mov	r0, #':'
+		bl	putc
+1:		mov	r0, #' '
+		bl	putc
+		ldr	r0, [r12, r11, lsl #2]
+		mov	r1, #8
+		bl	phex
+		and	r0, r11, #7
+		teq	r0, #3
+		moveq	r0, #' '
+		bleq	putc
+		and	r0, r11, #7
+		add	r11, r11, #1
+		teq	r0, #7
+		bne	1b
+		mov	r0, #'\n'
+		bl	putc
+		cmp	r11, #64
+		blt	2b
+		mov	pc, r10
+reloc_end:
+
+LC0:		.word	__bss_start
+		.word	_end
+		.word	_load_addr
+		.word	_start
+		.word	user_stack+4096
 		.align
+
+		.section	".stack"
+user_stack:	.space	4096
diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/misc.c linux/arch/arm/boot/compressed/misc.c
--- v2.3.22/linux/arch/arm/boot/compressed/misc.c	Sun Sep  6 10:44:47 1998
+++ linux/arch/arm/boot/compressed/misc.c	Thu Oct 21 12:15:36 1999
@@ -7,8 +7,17 @@
  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
  *
  * Modified for ARM Linux by Russell King
+ *
+ * Nicolas Pitre <nico@visuaide.com>  1999/04/14 :
+ *  For this code to run directly from Flash, all constant variables must
+ *  be marked with 'const' and all other variables initialized at run-time 
+ *  only.  This way all non constant variables will end up in the bss segment,
+ *  which should point to addresses in RAM and cleared to 0 on start.
+ *  This allows for a much quicker boot time.
  */
 
+unsigned int __machine_arch_type;
+
 #include <asm/uaccess.h>
 #include <asm/arch/uncompress.h>
 #include <asm/proc/uncompress.h>
@@ -22,7 +31,7 @@
 /*
  * Optimised C version of memzero for the ARM.
  */
-extern __inline__ __ptr_t __memzero (__ptr_t s, size_t n)
+void __memzero (__ptr_t s, size_t n)
 {
 	union { void *vp; unsigned long *ulp; unsigned char *ucp; } u;
 	int i;
@@ -62,11 +71,8 @@
 
 	if (n & 1)
 		*u.ucp++ = 0;
-	return s;
 }
 
-#define memzero(s,n) __memzero(s,n)
-
 extern __inline__ __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
 			    size_t __n)
 {
@@ -157,11 +163,11 @@
 static void gzip_release(void **);
 
 extern char input_data[];
-extern int  input_len;
+extern char input_data_end[];
 
 static uch *output_data;
 static ulg output_ptr;
-static ulg bytes_out = 0;
+static ulg bytes_out;
 
 static void *malloc(int size);
 static void free(void *where);
@@ -226,13 +232,14 @@
  * Fill the input buffer. This is called only when the buffer is empty
  * and at least one byte is really needed.
  */
-int fill_inbuf()
+int fill_inbuf(void)
 {
 	if (insize != 0)
 		error("ran out of input data\n");
 
 	inbuf = input_data;
-	insize = input_len;
+	insize = &input_data_end[0] - &input_data[0];
+
 	inptr = 1;
 	return inbuf[0];
 }
@@ -241,7 +248,7 @@
  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  * (Used for the decompressed data only.)
  */
-void flush_window()
+void flush_window(void)
 {
 	ulg c = crc;
 	unsigned n;
@@ -257,6 +264,7 @@
 	bytes_out += (ulg)outcnt;
 	output_ptr += (ulg)outcnt;
 	outcnt = 0;
+	puts(".");
 }
 
 static void error(char *x)
@@ -270,26 +278,24 @@
 	while(1);	/* Halt */
 }
 
-#define STACK_SIZE (4096)
-
-ulg user_stack [STACK_SIZE];
-
 #ifndef STANDALONE_DEBUG
 
-ulg decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p)
-{
-	free_mem_ptr = free_mem_ptr_p;
-	free_mem_ptr_end = free_mem_ptr_end_p;
-
-	proc_decomp_setup ();
-	arch_decomp_setup ();
+ulg
+decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
+		  int arch_id)
+{
+	output_data		= (uch *)output_start;	/* Points to kernel start */
+	free_mem_ptr		= free_mem_ptr_p;
+	free_mem_ptr_end	= free_mem_ptr_end_p;
+	__machine_arch_type	= arch_id;
 
-	output_data = (uch *)output_start;	/* Points to kernel start */
+	proc_decomp_setup();
+	arch_decomp_setup();
 
 	makecrc();
 	puts("Uncompressing Linux...");
 	gunzip();
-	puts("done.\nNow booting the kernel\n");
+	puts(" done, booting the kernel.\n");
 	return output_ptr;
 }
 #else
diff -u --recursive --new-file v2.3.22/linux/arch/arm/boot/compressed/vmlinux.lds.in linux/arch/arm/boot/compressed/vmlinux.lds.in
--- v2.3.22/linux/arch/arm/boot/compressed/vmlinux.lds.in	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/boot/compressed/vmlinux.lds.in	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,52 @@
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+  . = LOAD_ADDR;
+  _load_addr = .;
+
+  . = TEXT_START;
+  _text = .;
+
+  .text : {
+    _start = .;
+    head.o(.start)
+    *(.start)
+    head.o(.text)
+    *(.text)
+    *(.fixup)
+    *(.gnu.warning)
+    input_data = .;
+    piggy.o
+    input_data_end = .;
+    . = ALIGN(4);
+  }
+
+  _etext = .;
+
+  .data : {
+    *(.data)
+  }
+
+  _edata = .;
+
+  . = BSS_START;
+  __bss_start = .;
+  .bss : {
+    *(.bss)
+  }
+  _end = .;
+
+  .stack : {
+    *(.stack)
+  }
+
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
+
diff -u --recursive --new-file v2.3.22/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.3.22/linux/arch/arm/config.in	Sat Oct  9 11:47:50 1999
+++ linux/arch/arm/config.in	Wed Oct 20 16:29:08 1999
@@ -20,7 +20,7 @@
 	 RiscPC			CONFIG_ARCH_RPC \
 	 EBSA-110		CONFIG_ARCH_EBSA110 \
 	 FootBridge-based	CONFIG_FOOTBRIDGE" RiscPC
-
+# 	 SA1100-based		CONFIG_ARCH_SA1100
 if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
    bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE
    if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
@@ -31,9 +31,9 @@
 fi
 
 if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
-   bool '  Include support for Intel EBSA285' CONFIG_ARCH_EBSA285
-   bool '  Include support for Chalice CATS boards' CONFIG_CATS
-   bool '  Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER
+   bool '  Include support for EBSA285' CONFIG_ARCH_EBSA285
+   bool '  Include support for CATS' CONFIG_CATS
+   bool '  Include support for NetWinder' CONFIG_ARCH_NETWINDER
 fi
 
 if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then
@@ -42,6 +42,18 @@
    define_bool CONFIG_ARCH_CO285 y
 fi
 
+if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+   define_bool CONFIG_CPU_SA1100 y
+   choice 'SA1100 implementation' \
+	"Brutus			CONFIG_SA1100_BRUTUS \
+	 empeg			CONFIG_SA1100_EMPEG \
+	 Itsy			CONFIG_SA1100_ITSY \
+	 LART			CONFIG_SA1100_LART \
+	 PLEB			CONFIG_SA1100_PLEB \
+	 Victor			CONFIG_SA1100_VICTOR \
+	 Tifon			CONFIG_SA1100_TIFON" Brutus
+fi
+
 #
 # Select various configuration options depending on the machine type
 #  Easy check for Acorn-style architectures
@@ -76,6 +88,7 @@
    # Select CPU and optimisation dependent on architecture
    #
    if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
+        "$CONFIG_ARCH_SA1100" = "y" -o \
         "$CONFIG_FOOTBRIDGE" = "y" -o \
         "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
       define_bool CONFIG_CPU_32v4 y
@@ -139,21 +152,10 @@
    tristate 'RISC OS personality' CONFIG_ARTHUR
 fi
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-   if [ "$CONFIG_ARCH_ARC" = "y" ]; then
-      dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
-   fi
-   dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-   # If exactly one hardware type is selected then parport will optimise away
-   # support for loading any others.  Defeat this if the user is keen.
-   if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then
-      if [ "$CONFIG_PARPORT_PC" != "n" -o "$CONFIG_PARPORT_ARC" != "n" ]; then
-         bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-      fi
-   fi
-fi
+source drivers/parport/Config.in
+
 if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
+     "$CONFIG_ARCH_SA1100" = "y" -o \
      "$CONFIG_ARCH_NETWINDER" = "y" -o \
      "$CONFIG_CATS" = "y" ]; then
    string 'Initial kernel command string' CONFIG_CMDLINE
@@ -165,10 +167,10 @@
    bool 'Timer and CPU usage LEDs' CONFIG_LEDS
    if [ "$CONFIG_LEDS" = "y" ]; then
       if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \
-           "$CONFIG_ARCH_EBSA285" = "y" -o   \
+	   "$CONFIG_ARCH_EBSA285" = "y" -o   \
 	   "$CONFIG_ARCH_CO285" = "y" ]; then
-	 bool '  Timer LED' CONFIG_LEDS_TIMER
-	 bool '  CPU usage LED' CONFIG_LEDS_CPU
+         bool '  Timer LED' CONFIG_LEDS_TIMER
+         bool '  CPU usage LED' CONFIG_LEDS_CPU
       fi
    fi
 fi
@@ -186,11 +188,11 @@
 
 source drivers/char/Config.in
 if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-   if [ "$CONFIG_MOUSE" = "y" ]; then
+   if [ "$CONFIG_BUSMOUSE" = "y" ]; then
       if [ "$CONFIG_ARCH_RPC" != "y" ]; then
-	 define_bool CONFIG_KBDMOUSE y
+         define_bool CONFIG_KBDMOUSE y
       else
-	 define_bool CONFIG_RPCMOUSE y
+         define_bool CONFIG_RPCMOUSE y
       fi
    fi
 fi
@@ -230,7 +232,7 @@
 #
 # tristate 'ISDN support' CONFIG_ISDN
 # if [ "$CONFIG_ISDN" != "n" ]; then
-#   source drivers/isdn/Config.in
+#    source drivers/isdn/Config.in
 # fi
 # endmenu
 
@@ -267,17 +269,17 @@
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  if [ "$CONFIG_CPU_26" = "y" ]; then
-    bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE
-  fi
-
-  # These options are only for real kernel hackers
-  # who want to get their hands dirty. 
-  bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL
-  if [ "$CONFIG_DEBUG_LL" = "y" ]; then
-    if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
-      bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT
-    fi
-  fi
+   if [ "$CONFIG_CPU_26" = "y" ]; then
+      bool 'Disable pgtable cache (EXPERIMENTAL)' CONFIG_NO_PGT_CACHE
+   fi
+
+   # These options are only for real kernel hackers
+   # who want to get their hands dirty. 
+   bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL
+   if [ "$CONFIG_DEBUG_LL" = "y" ]; then
+      if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+         bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT
+      fi
+   fi
 fi
 endmenu
diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/brutus linux/arch/arm/def-configs/brutus
--- v2.3.22/linux/arch/arm/def-configs/brutus	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/brutus	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,221 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_SA1100=y
+CONFIG_CPU_SA1100=y
+CONFIG_SA1100_BRUTUS=y
+# CONFIG_SA1100_EMPEG is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_TIFON is not set
+# CONFIG_ARCH_ACORN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+CONFIG_CPU_32v4=y
+CONFIG_CPU_SA110=y
+# CONFIG_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+# CONFIG_NET is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_NWFPE=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+# CONFIG_PARPORT is not set
+CONFIG_CMDLINE=""
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_CPQ_DA is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL_SA1100=y
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+
+#
+# USB drivers - not for the faint of heart
+#
+# CONFIG_USB is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_SA1100=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/empeg linux/arch/arm/def-configs/empeg
--- v2.3.22/linux/arch/arm/def-configs/empeg	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/empeg	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,264 @@
+#
+# Example empeg-car kernel configuration file.
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_SA1100=y
+CONFIG_CPU_SA1100=y
+# CONFIG_SA1100_BRUTUS is not set
+CONFIG_SA1100_EMPEG=y
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_EMPEG_HENRY is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+# CONFIG_TEXT_SECTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_NWFPE=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+# CONFIG_PARPORT is not set
+CONFIG_CMDLINE=""
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EMPEG_IR=y
+CONFIG_EMPEG_USB=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_DEV=y
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_GEMTEK is not set
+CONFIG_RADIO_EMPEG=y
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+# CONFIG_UNIX is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_RARP is not set
+# CONFIG_SKB_LARGE is not set
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA subsystem support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+CONFIG_PPP=y
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_USER_BACKTRACE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge
--- v2.3.22/linux/arch/arm/def-configs/footbridge	Mon Jul 19 09:52:57 1999
+++ linux/arch/arm/def-configs/footbridge	Wed Oct 20 16:29:08 1999
@@ -17,22 +17,18 @@
 # CONFIG_CATS is not set
 CONFIG_ARCH_NETWINDER=y
 # CONFIG_ARCH_ACORN is not set
-CONFIG_PCI=y
-CONFIG_ISA_DMA=y
 CONFIG_CPU_32=y
 # CONFIG_CPU_26 is not set
-# CONFIG_CPU_ARM2 is not set
-# CONFIG_CPU_ARM3 is not set
-# CONFIG_CPU_ARM6 is not set
-# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_32v4=y
 CONFIG_CPU_SA110=y
+CONFIG_PCI=y
+CONFIG_ISA_DMA=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 # CONFIG_ALIGNMENT_TRAP is not set
-# CONFIG_TEXT_SECTIONS is not set
 
 #
 # Loadable module support
@@ -55,15 +51,35 @@
 # CONFIG_ARTHUR is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
 CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune"
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 # CONFIG_LEDS_CPU is not set
 
 #
-# Plug and Play support
+# I2O device support
 #
-# CONFIG_PNP is not set
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Plug and Play configuration
+#
+CONFIG_PNP=y
+CONFIG_ISAPNP=y
 
 #
 # Block devices
@@ -76,6 +92,7 @@
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -89,7 +106,7 @@
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 CONFIG_BLK_DEV_SL82C105=y
 # CONFIG_IDE_CHIPSETS is not set
@@ -136,6 +153,7 @@
 CONFIG_PARIDE_KTTI=m
 CONFIG_PARIDE_ON20=m
 CONFIG_PARIDE_ON26=m
+CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -149,15 +167,14 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_PRINTER=m
-CONFIG_PRINTER_READBACK=y
-CONFIG_MOUSE=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
 
 #
 # Mice
 #
-# CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
+CONFIG_MOUSE=y
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
@@ -172,6 +189,8 @@
 CONFIG_SOFT_WATCHDOG=y
 # CONFIG_PCWATCHDOG is not set
 # CONFIG_ACQUIRE_WDT is not set
+# CONFIG_21285_WATCHDOG is not set
+CONFIG_977_WATCHDOG=m
 CONFIG_DS1620=y
 CONFIG_NWBUTTON=y
 CONFIG_NWBUTTON_REBOOT=y
@@ -189,6 +208,8 @@
 #
 # CONFIG_JOYSTICK is not set
 # CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -196,11 +217,35 @@
 # CONFIG_FTAPE is not set
 
 #
+# USB drivers - not for the faint of heart
+#
+CONFIG_USB=m
+# CONFIG_USB_UHCI is not set
+CONFIG_USB_OHCI=m
+CONFIG_USB_OHCI_DEBUG=y
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_VROOTHUB=y
+# CONFIG_USB_DEBUG_ISOC is not set
+CONFIG_USB_HUB=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_KBD=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_CPIA is not set
+CONFIG_USB_SCSI=m
+CONFIG_USB_SCSI_DEBUG=m
+# CONFIG_USB_EZUSB is not set
+# CONFIG_USB_USS720 is not set
+CONFIG_USB_PROC=y
+
+#
 # Console drivers
 #
 CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
 CONFIG_FB_CYBER2000=y
 # CONFIG_FB_MATROX is not set
@@ -220,6 +265,7 @@
 # CONFIG_FBCON_IPLAN2P4 is not set
 # CONFIG_FBCON_IPLAN2P8 is not set
 # CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
 CONFIG_FBCON_VGA=y
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
@@ -235,8 +281,9 @@
 # Networking options
 #
 CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -254,15 +301,17 @@
 #
 # (it is safe to leave these untouched)
 #
-# CONFIG_INET_RARP is not set
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -271,7 +320,6 @@
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
 
 #
 # QoS and/or fair queueing
@@ -284,7 +332,7 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA subsystem support
+# IrDA (infrared) support
 #
 # CONFIG_IRDA is not set
 
@@ -292,9 +340,18 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
 # CONFIG_ARM_AM79C961A is not set
 CONFIG_NET_VENDOR_3COM=y
@@ -309,11 +366,12 @@
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 # CONFIG_PCNET32 is not set
+# CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -332,23 +390,32 @@
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
-
-#
-# CCP compressors for PPP are only built as modules.
-#
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
 CONFIG_SLIP_MODE_SLIP6=y
 # CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
 # CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
-# CONFIG_RCPCI is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_DLCI is not set
 
 #
 # SCSI support
@@ -359,8 +426,10 @@
 # Sound
 #
 CONFIG_SOUND=m
+# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
@@ -410,6 +479,7 @@
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_MINIX_FS is not set
@@ -438,12 +508,17 @@
 #
 # Partition Types
 #
+CONFIG_PARTITION_ADVANCED=y
 # CONFIG_OSF_PARTITION is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
 CONFIG_ACORN_PARTITION=y
 CONFIG_ACORN_PARTITION_ADFS=y
 # CONFIG_ACORN_PARTITION_ICS is not set
@@ -479,6 +554,7 @@
 # CONFIG_NLS_ISO8859_7 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
 CONFIG_NLS_ISO8859_15=m
 # CONFIG_NLS_KOI8_R is not set
 
@@ -487,7 +563,7 @@
 #
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.22/linux/arch/arm/def-configs/victor linux/arch/arm/def-configs/victor
--- v2.3.22/linux/arch/arm/def-configs/victor	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/victor	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,207 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_SA1100=y
+CONFIG_CPU_SA1100=y
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_EMPEG is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_PLEB is not set
+CONFIG_SA1100_VICTOR=y
+# CONFIG_VICTOR_BOARD1 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+# CONFIG_TEXT_SECTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+# CONFIG_NET is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_NWFPE=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+# CONFIG_PARPORT is not set
+CONFIG_CMDLINE=""
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_IDEDISK is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.22/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.3.22/linux/arch/arm/defconfig	Sat Jun 26 08:34:19 1999
+++ linux/arch/arm/defconfig	Wed Oct 20 16:29:08 1999
@@ -55,7 +55,7 @@
 # CONFIG_ARTHUR is not set
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
-CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune"
+CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune"
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 # CONFIG_LEDS_CPU is not set
@@ -89,7 +89,7 @@
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 CONFIG_BLK_DEV_SL82C105=y
 # CONFIG_IDE_CHIPSETS is not set
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.3.22/linux/arch/arm/kernel/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/Makefile	Wed Oct 20 16:29:08 1999
@@ -22,6 +22,7 @@
 O_OBJS_ebsa110    = dma-dummy.o
 O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) isa.o
 O_OBJS_nexuspci   = dma-dummy.o
+O_OBJS_sa1100     = dma-dummy.o fiq.o
 
 OX_OBJS_arc	  = dma.o
 OX_OBJS_a5k	  = dma.o
@@ -29,11 +30,16 @@
 OX_OBJS_ebsa110	  = 
 OX_OBJS_footbridge= dma.o hw-footbridge.o
 OX_OBJS_nexuspci  =
+OX_OBJS_sa1100    =
 
 all: kernel.o $(HEAD_OBJ) init_task.o
 
 O_OBJS += $(O_OBJS_$(MACHINE))
 
+ifeq ($(CONFIG_DEBUG_LL),y)
+  O_OBJS += debug-$(PROCESSOR).o
+endif
+
 ifeq ($(CONFIG_MODULES),y)
   OX_OBJS = armksyms.o
 endif
@@ -42,17 +48,15 @@
   OX_OBJS += ecard.o
 endif
 
-ifeq ($(MACHINE),nexuspci)
-  ifdef CONFIG_PCI
+ifeq ($(CONFIG_PCI),y)
+  ifeq ($(MACHINE),nexuspci)
     O_OBJS += plx9080.o
-  endif
-else
-  ifdef CONFIG_PCI
+  else
     O_OBJS += bios32.o dec21285.o
   endif
 endif
 
-ifdef CONFIG_LEDS
+ifeq ($(CONFIG_LEDS),y)
   OX_OBJS += leds-$(MACHINE).o
 endif
 
@@ -73,13 +77,11 @@
 $(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
 	$(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
 
-$(ENTRY_OBJ): $(ENTRY_OBJ:.o=.S)
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $(ENTRY_OBJ:.o=.S) -o $@
-
 include $(TOPDIR)/Rules.make
 
-$(ENTRY_OBJ): ../lib/constants.h
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $<
 
 # Spell out some dependencies that `make dep' doesn't spot
-entry-armv.o: calls.S
-entry-armo.o: calls.S
+entry-armv.o: calls.S ../lib/constants.h
+entry-armo.o: calls.S ../lib/constants.h
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.3.22/linux/arch/arm/kernel/armksyms.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/armksyms.c	Wed Oct 20 16:29:08 1999
@@ -2,12 +2,14 @@
 #include <linux/module.h>
 #include <linux/user.h>
 #include <linux/string.h>
+#include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/in6.h>
 
+#include <asm/byteorder.h>
 #include <asm/elf.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -93,6 +95,9 @@
 EXPORT_SYMBOL(__iounmap);
 #endif
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(system_rev);
+EXPORT_SYMBOL(system_serial_low);
+EXPORT_SYMBOL(system_serial_high);
 
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -108,7 +113,7 @@
 EXPORT_SYMBOL(cpu_flush_ram_page);
 EXPORT_SYMBOL(cpu_flush_tlb_all);
 EXPORT_SYMBOL(cpu_flush_tlb_area);
-EXPORT_SYMBOL(cpu_switch_mm);
+EXPORT_SYMBOL(cpu_set_pgd);
 EXPORT_SYMBOL(cpu_set_pmd);
 EXPORT_SYMBOL(cpu_set_pte);
 EXPORT_SYMBOL(cpu_flush_icache_area);
@@ -165,19 +170,20 @@
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(__memset);
+EXPORT_SYMBOL_NOVERS(memset); /* needed for some versions of gcc */
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memmove);
 EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memscan);
-EXPORT_SYMBOL_NOVERS(memzero);
+EXPORT_SYMBOL_NOVERS(__memzero);
 
 	/* user mem (segment) */
 #if defined(CONFIG_CPU_32)
 EXPORT_SYMBOL(__arch_copy_from_user);
 EXPORT_SYMBOL(__arch_copy_to_user);
 EXPORT_SYMBOL(__arch_clear_user);
-EXPORT_SYMBOL(__arch_strlen_user);
+EXPORT_SYMBOL(__arch_strnlen_user);
 #elif defined(CONFIG_CPU_26)
 EXPORT_SYMBOL(uaccess_kernel);
 EXPORT_SYMBOL(uaccess_user);
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.3.22/linux/arch/arm/kernel/bios32.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/arm/kernel/bios32.c	Wed Oct 20 16:29:08 1999
@@ -7,6 +7,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/errno.h>
 #include <linux/init.h>
 
 #include <asm/irq.h>
@@ -71,6 +72,38 @@
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 },
 	{ 0 }
 };
+
+/*
+ * Assign new address to PCI resource.  We hope our resource information
+ * is complete.  On the PC, we don't re-assign resources unless we are
+ * forced to do so.
+ *
+ * Expects start=0, end=size-1, flags=resource type.
+ */
+
+int __init pcibios_assign_resource(struct pci_dev *dev, int i)
+{
+	struct resource *r = &dev->resource[i];
+	struct resource *pr = pci_find_parent_resource(dev, r);
+	unsigned long size = r->end + 1;
+	unsigned long flags = 0;
+
+	if (!pr)
+		return -EINVAL;
+	if (r->flags & IORESOURCE_IO) {
+		if (size > 0x100)
+			return -EFBIG;
+		if (allocate_resource(pr, r, size, 0x9000, ~0, 1024))
+			return -EBUSY;
+		flags = PCI_BASE_ADDRESS_SPACE_IO;
+	} else {
+		if (allocate_resource(pr, r, size, 0x00100000, 0x7fffffff, size))
+			return -EBUSY;
+	}
+	if (i < 6)
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start | flags);
+	return 0;
+}
 
 /*
  * Assign an address to an I/O range.
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/debug-armo.S linux/arch/arm/kernel/debug-armo.S
--- v2.3.22/linux/arch/arm/kernel/debug-armo.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/debug-armo.S	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/arm/kernel/debug-armo.S
+ *
+ * Copyright (C) 1999 Russell King
+ *
+ * 26-bit debugging code
+ */
+#include <linux/linkage.h>
+
+		.macro	addruart,rx
+		mov	\rx, #0x03000000
+		orr	\rx, \rx, #0x00010000
+		orr	\rx, \rx, #0x00000fe0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldrb	\rd, [\rx, #0x14]
+		and	\rd, \rd, #0x60
+		teq	\rd, #0x60
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x18]
+		tst	\rd, #0x10
+		beq	1001b
+		.endm
+
+		.text
+/*
+ * Useful debugging routines
+ */
+ENTRY(printhex8)
+		mov	r1, #8
+		b	printhex
+
+ENTRY(printhex4)
+		mov	r1, #4
+		b	printhex
+
+ENTRY(printhex2)
+		mov	r1, #2
+printhex:	ldr	r2, =hexbuf
+		add	r3, r2, r1
+		mov	r1, #0
+		strb	r1, [r3]
+1:		and	r1, r0, #15
+		mov	r0, r0, lsr #4
+		cmp	r1, #10
+		addlt	r1, r1, #'0'
+		addge	r1, r1, #'a' - 10
+		strb	r1, [r3, #-1]!
+		teq	r3, r2
+		bne	1b
+		mov	r0, r2
+		b	printascii
+
+		.ltorg
+
+ENTRY(printascii)
+		addruart r3
+		b	2f
+1:		waituart r2, r3
+		senduart r1, r3
+		busyuart r2, r3
+		teq	r1, #'\n'
+		moveq	r1, #'\r'
+		beq	1b
+2:		teq	r0, #0
+		ldrneb	r1, [r0], #1
+		teqne	r1, #0
+		bne	1b
+		mov	pc, lr
+
+ENTRY(printch)
+		addruart r3
+		mov	r1, r0
+		mov	r0, #0
+		b	1b
+
+		.bss
+hexbuf:		.space 16
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S
--- v2.3.22/linux/arch/arm/kernel/debug-armv.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/debug-armv.S	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,206 @@
+/*
+ * linux/arch/arm/kernel/debug-armv.S
+ *
+ * Copyright (C) 1994-1999 Russell King
+ *
+ * 32-bit debugging code
+ */
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/hardware.h>
+#include <asm/dec21285.h>
+
+		.text
+
+/*
+ * Some debugging routines (useful if you've got MM problems and
+ * printk isn't working).  For DEBUGGING ONLY!!!  Do not leave
+ * references to these in a production kernel!
+ */
+#if defined(CONFIG_ARCH_RPC)
+		.macro	addruart,rx
+		mov	\rx, #0xe0000000
+		orr	\rx, \rx, #0x00010000
+		orr	\rx, \rx, #0x00000fe0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldrb	\rd, [\rx, #0x14]
+		and	\rd, \rd, #0x60
+		teq	\rd, #0x60
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x18]
+		tst	\rd, #0x10
+		beq	1001b
+		.endm
+
+#elif defined(CONFIG_ARCH_EBSA110)
+		.macro	addruart,rx
+		mov	\rx, #0xf0000000
+		orr	\rx, \rx, #0x00000be0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldrb	\rd, [\rx, #0x14]
+		and	\rd, \rd, #0x60
+		teq	\rd, #0x60
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x18]
+		tst	\rd, #0x10
+		beq	1001b
+		.endm
+
+#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
+#ifndef CONFIG_DEBUG_DC21285_PORT
+	/* For NetWinder debugging */
+		.macro	addruart,rx
+		mov	\rx, #0xff000000
+		orr	\rx, \rx, #0x000003f8
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldrb	\rd, [\rx, #0x5]
+		and	\rd, \rd, #0x60
+		teq	\rd, #0x60
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x6]
+		tst	\rd, #0x10
+		beq	1001b
+		.endm
+#else
+	/* For EBSA285 debugging */
+		.equ	dc21285_high, ARMCSR_BASE & 0xff000000
+		.equ	dc21285_low,  ARMCSR_BASE & 0x00ffffff
+
+		.macro	addruart,rx
+		mov	\rx, #dc21285_high
+		.if	dc21285_low
+		orr	\rx, \rx, #dc21285_low
+		.endif
+		.endm
+
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #0x160]	@ UARTDR
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:		ldr	\rd, [\rx, #0x178]	@ UARTFLG
+		tst	\rd, #1 << 3
+		bne	1001b
+		.endm
+
+		.macro	waituart,rd,rx
+		.endm
+#endif
+#elif defined(CONFIG_ARCH_NEXUSPCI)
+		.macro	addruart,rx
+		ldr	\rx, =0xfff00000
+		.endm
+
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #0xc]
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:		ldr	\rd, [\rx, #0x4]
+		tst	\rd, #1 << 0
+		bne	1001b
+		.endm
+
+		.macro	waituart,rd,rx
+		.endm
+
+#elif defined(CONFIG_ARCH_SA1100)
+		.macro	addruart,rx
+		mov	\rx, #0xf8000000
+		add	\rx, \rx, #0x00050000
+		.endm
+
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #0x14]	@ UARTDR
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:		ldr	\rd, [\rx, #0x20]	@ UTSR1
+		tst	\rd, #1 << 2
+		beq	1001b
+		.endm
+
+#else
+#error Unknown architecture
+#endif
+
+/*
+ * Useful debugging routines
+ */
+ENTRY(printhex8)
+		mov	r1, #8
+		b	printhex
+
+ENTRY(printhex4)
+		mov	r1, #4
+		b	printhex
+
+ENTRY(printhex2)
+		mov	r1, #2
+printhex:	ldr	r2, =hexbuf
+		add	r3, r2, r1
+		mov	r1, #0
+		strb	r1, [r3]
+1:		and	r1, r0, #15
+		mov	r0, r0, lsr #4
+		cmp	r1, #10
+		addlt	r1, r1, #'0'
+		addge	r1, r1, #'a' - 10
+		strb	r1, [r3, #-1]!
+		teq	r3, r2
+		bne	1b
+		mov	r0, r2
+		b	printascii
+
+		.ltorg
+
+ENTRY(printascii)
+		addruart r3
+		b	2f
+1:		waituart r2, r3
+		senduart r1, r3
+		busyuart r2, r3
+		teq	r1, #'\n'
+		moveq	r1, #'\r'
+		beq	1b
+2:		teq	r0, #0
+		ldrneb	r1, [r0], #1
+		teqne	r1, #0
+		bne	1b
+		mov	pc, lr
+
+ENTRY(printch)
+		addruart r3
+		mov	r1, r0
+		mov	r0, #0
+		b	1b
+
+		.bss
+hexbuf:		.space 16
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c
--- v2.3.22/linux/arch/arm/kernel/dec21285.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/dec21285.c	Wed Oct 20 16:29:08 1999
@@ -13,241 +13,318 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 
+#include <asm/dec21285.h>
+#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/hardware.h>
 
 #define MAX_SLOTS		21
 
-extern void pcibios_fixup_ebsa285(struct pci_dev *dev);
-extern void pcibios_init_ebsa285(void);
+extern int setup_arm_irq(int, struct irqaction *);
+extern void pcibios_report_device_errors(void);
+extern int (*pci_irq_fixup)(struct pci_dev *dev);
 
-int
-pcibios_present(void)
+static unsigned long
+dc21285_base_address(struct pci_dev *dev, int where)
 {
-	return 1;
+	unsigned long addr = 0;
+	unsigned int devfn = dev->devfn;
+
+	if (dev->bus->number != 0)
+		addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8);
+	else if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
+		addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
+
+	return addr;
 }
 
-static unsigned long
-pcibios_base_address(unsigned char bus, unsigned char dev_fn)
+static int
+dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value)
 {
-	if (bus == 0) {
-		int slot = PCI_SLOT(dev_fn);
-		
-		if (slot < MAX_SLOTS)
-			return PCICFG0_BASE + 0xc00000 +
-				(slot << 11) + (PCI_FUNC(dev_fn) << 8);
-		else
-			return 0;
-	} else
-		return PCICFG1_BASE | (bus << 16) | (dev_fn << 8);
-}
-
-int
-pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-			 unsigned char where, unsigned char *val)
-{
-	unsigned long addr = pcibios_base_address(bus, dev_fn);
-	unsigned char v;
-
-	if (addr)
-		__asm__("ldr%?b	%0, [%1, %2]"
-			: "=r" (v)
-			: "r" (addr), "r" (where));
+	unsigned long addr = dc21285_base_address(dev, where);
+	u8 v;
+
+	if (addr)
+		asm("ldr%?b	%0, [%1, %2]"
+			: "=r" (v) : "r" (addr), "r" (where));
 	else
 		v = 0xff;
-	*val = v;
+
+	*value = v;
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int
-pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-			 unsigned char where, unsigned short *val)
+static int
+dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value)
 {
-	unsigned long addr = pcibios_base_address(bus, dev_fn);
-	unsigned short v;
+	unsigned long addr = dc21285_base_address(dev, where);
+	u16 v;
 
 	if (addr)
-		__asm__("ldr%?h	%0, [%1, %2]"
-			: "=r" (v)
-			: "r" (addr), "r" (where));
+		asm("ldr%?h	%0, [%1, %2]"
+			: "=r" (v) : "r" (addr), "r" (where));
 	else
 		v = 0xffff;
-	*val = v;
+
+	*value = v;
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int
-pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-			  unsigned char where, unsigned int *val)
+static int
+dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
-	unsigned long addr = pcibios_base_address(bus, dev_fn);
-	unsigned int v;
+	unsigned long addr = dc21285_base_address(dev, where);
+	u32 v;
 
 	if (addr)
-		__asm__("ldr%?	%0, [%1, %2]"
-			: "=r" (v)
-			: "r" (addr), "r" (where));
+		asm("ldr%?	%0, [%1, %2]"
+			: "=r" (v) : "r" (addr), "r" (where));
 	else
 		v = 0xffffffff;
-	*val = v;
+
+	*value = v;
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int
-pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-			  unsigned char where, unsigned char val)
+static int
+dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value)
 {
-	unsigned long addr = pcibios_base_address(bus, dev_fn);
+	unsigned long addr = dc21285_base_address(dev, where);
 
 	if (addr)
-		__asm__("str%?b	%0, [%1, %2]"
-			: : "r" (val), "r" (addr), "r" (where));
+		asm("str%?b	%0, [%1, %2]"
+			: : "r" (value), "r" (addr), "r" (where));
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int
-pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-			  unsigned char where, unsigned short val)
+static int
+dc21285_write_config_word(struct pci_dev *dev, int where, u16 value)
 {
-	unsigned long addr = pcibios_base_address(bus, dev_fn);
+	unsigned long addr = dc21285_base_address(dev, where);
 
 	if (addr)
-		__asm__("str%?h	%0, [%1, %2]"
-			: : "r" (val), "r" (addr), "r" (where));
+		asm("str%?h	%0, [%1, %2]"
+			: : "r" (value), "r" (addr), "r" (where));
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int
-pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-			   unsigned char where, unsigned int val)
+static int
+dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value)
 {
-	unsigned long addr = pcibios_base_address(bus, dev_fn);
+	unsigned long addr = dc21285_base_address(dev, where);
 
 	if (addr)
-		__asm__("str%?	%0, [%1, %2]"
-			: : "r" (val), "r" (addr), "r" (where));
+		asm("str%?	%0, [%1, %2]"
+			: : "r" (value), "r" (addr), "r" (where));
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
-void __init pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set)
+static struct pci_ops dc21285_ops = {
+	dc21285_read_config_byte,
+	dc21285_read_config_word,
+	dc21285_read_config_dword,
+	dc21285_write_config_byte,
+	dc21285_write_config_word,
+	dc21285_write_config_dword,
+};
+
+/*
+ * Warn on PCI errors.
+ */
+static void
+dc21285_error(int irq, void *dev_id, struct pt_regs *regs)
+{
+	static unsigned long next_warn;
+	unsigned long cmd       = *CSR_PCICMD & 0x0000ffff;
+	unsigned long ctrl      = (*CSR_SA110_CNTL) & 0xffffde07;
+	unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
+	int warn = time_after_eq(jiffies, next_warn);
+
+	ctrl |= SA110_CNTL_DISCARDTIMER;
+
+	if (warn) {
+		next_warn = jiffies + HZ;
+		printk(KERN_DEBUG "PCI: ");
+	}
+
+	if (irqstatus & (1 << 31)) {
+		if (warn)
+			printk("parity error ");
+		cmd |= 1 << 31;
+	}
+
+	if (irqstatus & (1 << 30)) {
+		if (warn)
+			printk("target abort ");
+		cmd |= 1 << 28;
+	}
+
+	if (irqstatus & (1 << 29)) {
+		if (warn)
+			printk("master abort ");
+		cmd |= 1 << 29;
+	}
+
+	if (irqstatus & (1 << 28)) {
+		if (warn)
+			printk("data parity error ");
+		cmd |= 1 << 24;
+	}
+
+	if (irqstatus & (1 << 27)) {
+		if (warn)
+			printk("discard timer expired ");
+		ctrl &= ~SA110_CNTL_DISCARDTIMER;
+	}
+
+	if (irqstatus & (1 << 23)) {
+		if (warn)
+			printk("system error ");
+		ctrl |= SA110_CNTL_RXSERR;
+	}
+
+	if (warn)
+		printk("pc=[<%08lX>]\n", instruction_pointer(regs));
+
+	pcibios_report_device_errors();
+
+	*CSR_PCICMD = cmd;
+	*CSR_SA110_CNTL = ctrl;
+}
+
+static struct irqaction dc21285_error_action = {
+	dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL
+};
+
+static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 };
+
+static int __init ebsa_irqval(struct pci_dev *dev)
 {
-	unsigned short cmd;
+	u8 pin;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	cmd = (cmd & ~clear) | set;
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
+	return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
 }
 
-void __init pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr)
+static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
+
+static int __init cats_irqval(struct pci_dev *dev)
 {
-	int reg = PCI_BASE_ADDRESS_0 + (idx << 2);
+	if (dev->irq >= 128)
+		return 16 + (dev->irq & 0x1f);
 
-	pci_write_config_dword(dev, reg, addr);
-	pci_read_config_dword(dev, reg, &addr);
+	switch (dev->irq) {
+	case 1 ... 4:
+		return irqmap_cats[dev->irq - 1];
 
-	dev->base_address[idx] = addr;
+	default:
+		printk("PCI: device %02x:%02x has unknown irq line %x\n",
+		       dev->bus->number, dev->devfn, dev->irq);
+	case 0:
+		break;
+	}
+	return 0;
 }
 
-void __init pcibios_fixup(void)
+static int __init netwinder_irqval(struct pci_dev *dev)
 {
-	struct pci_dev *dev;
+#define DEV(v,d) ((v)<<16|(d))
+	switch (DEV(dev->vendor, dev->device)) {
+	case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142):
+		return IRQ_NETWINDER_ETHER100;
+
+	case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a):
+		return IRQ_NETWINDER_ETHER10;
 
-	for (dev = pci_devices; dev; dev = dev->next) {
-		pcibios_fixup_ebsa285(dev);
+	case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553):
+		return 0;
 
-		pcibios_write_config_byte(dev->bus->number, dev->devfn,
-					  PCI_INTERRUPT_LINE, dev->irq);
+	case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105):
+		return IRQ_ISA_HARDDISK1;
 
-		printk(KERN_DEBUG
-		       "PCI: %02x:%02x [%04x/%04x] on irq %d\n",
+	case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000):
+		return IRQ_NETWINDER_VGA;
+
+	default:
+		printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n",
 			dev->bus->number, dev->devfn,
-			dev->vendor, dev->device, dev->irq);
+			dev->vendor, dev->device);
+		return 0;
 	}
-
-	hw_init();
 }
 
-void __init pcibios_init(void)
+struct pci_ops * __init dc21285_init(int pass)
 {
-	unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET;
+	unsigned int mem_size;
 	unsigned long cntl;
 
-	*CSR_SDRAMBASEMASK    = (mem_size - 1) & 0x0ffc0000;
-	*CSR_SDRAMBASEOFFSET  = 0;
-	*CSR_ROMBASEMASK      = 0x80000000;
-	*CSR_CSRBASEMASK      = 0;
-	*CSR_CSRBASEOFFSET    = 0;
-	*CSR_PCIADDR_EXTN     = 0;
+	if (pass == 0) {
+		mem_size = (unsigned int)high_memory - PAGE_OFFSET;
+		*CSR_SDRAMBASEMASK    = (mem_size - 1) & 0x0ffc0000;
+		*CSR_SDRAMBASEOFFSET  = 0;
+		*CSR_ROMBASEMASK      = 0x80000000;
+		*CSR_CSRBASEMASK      = 0;
+		*CSR_CSRBASEOFFSET    = 0;
+		*CSR_PCIADDR_EXTN     = 0;
 
 #ifdef CONFIG_HOST_FOOTBRIDGE
-	/*
-	 * Against my better judgement, Philip Blundell still seems
-	 * to be saying that we should initialise the PCI stuff here
-	 * when the PCI_CFN bit is not set, dispite my comment below,
-	 * which he decided to remove.  If it is not set, then
-	 * the card is in add-in mode, and we're in a machine where
-	 * the bus is set up by 'others'.
-	 *
-	 * We should therefore not mess about with the mapping in
-	 * anyway, and we should not be using the virt_to_bus functions
-	 * that exist in the HOST architecture mode (since they assume
-	 * a fixed mapping).
-	 *
-	 * Instead, you should be using ADDIN mode, which allows for
-	 * this situation.  This does assume that you have correctly
-	 * initialised the PCI bus, which you must have done to get
-	 * your PC booted.
-	 *
-	 * Unfortunately, he seems to be blind to this.  I guess he'll
-	 * also remove all this.
-	 *
-	 * And THIS COMMENT STAYS, even if this gets patched, thank
-	 * you.
-	 */
-
-	/*
-	 * Map our SDRAM at a known address in PCI space, just in case
-	 * the firmware had other ideas.  Using a nonzero base is
-	 * necessary, since some VGA cards forcefully use PCI addresses
-	 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
-	 *
-	 * NOTE! If you need to chec the PCI_CFN bit in the SA110
-	 * control register then you've configured the kernel wrong.
-	 * If you're not using host mode, then DO NOT set
-	 * CONFIG_HOST_FOOTBRIDGE, but use CONFIG_ADDIN_FOOTBRIDGE
-	 * instead.  In this case, you MUST supply some firmware
-	 * to allow your PC to boot, plus we should not modify the
-	 * mappings that the PC BIOS has set up for us.
-	 */
-	*CSR_PCICACHELINESIZE = 0x00002008;
-	*CSR_PCICSRBASE       = 0;
-	*CSR_PCICSRIOBASE     = 0;
-	*CSR_PCISDRAMBASE     = virt_to_bus((void *)PAGE_OFFSET);
-	*CSR_PCIROMBASE       = 0;
-	*CSR_PCICMD           = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-				PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
-				PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
-				(1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
+		/*
+		 * Map our SDRAM at a known address in PCI space, just in case
+		 * the firmware had other ideas.  Using a nonzero base is
+		 * necessary, since some VGA cards forcefully use PCI addresses
+		 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
+		 */
+		*CSR_PCICACHELINESIZE = 0x00002008;
+		*CSR_PCICSRBASE       = 0;
+		*CSR_PCICSRIOBASE     = 0;
+		*CSR_PCISDRAMBASE     = virt_to_bus((void *)PAGE_OFFSET);
+		*CSR_PCIROMBASE       = 0;
+		*CSR_PCICMD           = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+					PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
+					PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
+					(1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
 #endif
 
-	/*
-	 * Clear any existing errors - we aren't
-	 * interested in historical data...
-	 */
-	cntl = *CSR_SA110_CNTL & 0xffffde07;
-	*CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
-
-	pcibios_init_ebsa285();
+		printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n",
+			*CSR_CLASSREV & 0xff);
 
-	printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff);
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
+		switch (machine_arch_type) {
+		case MACH_TYPE_EBSA285:
+			pci_irq_fixup = ebsa_irqval;
+			break;
+
+		case MACH_TYPE_CATS:
+			pci_irq_fixup = cats_irqval;
+			break;
+
+		case MACH_TYPE_NETWINDER:
+			pci_irq_fixup = netwinder_irqval;
+			break;
+		}
+
+		return &dc21285_ops;
+	} else {
+		/*
+		 * Clear any existing errors - we aren't
+		 * interested in historical data...
+		 */
+		cntl = *CSR_SA110_CNTL & 0xffffde07;
+		*CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
+		cntl = *CSR_PCICMD & 0x0000ffff;
+		*CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24;
+
+		/*
+		 * Initialise PCI error IRQ after we've finished probing
+		 */
+		setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action);
 
-char * __init pcibios_setup(char *str)
-{
-	return str;
+		return NULL;
+	}
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c
--- v2.3.22/linux/arch/arm/kernel/dma-dummy.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/arm/kernel/dma-dummy.c	Wed Oct 20 16:29:08 1999
@@ -17,15 +17,18 @@
 	return -EINVAL;
 }
 
-void free_dma(int channel)
-{
-}
-
-int get_dma_list(char *buf)
+int no_dma(void)
 {
 	return 0;
 }
 
-void __init init_dma(void)
-{
-}
+#define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a)
+GLOBAL_ALIAS(disable_dma, no_dma);
+GLOBAL_ALIAS(enable_dma, no_dma);
+GLOBAL_ALIAS(free_dma, no_dma);
+GLOBAL_ALIAS(get_dma_residue, no_dma);
+GLOBAL_ALIAS(get_dma_list, no_dma);
+GLOBAL_ALIAS(set_dma_mode, no_dma);
+GLOBAL_ALIAS(set_dma_count, no_dma);
+GLOBAL_ALIAS(set_dma_addr, no_dma);
+GLOBAL_ALIAS(init_dma, no_dma);
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-footbridge.c linux/arch/arm/kernel/dma-footbridge.c
--- v2.3.22/linux/arch/arm/kernel/dma-footbridge.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/dma-footbridge.c	Wed Oct 20 16:29:08 1999
@@ -13,14 +13,11 @@
 
 #include <linux/config.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/mman.h>
+#include <linux/errno.h>
 #include <linux/init.h>
 
-#include <asm/page.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/hardware.h>
 
 #include "dma.h"
 #include "dma-isa.h"
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-isa.c linux/arch/arm/kernel/dma-isa.c
--- v2.3.22/linux/arch/arm/kernel/dma-isa.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/dma-isa.c	Wed Oct 20 16:29:08 1999
@@ -126,6 +126,13 @@
 	outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]);
 }
 
+static struct resource dma_resources[] = {
+	{ "dma1",		0x0000, 0x000f },
+	{ "dma low page", 	0x0080, 0x008f },
+	{ "dma2",		0x00c0, 0x00df },
+	{ "dma high page",	0x0480, 0x048f }
+};
+
 int __init isa_init_dma(void)
 {
 	int dmac_found;
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c
--- v2.3.22/linux/arch/arm/kernel/dma-rpc.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/dma-rpc.c	Wed Oct 20 16:29:08 1999
@@ -357,6 +357,8 @@
 	}
 
 	outb(tcr, IOMD_DMATCR);
+
+	return speed;
 }
 
 void __init arch_dma_init(dma_t *dma)
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.3.22/linux/arch/arm/kernel/ecard.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/ecard.c	Wed Oct 20 16:29:08 1999
@@ -82,7 +82,7 @@
 /* List of descriptions of cards which don't have an extended
  * identification, or chunk directories containing a description.
  */
-static const struct expcard_blacklist __init blacklist[] = {
+static struct expcard_blacklist __initdata blacklist[] = {
 	{ MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
 };
 
@@ -827,6 +827,8 @@
 			ectcr |= 1 << slot;
 		break;
 #endif
+	default:
+		break;
 	}
 
 #ifdef IOMD_ECTCR
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.3.22/linux/arch/arm/kernel/entry-armv.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/entry-armv.S	Wed Oct 20 16:29:08 1999
@@ -298,6 +298,30 @@
 
 		.macro	irq_prio_table
 		.endm
+
+#elif defined(CONFIG_ARCH_SA1100)
+
+		.macro	disable_fiq
+		.endm
+
+		.macro	get_irqnr_and_base, irqnr, irqstat, base
+		mov	r4, #0xfa000000			@ ICIP = 0xfa050000
+		add	r4, r4, #0x00050000
+		ldr	\irqstat, [r4]			@ get irqs
+		ldr	\irqnr, [r4, #4]		@ ICMR = 0xfa050004
+		ands	\irqstat, \irqstat, \irqnr
+		mov	\irqnr, #0
+		beq	1002f
+1001:		tst	\irqstat, #1
+		addeq	\irqnr, \irqnr, #1
+		moveq	\irqstat, \irqstat, lsr #1
+		beq	1001b
+1002:
+		.endm
+
+		.macro	irq_prio_table
+		.endm
+
 #else
 #error Unknown architecture
 #endif
@@ -449,11 +473,15 @@
 		add	r5, sp, #S_SP
 		mov	r1, lr
 		stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+
+		mrs	r9, cpsr			@ Enable interrupts if they were
 		tst	r3, #I_BIT
-		mrseq	r0, cpsr			@ Enable interrupts if they were
-		biceq	r0, r0, #I_BIT			@ previously
-		msreq	cpsr, r0
+		biceq	r9, r9, #I_BIT			@ previously
+
 		mov	r0, r2
+/*
+ * This routine must not corrupt r9
+ */
 #ifdef MULTI_CPU
 		ldr	r2, .LCprocfns
 		mov	lr, pc
@@ -461,6 +489,7 @@
 #else
 		bl	cpu_data_abort
 #endif
+		msr	cpsr, r9
 		mov	r3, sp
 		bl	SYMBOL_NAME(do_DataAbort)
 		ldr	r0, [sp, #S_PSR]
@@ -544,9 +573,6 @@
 #endif
 
 		mov	fp, #0
-		mrs	r2, cpsr			@ Enable interrupts if they were
-		bic	r2, r2, #I_BIT			@ previously
-		msr	cpsr, r2
 #ifdef MULTI_CPU
 		ldr	r2, .LCprocfns
 		mov	lr, pc
@@ -554,6 +580,10 @@
 #else
 		bl	cpu_data_abort
 #endif
+		mrs	r3, cpsr			@ Enable interrupts if they were
+		bic	r3, r3, #I_BIT			@ previously
+		msr	cpsr, r3
+
 		mov	r3, sp
 		adrsvc	al, lr, ret_from_sys_call
 		b	SYMBOL_NAME(do_DataAbort)
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S
--- v2.3.22/linux/arch/arm/kernel/head-armo.S	Thu Dec 17 09:05:42 1998
+++ linux/arch/arm/kernel/head-armo.S	Wed Oct 20 16:29:08 1999
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/kernel/head.S
+ * linux/arch/arm/kernel/head-armo.S
  *
  * Copyright (C) 1994, 1995, 1996, 1997 Russell King
  *
@@ -7,11 +7,13 @@
  */
 #include <linux/linkage.h>
 
-		.text
-		.align
+		.globl	SYMBOL_NAME(swapper_pg_dir)
+		.equ	SYMBOL_NAME(swapper_pg_dir),	0x0207d000
+
 /*
  * Entry point.
  */
+		.section ".text.init",#alloc,#execinstr
 ENTRY(stext)
 ENTRY(_stext)
 __entry:	cmp	pc, #0x02000000
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.3.22/linux/arch/arm/kernel/head-armv.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/head-armv.S	Wed Oct 20 16:29:08 1999
@@ -1,54 +1,60 @@
 /*
- * linux/arch/arm/kernel/head32.S
+ * linux/arch/arm/kernel/head-armv.S
  *
- * Copyright (C) 1994-1998 Russell King
+ * Copyright (C) 1994-1999 Russell King
  *
- * Kernel 32 bit startup code for ARM6 / ARM7 / StrongARM
+ * 32-bit kernel startup code for all architectures
  */
 #include <linux/config.h>
 #include <linux/linkage.h>
+
+#include <asm/assembler.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 
+#if (TEXTADDR & 0xffff) != 0x8000
+#error TEXTADDR must start at 0xXXXX8000
+#endif
+
+#define SWAPPER_PGDIR_OFFSET	0x4000
+
 		.globl	SYMBOL_NAME(swapper_pg_dir)
-		.equ	SYMBOL_NAME(swapper_pg_dir),	TEXTADDR - 0x4000
+		.equ	SYMBOL_NAME(swapper_pg_dir),	TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET
 
 		.section ".text.init",#alloc,#execinstr
 ENTRY(stext)
 ENTRY(_stext)
 
-#if (TEXTADDR & 0xffff) != 0x8000
-#error TEXTADDR must start at 0xXXXX8000
-#endif
-
 #ifdef CONFIG_ARCH_NETWINDER
+/*
+ * Compatability cruft for old NetWinder NeTTroms.  This
+ * code is currently scheduled for destruction in 2.5.xx
+ */
+		.rept	8
 		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
-		mov	r0, r0
+		.endr
 
 		adr	r2, 1f
 		ldmdb	r2, {r7, r8}
-		and	r3, r2, #0x0000c000
-		teq	r3, #0x00008000
+		and	r3, r2, #0xc000
+		teq	r3, #0x8000
 		beq	__entry
 		bic	r3, r2, #0xc000
 		orr	r3, r3, #0x8000
 		mov	r0, r3
-		mov	r4, #32
+		mov	r4, #64
 		sub	r5, r8, r7
 		b	1f
 
 		.word	_stext
-		.word	_end
+		.word	__bss_start
 
-1:		ldmia	r2!, {r6, r7, r8, r9}
+1:
+		.rept	4
+		ldmia	r2!, {r6, r7, r8, r9}
 		stmia	r3!, {r6, r7, r8, r9}
-		subs	r4, r4, #16
+		.endr
+		subs	r4, r4, #64
 		bcs	1b
 		movs	r4, r5
 		mov	r5, #0
@@ -59,78 +65,114 @@
 #endif
 
 /*
- * Entry point and restart point.  Entry *must* be called with r0 == 0,
- * MMU off.  Note! These should be unique!!! Please read Documentation/ARM-README
- * for more information.
- *
- *  r1 = 0 -> DEC EBSA-110
- *  r1 = 1 -> Acorn RiscPC
- *  r1 = 2 -> ebsit
- *  r1 = 3 -> nexuspci
- *  r1 = 4 -> DEC EBSA-285
- *  r1 = 5 -> Corel Netwinder
- *  r1 = 6 -> CATS
- *  r1 = 7 -> tbox
- *  r1 = 8 -> SA110/21285 as co-processor
- *  r1 = 9 -> CL-PS7110 system
- *  r1 = 12 -> SA1100 based system
- */
+ * Entry point.  Entry *must* be called with r0 == 0, with the MMU off.
+ *  r1 contains the unique architecture number.  See
+ * linux/arch/arm/kernel/setup.c machine_desc[] array for the complete
+ * list.  If you require a new number, please follow the instructions
+ * given in Documentation/ARM-README.
+ */
+__entry:	teq	r0, #0
+		movne	r0, #'i'
+		bne	__error
+		bl	__lookup_processor_type
+		teq	r10, #0				@ invalid processor?
+		moveq	r0, #'p'
+		beq	__error
+		bl	__lookup_architecture_type
+		teq	r7, #0				@ invalid architecture?
+		moveq	r0, #'a'
+		beq	__error
+		bl	__create_page_tables
+		adr	lr, __aligned_call
+		add	pc, r10, #12			@ flush caches (returns ctrl reg)
+
+__switch_data:	.long	__mmap_switched
+		.long	SYMBOL_NAME(__bss_start)
+		.long	SYMBOL_NAME(_end)
+		.long	SYMBOL_NAME(processor_id)
+		.long	SYMBOL_NAME(__machine_arch_type)
+		.long	SYMBOL_NAME(cr_alignment)
+		.long	SYMBOL_NAME(init_task_union)+8192
+
+		/*
+		 * This needs to be aligned to a cache line.
+		 */
+		.align	5
+__aligned_call:
+		ldr	lr, __switch_data
+#ifdef CONFIG_ALIGNMENT_TRAP
+		orr	r0, r0, #2			@ ...........A.
+#endif
+		mcr	p15, 0, r0, c1, c0
+		mov	pc, lr
+
+		/*
+		 * This code follows on after the page
+		 * table switch and jump above.
+		 *
+		 * r0  = processor control register
+		 * r1  = machine ID
+		 * r9  = processor ID
+		 */
+		.align	5
+__mmap_switched:
+		adr	r3, __switch_data + 4
+		ldmia	r3, {r4, r5, r6, r7, r8, sp}	@ Setup stack
+
+		mov	fp, #0				@ Clear BSS
+1:		cmp	r4, r5
+		strcc	fp, [r4],#4
+		bcc	1b
+
+		str	r9, [r6]			@ Save processor ID
+		str	r1, [r7]			@ Save machine type
+		bic	r2, r0, #2			@ Clear 'A' bit
+		stmia	r8, {r0, r2}			@ Save control register values
+		b	SYMBOL_NAME(start_kernel)
+
 
-__entry:	teq	r0, #0					@ check for illegal entry...
-		bne	.Lerror					@ loop indefinitely
-		cmp	r1, #9					@ Unknown machine architecture
-		bge	.Lerror
-/* First thing to do is to get the page tables set up so that we can call
- * the kernel in the correct place.  This is relocatable code...
- * - Read processor ID register (CP#15, CR0).
- */
-		mrc	p15, 0, r9, c0, c0			@ get Processor ID
-/* Values are:
- *		XX01XXXX = ARMv4 architecture (StrongARM)
- *		XX00XXXX = ARMv3 architecture
- *		4156061X = ARM 610
- */
-		adr	r10, .LCProcTypes
-1:		ldmia	r10!, {r5, r6, r8}			@ Get Set, Mask, MMU Flags
-		teq	r5, #0					@ End of list?
-		beq	.Lerror
-		eor	r5, r5, r9
-		tst	r5, r6
-		addne	r10, r10, #8
-		bne	1b
 
-		adr	r4, .LCMachTypes
-		add	r4, r4, r1, lsl #4
-		ldmia	r4, {r4, r5, r6, r7}
 /*
- * r4 = page dir in physical ram
+ * Setup the initial page tables.  We only setup the barest
+ * amount which are required to get the kernel running, which
+ * generally means mapping in the kernel code.
+ *
+ * We only map in 2MB of RAM, which should be sufficient in
+ * all cases.
+ *
+ * r4 = physical address of page tables
  * r5 = physical address of start of RAM
- * r6 = I/O address
+ * r6 = physical IO address
+ * r7 = byte offset into page tables for IO
+ * r8 = page table flags
  */
+__create_page_tables:
 		mov	r0, r4
 		mov	r3, #0
-		add	r2, r0, #0x4000
-1:		str	r3, [r0], #4				@ Clear page table
+		add	r2, r0, #0x4000			@ Clear page table
+1:		str	r3, [r0], #4
+		str	r3, [r0], #4
+		str	r3, [r0], #4
+		str	r3, [r0], #4
 		teq	r0, r2
 		bne	1b
-/*
- * Add enough entries to allow the kernel to be called.
- * It will sort out the real mapping in paging_init.
- * We map in 2MB of memory into (TEXTADDR-0x8000) + 2MB
- */
+		/*
+		 * map in two sections (2MB) for kernel.
+		 * these are marked cacheable and bufferable.
+		 */
 		add	r0, r4, #(TEXTADDR - 0x8000) >> 18
-		mov	r3, #0x0000000c				@ SECT_CACHEABLE | SECT_BUFFERABLE
+		mov	r3, #0x0c
 		orr	r3, r3, r8
 		add	r3, r3, r5
 		str	r3, [r0], #4
 		add	r3, r3, #1 << 20
 		str	r3, [r0], #4
-		add	r3, r3, #1 << 20
 #ifdef CONFIG_DEBUG_LL
-/* Map in IO space
- * This allows debug messages to be output via a serial
- * before/while paging_init.
- */
+		/*
+		 * Map in IO space for serial debugging.
+		 * This allows debug messages to be output
+		 * via a serial before paging_init.
+		 */
 		add	r0, r4, r7
 		orr	r3, r6, r8
 		add	r2, r0, #0x0800
@@ -147,45 +189,39 @@
 		str	r3, [r0], #4
 		add	r3, r3, #1 << 20
 		str	r3, [r0], #4
-1:
 #endif
 #endif
 #ifdef CONFIG_ARCH_RPC
-/* Map in screen at 0x02000000 & SCREEN2_BASE
- * Similar reasons here - for debug, and when things go
- * wrong to a certain extent.  This is of limited use to
- * non-Acorn RiscPC architectures though.
- */
+		/*
+		 * Map in screen at 0x02000000 & SCREEN2_BASE
+		 * Similar reasons here - for debug.  This is
+		 * only for Acorn RiscPC architectures.
+		 */
 		teq	r5, #0
-		addne	r0, r4, #0x80				@ 02000000
+		addne	r0, r4, #0x80			@ 02000000
 		movne	r3, #0x02000000
 		orrne	r3, r3, r8
 		strne	r3, [r0]
-		addne	r0, r4, #0x3600				@ d8000000
+		addne	r0, r4, #0x3600			@ d8000000
 		strne	r3, [r0]
 #endif
-		b	aligned_call
-/*
- * The following should work on both v3 and v4 implementations
- * Note: it seems that if the mov pc,lr is on the next cache
- * line, it doesn't get fetched before the MMU starts
- * translating, which prevents the kernel from booting.
- * Ensure that this never happens.
- */
-		.align 5
-aligned_call:
-		mov	lr, pc
-		mov	pc, r10					@ Call processor flush (returns ctrl reg)
-		adr	r5, __entry
-		sub	r10, r10, r5				@ Make r10 PIC
-		ldr	lr, .Lbranch
-		mcr	p15, 0, r0, c1, c0			@ Enable MMU & caches.  In 3 instructions
-								@ we lose this page!
 		mov	pc, lr
 
-.Lerror:
+
+
+/*
+ * Exception handling.  Something went wrong and we can't
+ * proceed.  We ought to tell the user, but since we
+ * don't have any guarantee that we're even running on
+ * the right architecture, we do virtually nothing.
+ * r0 = ascii error character
+ *
+ * Generally, only serious errors cause this.
+ */
+__error:
 #ifdef CONFIG_ARCH_RPC
-/* Turn the screen red on a error - RiscPC only.
+/*
+ * Turn the screen red on a error - RiscPC only.
  */
 		mov	r0, #0x02000000
 		mov	r3, #0x11
@@ -199,356 +235,171 @@
 1:		mov	r0, r0
 		b	1b
 
-.Lbranch:	.long	.Lalready_done_mmap			@ Real address of routine
-
-		@ DEC EBSA110 (pg dir phys, phys ram start, phys i/o)
-.LCMachTypes:	.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000	@ Address of page tables (physical)
-		.long	0					@ Address of RAM
-		.long	0xe0000000				@ I/O address
-		.long	0x3800
-
-		@ Acorn RiscPC
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x10000000
-		.long	0x10000000
-		.long	0x03000000
-		.long	0x3800
-
-		@ EBSIT ???
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000
-		.long	0
-		.long	0xe0000000
-		.long	0x3800
-
-		@ NexusPCI
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x40000000
-		.long	0x40000000
-		.long	0x10000000
-		.long	0x3800
-
-		@ DEC EBSA285
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
-		.long	0					@ Address of RAM
-		.long	0x24000000				@ I/O base address (0x42000000 -> 0xFE000000)
-		.long	0x3800
-
-		@ Corel VNC
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
-		.long	0					@ Address of RAM
-		.long	0x24000000				@ I/O base address (0x42000000 -> 0xfe000000)
-		.long	0x3800
-
-		@ CATS
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
-		.long	0					@ Address of RAM
-		.long	0x24000000				@ I/O base address (0x42000000 -> 0xfe000000)
-		.long	0x3800
-
-		@ tbox
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x80000000
-		.long	0x80000000				@ Address of RAM
-		.long	0x00400000				@ Uart
-		.long	0x3800
-
-		@ DEC EBSA285 as co-processor
-		.long	0x4000					@ Address of page tables (physical)
-		.long	0					@ Address of RAM
-		.long	DC21285_ARMCSR_BASE			@ Physical I/O base address
-		.long	0x7cf00000 >> 18			@ Virtual I/O base address
 
-		@ SA1100
-		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0xc0000000
-		.long	0xc0000000
-		.long	0x80000000				@ IO mapping will change when kernel gets on its feet
-		.long	0x3800
 
-.LCProcTypes:	@ ARM6 / 610
-		.long	0x41560600
-		.long	0xffffff00
-		.long	0x00000c12
-		b	.Larmv3_flush_early			@ arm v3 flush & ctrl early setup
+/*
+ * Read processor ID register (CP#15, CR0), and determine
+ * processor type.
+ *
+ * Returns:
+ *	r5, r6, r7 corrupted
+ *	r8  = page table flags
+ *	r9  = processor ID
+ *	r10 = pointer to processor structure
+ */
+__lookup_processor_type:
+		adr	r5, 2f
+		ldmia	r5, {r7, r9, r10}
+		sub	r5, r5, r9
+		add	r7, r7, r5
+		add	r10, r10, r5
+		mrc	p15, 0, r9, c0, c0		@ get processor id
+1:		ldmia	r10, {r5, r6, r8}		@ value, mask, mmuflags
+		eor	r5, r5, r9
+		tst	r5, r6
+		moveq	pc, lr
+		add	r10, r10, #36			@ sizeof(proc_info_list)
+		cmp	r10, r7
+		blt	1b
+		mov	r10, #0
 		mov	pc, lr
 
-		@ ARM7
-		.long	0x41007000
-		.long	0xfffff000
-		.long	0x00000c12
-		b	.Larmv3_flush_late			@ arm v3 flush & ctrl late setup
-		mov	pc, lr
+2:		.long	__proc_info_end
+		.long	2b
+		.long	__proc_info_begin
 
-		@ ARM710
-		.long	0x41007000
-		.long	0xfff8f000				@ arm710 processors are weird
-		.long	0x00000c12
-		b	.Larmv3_flush_late			@ arm v3 flush & ctrl late setup
+/*
+ * Lookup machine architecture
+ * r1 = machine architecture number
+ * Returns:
+ *  r4 = physical address of page tables
+ *  r5 = physical start address of RAM
+ *  r6 = physical address of IO
+ *  r7 = byte offset into page tables for IO
+ */
+__lookup_architecture_type:
+		cmp	r1, #(__arch_types_end - __arch_types_start) / 16
+		bge	1f
+		adr	r4, __arch_types_start
+		add	r4, r4, r1, lsl #4
+		ldmia	r4, {r4, r5, r6, r7}
+		add	r4, r5, #SWAPPER_PGDIR_OFFSET
+		mov	r7, r7, lsr #18
 		mov	pc, lr
-
-		@ StrongARM-110 and StrongARM-1100
-		.long	0x4401a100				@ 4401a100 and 4401a110
-		.long	0xffffffe0
-		.long	0x00000c02
-		b	.Larmv4_flush_early
-		b	.Lsa_fastclock
-
-		.long	0
-		.align
-
-.Larmv3_flush_early:
-		mov	r0, #0
-		mcr	p15, 0, r0, c7, c0			@ flush caches on v3
-		mcr	p15, 0, r0, c5, c0			@ flush TLBs on v3
-		mcr	p15, 0, r4, c2, c0			@ load page table pointer
-		mov	r0, #0x1f				@ Domains 0, 1 = client
-		mcr	p15, 0, r0, c3, c0			@ load domain access register
-#ifdef CONFIG_ALIGNMENT_TRAP
-		mov	r0, #0x3f				@ ....S..DPWCAM
-#else
-		mov	r0, #0x3d				@ ....S..DPWC.M
-#endif
-		orr	r0, r0, #0x100
+1:		mov	r7, #0
 		mov	pc, lr
 
-.Larmv3_flush_late:
-		mov	r0, #0
-		mcr	p15, 0, r0, c7, c0			@ flush caches on v3
-		mcr	p15, 0, r0, c5, c0			@ flush TLBs on v3
-		mcr	p15, 0, r4, c2, c0			@ load page table pointer
-		mov	r0, #0x1f				@ Domains 0, 1 = client
-		mcr	p15, 0, r0, c3, c0			@ load domain access register
-#ifdef CONFIG_ALIGNMENT_TRAP
-		mov	r0, #0x7f				@ ....S.LDPWCAM
-#else
-		mov	r0, #0x7d				@ ....S.LDPWC.M
-#endif
-		orr	r0, r0, #0x100
-		mov	pc, lr
+/*
+ * Machine parameters.  Each machine requires 4 words, which are:
+ *
+ * word0: unused
+ * word1: physical start address of RAM
+ * word2: physical start address of IO
+ * word3: virtual start address of IO
+ *
+ * The IO mappings entered here are used to set up mappings
+ * required for debugging information to be shown to the user.
+ * paging_init() does the real page table initialisation.
+ */
+		@ 0x00 - DEC EBSA110
+__arch_types_start:
+		.long	0
+		.long	0
+		.long	0xe0000000
+		.long	0xe0000000
 
-.Larmv4_flush_early:
-		mov	r0, #0
-		mcr	p15, 0, r0, c7, c7			@ flush I,D caches on v4
-		mcr	p15, 0, r0, c7, c10, 4			@ drain write buffer on v4
-		mcr	p15, 0, r0, c8, c7			@ flush I,D TLBs on v4
-		mcr	p15, 0, r4, c2, c0			@ load page table pointer
-		mov	r0, #0x1f				@ Domains 0, 1 = client
-		mcr	p15, 0, r0, c3, c0			@ load domain access register
-		mrc	p15, 0, r0, c1, c0			@ get control register v4
-		bic	r0, r0, #0x0e00
-		bic	r0, r0, #0x0002
-#ifdef CONFIG_ALIGNMENT_TRAP
-		orr	r0, r0, #0x003f				@ I...S..DPWCAM
-#else
-		orr	r0, r0, #0x003d				@ I...S..DPWC.M
-#endif
-		orr	r0, r0, #0x1100				@ v4 supports separate I cache
-		mov	pc, lr
+		@ 0x01 - Acorn RiscPC
+		.long	0
+		.long	0x10000000
+		.long	0x03000000
+		.long	0xe0000000
 
-.Lsa_fastclock:	mcr	p15, 0, r4, c15, c1, 2			@ Enable clock switching
-		mov	pc, lr
+		@ 0x02 - Unused
+		.long	0
+		.long	0
+		.long	0xe0000000
+		.long	0xe0000000
 
-.LC0:		.long	SYMBOL_NAME(__entry)
-		.long	SYMBOL_NAME(__machine_arch_type)
-		.long	SYMBOL_NAME(__bss_start)
-		.long	SYMBOL_NAME(processor_id)
-		.long	SYMBOL_NAME(_end)
-		.long	SYMBOL_NAME(cr_alignment)
-		.long	SYMBOL_NAME(init_task_union)+8192
-		.align
+		@ 0x03 - NexusPCI
+		.long	0
+		.long	0x40000000
+		.long	0x10000000
+		.long	0xe0000000
 
-.Lalready_done_mmap:
-		adr	r4, .LC0
-		ldmia	r4, {r3, r4, r5, r6, r7, r8, sp}	@ Setup stack
-		add	r10, r10, r3				@ Add base back in
-		mov	fp, #0
-1:		cmp	r5, r7					@ Clear BSS
-		strcc	fp, [r5],#4
-		bcc	1b
+		@ 0x04 - DEC EBSA285
+		.long	0
+		.long	0
+		.long	0x24000000			@ I/O base address (0x42000000 -> 0xfe000000)
+		.long	0xe0000000
 
-		bic	r2, r0, #2				@ Clear 'A' bit
-		stmia	r8, {r0, r2}				@ Save control register values
+		@ 0x05 - Rebel.com NetWinder
+		.long	0
+		.long	0
+		.long	0x24000000			@ I/O base address (0x42000000 -> 0xfe000000)
+		.long	0xe0000000
 
-		str	r1, [r4]				@ Save machine type
-		str	r9, [r6]				@ Save processor ID
-		mov	lr, pc
-		add	pc, r10, #4				@ Call post-processor init
-		mov	fp, #0
-		b	SYMBOL_NAME(start_kernel)
+		@ 0x06 - CATS
+		.long	0
+		.long	0
+		.long	0x24000000			@ I/O base address (0x42000000 -> 0xfe000000)
+		.long	0xe0000000
 
-		.text
+		@ 0x07 - tbox
+		.long	0
+		.long	0x80000000
+		.long	0x00400000			@ Uart
+		.long	0xe0000000
 
-#ifdef CONFIG_DEBUG_LL
-/*
- * Some debugging routines (useful if you've got MM problems and
- * printk isn't working).  For DEBUGGING ONLY!!!  Do not leave
- * references to these in a production kernel!
- */
-#if defined(CONFIG_ARCH_RPC)
-		.macro	addruart,rx
-		mov	\rx, #0xe0000000
-		orr	\rx, \rx, #0x00010000
-		orr	\rx, \rx, #0x00000fe0
-		.endm
-
-		.macro	senduart,rd,rx
-		strb	\rd, [\rx]
-		.endm
-
-		.macro	busyuart,rd,rx
-1002:		ldrb	\rd, [\rx, #0x14]
-		and	\rd, \rd, #0x60
-		teq	\rd, #0x60
-		bne	1002b
-		.endm
-
-		.macro	waituart,rd,rx
-1001:		ldrb	\rd, [\rx, #0x18]
-		tst	\rd, #0x10
-		beq	1001b
-		.endm
-
-#elif defined(CONFIG_ARCH_EBSA110)
-		.macro	addruart,rx
-		mov	\rx, #0xf0000000
-		orr	\rx, \rx, #0x00000be0
-		.endm
-
-		.macro	senduart,rd,rx
-		strb	\rd, [\rx]
-		.endm
-
-		.macro	busyuart,rd,rx
-1002:		ldrb	\rd, [\rx, #0x14]
-		and	\rd, \rd, #0x60
-		teq	\rd, #0x60
-		bne	1002b
-		.endm
-
-		.macro	waituart,rd,rx
-1001:		ldrb	\rd, [\rx, #0x18]
-		tst	\rd, #0x10
-		beq	1001b
-		.endm
-
-#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
-#ifndef CONFIG_DEBUG_DC21285_PORT
-	/* For NetWinder debugging */
-		.macro	addruart,rx
-		mov	\rx, #0xff000000
-		orr	\rx, \rx, #0x000003f8
-		.endm
-
-		.macro	senduart,rd,rx
-		strb	\rd, [\rx]
-		.endm
-
-		.macro	busyuart,rd,rx
-1002:		ldrb	\rd, [\rx, #0x5]
-		and	\rd, \rd, #0x60
-		teq	\rd, #0x60
-		bne	1002b
-		.endm
-
-		.macro	waituart,rd,rx
-1001:		ldrb	\rd, [\rx, #0x6]
-		tst	\rd, #0x10
-		beq	1001b
-		.endm
-#else
-	/* For EBSA285 debugging */
-		.equ	dc21285_high, ARMCSR_BASE & 0xff000000
-		.equ	dc21285_low,  ARMCSR_BASE & 0x00ffffff
-
-		.macro	addruart,rx
-		mov	\rx, #dc21285_high
-		.if	dc21285_low
-		orr	\rx, \rx, #dc21285_low
-		.endif
-		.endm
-
-		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0x160]	@ UARTDR
-		.endm
-
-		.macro	busyuart,rd,rx
-1001:		ldr	\rd, [\rx, #0x178]	@ UARTFLG
-		tst	\rd, #1 << 3
-		bne	1001b
-		.endm
+		@ 0x08 - DEC EBSA285 as co-processor
+		.long	0
+		.long	0
+		.long	DC21285_ARMCSR_BASE		@ Physical I/O base address
+		.long	0x7cf00000			@ Virtual I/O base address
 
-		.macro	waituart,rd,rx
-		.endm
-#endif
-#elif defined(CONFIG_ARCH_NEXUSPCI)
-		.macro	addruart,rx
-		ldr	\rx, =0xfff00000
-		.endm
-
-		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0xc]
-		.endm
-
-		.macro	busyuart,rd,rx
-1001:		ldr	\rd, [\rx, #0x4]
-		tst	\rd, #1 << 0
-		bne	1001b
-		.endm
-
-		.macro	waituart,rd,rx
-		.endm
-#else
-#error Unknown architecture
-#endif
+		@ 0x09 - CL-PS7110
+		.long	0
+		.long	0
+		.long	0
+		.long	0
 
-/*
- * Useful debugging routines
- */
-ENTRY(printhex8)
-		mov	r1, #8
-		b	printhex
-
-ENTRY(printhex4)
-		mov	r1, #4
-		b	printhex
-
-ENTRY(printhex2)
-		mov	r1, #2
-printhex:	ldr	r2, =hexbuf
-		add	r3, r2, r1
-		mov	r1, #0
-		strb	r1, [r3]
-1:		and	r1, r0, #15
-		mov	r0, r0, lsr #4
-		cmp	r1, #10
-		addlt	r1, r1, #'0'
-		addge	r1, r1, #'a' - 10
-		strb	r1, [r3, #-1]!
-		teq	r3, r2
-		bne	1b
-		mov	r0, r2
-		b	printascii
+		@ 0x0a - Acorn Archimedes
+		.long	0
+		.long	0
+		.long	0
+		.long	0
 
-		.ltorg
+		@ 0x0b - Acorn A5000
+		.long	0
+		.long	0
+		.long	0
+		.long	0
 
-ENTRY(printascii)
-		addruart r3
-		b	2f
-1:		waituart r2, r3
-		senduart r1, r3
-		busyuart r2, r3
-		teq	r1, #'\n'
-		moveq	r1, #'\r'
-		beq	1b
-2:		teq	r0, #0
-		ldrneb	r1, [r0], #1
-		teqne	r1, #0
-		bne	1b
-		mov	pc, lr
+		@ 0x0c - Etoile
+		.long	0
+		.long	0
+		.long	0
+		.long	0
 
-ENTRY(printch)
-		addruart r3
-		mov	r1, r0
-		mov	r0, #0
-		b	1b
+		@ 0x0d - LaCie_NAS
+		.long	0
+		.long	0
+		.long	0
+		.long	0
 
-		.bss
-hexbuf:		.space 16
+		@ 0x0e - CL-PS7500
+		.long	0
+		.long	0
+		.long	0
+		.long	0
 
-#endif
+		@ 0x0f - Shark
+		.long	0
+		.long	0
+		.long	0
+		.long	0
+__arch_types_end:
+		@ unknown - SA1100
+		.long	0
+		.long	0xc0000000
+		.long	0x80000000
+		.long	0xe0000000
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c
--- v2.3.22/linux/arch/arm/kernel/hw-footbridge.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/hw-footbridge.c	Wed Oct 20 16:29:08 1999
@@ -25,269 +25,8 @@
 #include <asm/system.h>
 
 #define IRDA_IO_BASE		0x180
-#define ETHER10_IO_BASE		0x301
 #define GP1_IO_BASE		0x338
 #define GP2_IO_BASE		0x33a
-#define DEC21143_IO_BASE	0x401
-#define DEC21143_MEM_BASE	0x00800000
-#define CYBER2000_MEM_BASE	0x01000000
-
-int	have_isa_bridge;
-
-extern int setup_arm_irq(int, struct irqaction *);
-extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set);
-extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr);
-extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq);
-extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
-
-#ifdef CONFIG_PCI
-
-static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 };
-
-static int __init ebsa_irqval(struct pci_dev *dev)
-{
-	unsigned char pin;
-	
-	pcibios_read_config_byte(dev->bus->number,
-				 dev->devfn,
-				 PCI_INTERRUPT_PIN,
-				 &pin);
-	
-	return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
-}
-
-#ifdef CONFIG_CATS
-static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
-
-static int __init cats_irqval(struct pci_dev *dev)
-{
-	if (dev->irq >= 128)
-		return 16 + (dev->irq & 0x1f);
-
-	switch (dev->irq) {
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-		return irqmap_cats[dev->irq - 1];
-	case 0:
-		return 0;
-	}
-
-	printk("PCI: device %02x:%02x has unknown irq line %x\n",
-	       dev->bus->number, dev->devfn, dev->irq);
-	return 0;
-}
-#endif
-
-void __init pcibios_fixup_ebsa285(struct pci_dev *dev)
-{
-	/* Latency timer of 32 */
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32);
-
-	/* 32-byte cache line size */
-	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
-
-	/* Set SysErr enable, Parity enable */
-	pci_set_cmd(dev, 0, PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
-
-	/* If this device is an ISA bridge, set the
-	 * have_isa_bridge flag.  We will then go looking
-	 * for things like keyboard, etc
-	 */
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA ||
-	    (dev->class >> 8) == PCI_CLASS_BRIDGE_EISA)
-		have_isa_bridge = !0;
-
-	/* sort out the irq mapping for this device */
-	switch (machine_arch_type) {
-	case MACH_TYPE_EBSA285:
-		dev->irq = ebsa_irqval(dev);
-		/* Turn on bus mastering - boot loader doesn't
-		 * - perhaps it should! - dag
-		 */
-		pci_set_cmd(dev, 0, PCI_COMMAND_MASTER);
-		break;
-
-#ifdef CONFIG_CATS
-	case MACH_TYPE_CATS:
-		dev->irq = cats_irqval(dev);
-		/* Turn on bus mastering - boot loader doesn't
-		 * - perhaps it should! - dag
-		 */
-		pci_set_cmd(dev, 0, PCI_COMMAND_MASTER);
-		break;
-#endif
-#ifdef CONFIG_ARCH_NETWINDER
-	case MACH_TYPE_NETWINDER:
-		/* disable ROM */
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
-
-#define DEV(v,d) ((v)<<16|(d))
-		switch (DEV(dev->vendor, dev->device)) {
-		/* Ether 100 */
-		case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142):
-			pci_set_base_addr(dev, 0, DEC21143_IO_BASE);
-			pci_set_base_addr(dev, 1, DEC21143_MEM_BASE);
-			pci_set_cmd(dev, 0, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
-			/* Put the chip to sleep in case the driver isn't loaded */
-			pci_write_config_dword(dev, 0x40, 0x80000000);
-			dev->irq = IRQ_NETWINDER_ETHER100;
-			break;
-
-		/* Ether 10 */
-		case DEV(PCI_VENDOR_ID_WINBOND2,0x5a5a):
-			pci_set_base_addr(dev, 0, ETHER10_IO_BASE);
-			pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO);
-			dev->irq = IRQ_NETWINDER_ETHER10;
-			break;
-
-		/* ISA bridge */
-		case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_83C553):
-			pci_set_base_addr(dev, 0, 0);
-			pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO);
-			/*
-			 * Enable all memory requests from ISA to be channeled to PCI
-			 */
-			pci_write_config_byte(dev, 0x48, 255);
-			/*
-			 * Disable ping-pong (as per errata)
-			 */
-			pci_write_config_byte(dev, 0x42, 0);
-			/*
-			 * Enable PCI packet retry
-			 */
-			pci_write_config_byte(dev, 0x40, 0x22);
-			/*
-			 * Do not use PCI CPU park enable, park on
-			 * last master, disable GAT bit
-			 */
-			pci_write_config_byte(dev, 0x83, 0x02);
-			/*
-			 * Default rotating priorities
-			 */
-			pci_write_config_byte(dev, 0x80, 0xe0);
-			/*
-			 * Rotate bank 4
-			 */
-			pci_write_config_byte(dev, 0x81, 0x01);
-			break;
-
-		/* IDE */
-		case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_82C105):
-			pci_set_base_addr(dev, 0, 0x1f1);
-			pci_set_base_addr(dev, 1, 0x3f5);
-			pci_set_base_addr(dev, 2, 0x171);
-			pci_set_base_addr(dev, 3, 0x375);
-			pci_set_base_addr(dev, 4, 0xe801);
-			pci_set_cmd(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MASTER | PCI_COMMAND_IO);
-			dev->irq = IRQ_ISA_HARDDISK1;
-			break;
-
-		/* VGA */
-		case DEV(PCI_VENDOR_ID_INTERG,0x2000):
-			pci_set_base_addr(dev, 0, CYBER2000_MEM_BASE);
-			pci_set_cmd(dev, PCI_COMMAND_MASTER, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-			dev->irq = IRQ_NETWINDER_VGA;
-			break;
-		}
-#endif
-	}
-}
-
-static inline void
-report_pci_dev_error(void)
-{
-	struct pci_dev *dev;
-
-	for (dev = pci_devices; dev; dev = dev->next) {
-		unsigned short status;
-
-		pci_read_config_word(dev, PCI_STATUS, &status);
-		if (status & 0xf900) {
-			printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n",
-				dev->vendor, dev->device, status);
-
-			pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
-		}
-	}
-}
-#else
-#define report_pci_dev_error()
-#endif
-
-/*
- * Warn on PCI errors.  Please report any occurances!
- */
-static void
-irq_pci_err(int irq, void *dev_id, struct pt_regs *regs)
-{
-	static unsigned long next_warn;
-	unsigned long cmd       = *CSR_PCICMD & 0x0000ffff;
-	unsigned long ctrl      = (*CSR_SA110_CNTL) & 0xffffde07;
-	unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
-	int warn = time_after_eq(jiffies, next_warn);
-
-	ctrl |= SA110_CNTL_DISCARDTIMER;
-
-	if (warn) {
-		next_warn = jiffies + 3 * HZ / 100;
-		printk(KERN_DEBUG "PCI: ");
-	}
-
-	if (irqstatus & (1 << 31)) {
-		if (warn)
-			printk("parity error ");
-		cmd |= 1 << 31;
-	}
-
-	if (irqstatus & (1 << 30)) {
-		if (warn)
-			printk("target abort ");
-		cmd |= 1 << 28;
-	}
-
-	if (irqstatus & (1 << 29)) {
-		if (warn)
-			printk("master abort ");
-		cmd |= 1 << 29;
-	}
-
-	if (irqstatus & (1 << 28)) {
-		if (warn)
-			printk("data parity error ");
-		cmd |= 1 << 24;
-	}
-
-	if (irqstatus & (1 << 27)) {
-		if (warn)
-			printk("discard timer expired ");
-		ctrl &= ~SA110_CNTL_DISCARDTIMER;
-	}
-
-	if (irqstatus & (1 << 23)) {
-		if (warn)
-			printk("system error ");
-		ctrl |= SA110_CNTL_RXSERR;
-	}
-
-	if (warn)
-		printk("pc=[<%08lX>]\n", instruction_pointer(regs));
-
-	report_pci_dev_error();
-
-	*CSR_PCICMD = cmd;
-	*CSR_SA110_CNTL = ctrl;
-}
-
-static struct irqaction irq_pci_error = {
-	irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL
-};
-
-void __init pcibios_init_ebsa285(void)
-{
-	setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error);
-}
 
 /*
  * Netwinder stuff
@@ -627,7 +366,7 @@
 
 	current_cpld = (current_cpld & ~mask) | set;
 
-	gpio_modify_io(GPIO_DATA, 0);
+	gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0);
 	gpio_modify_op(GPIO_IOLOAD, 0);
 
 	for (msk = 8; msk; msk >>= 1) {
@@ -647,7 +386,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&gpio_lock, flags);
-	cpld_modify(-1, CPLD_UNMUTE | 4);
+	cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);
 	spin_unlock_irqrestore(&gpio_lock, flags);
 }
 
@@ -713,12 +452,15 @@
 
 	dprintk("Card no = %d\n", inb(0x203));
 
+	/* disable the modem section of the chip */
 	WRITE_RWA(7, 3);
 	WRITE_RWA(0x30, 0);
 
+	/* disable the cdrom section of the chip */
 	WRITE_RWA(7, 4);
 	WRITE_RWA(0x30, 0);
 
+	/* disable the MPU-401 section of the chip */
 	WRITE_RWA(7, 2);
 	WRITE_RWA(0x30, 0);
 }
@@ -925,6 +667,7 @@
 	extern void register_isa_ports(unsigned int, unsigned int, 
 				       unsigned int);
 	register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
+
 #ifdef CONFIG_ARCH_NETWINDER
 	/*
 	 * this ought to have a better home...
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c
--- v2.3.22/linux/arch/arm/kernel/init_task.c	Mon Jul 26 22:41:09 1999
+++ linux/arch/arm/kernel/init_task.c	Wed Oct 20 16:29:08 1999
@@ -1,4 +1,5 @@
 #include <linux/mm.h>
+#include <linux/fs.h>
 #include <linux/sched.h>
 
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c
--- v2.3.22/linux/arch/arm/kernel/ioport.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/ioport.c	Wed Oct 20 16:29:08 1999
@@ -9,10 +9,12 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
+#include <linux/mm.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_CPU_32
 asmlinkage int sys_iopl(unsigned long turn_on)
 {
 	if (turn_on && !capable(CAP_SYS_RAWIO))
@@ -25,3 +27,9 @@
 
 	return 0;
 }
+#else
+asmlinkage int sys_iopl(unsigned long turn_on)
+{
+	return -ENOSYS;
+}
+#endif
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.3.22/linux/arch/arm/kernel/irq.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/irq.c	Wed Oct 20 16:29:08 1999
@@ -494,8 +494,5 @@
 	}
 
 	irq_init_irq();
-#ifdef CONFIG_ARCH_ACORN
-	init_FIQ();
-#endif
 	init_dma();
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c
--- v2.3.22/linux/arch/arm/kernel/leds-footbridge.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/arm/kernel/leds-footbridge.c	Wed Oct 20 16:29:08 1999
@@ -138,7 +138,7 @@
 	switch (evt) {
 	case led_start:
 		led_state |= LED_STATE_ENABLED;
-		hw_led_state = 0;
+		hw_led_state = GPIO_GREEN_LED;
 		break;
 
 	case led_stop:
@@ -223,25 +223,19 @@
 {
 }
 
-void __init
+static void __init
 init_leds_event(led_event_t evt)
 {
-	switch (machine_arch_type) {
+	leds_event = dummy_leds_event;
+
 #ifdef CONFIG_FOOTBRIDGE
-	case MACH_TYPE_EBSA285:
-	case MACH_TYPE_CO285:
+	if (machine_is_ebsa285() || machine_is_co285())
 		leds_event = ebsa285_leds_event;
-		break;
 #endif
 #ifdef CONFIG_ARCH_NETWINDER
-	case MACH_TYPE_NETWINDER:
+	if (machine_is_netwinder())
 		leds_event = netwinder_leds_event;
-		break;
 #endif
-
-	default:
-		leds_event = dummy_leds_event;
-	}
 
 	leds_event(evt);
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.3.22/linux/arch/arm/kernel/process.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/process.c	Wed Oct 20 16:29:08 1999
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/process.c
  *
- *  Copyright (C) 1996 Russell King - Converted to ARM.
+ *  Copyright (C) 1996-1999 Russell King - Converted to ARM.
  *  Origional Copyright (C) 1995  Linus Torvalds
  */
 
@@ -32,6 +32,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/arch/system.h>
 #include <asm/io.h>
 
 extern char *processor_modes[];
@@ -60,26 +61,38 @@
 	current->priority = 0;
 	current->counter = -100;
 	while (1) {
-		if (!current->need_resched && !hlt_counter)
-			proc_idle();
-		schedule();
+		if (!hlt_counter)
+			arch_do_idle();
+		if (current->need_resched) {
+			schedule();
 #ifndef CONFIG_NO_PGT_CACHE
-		check_pgt_cache();
+			check_pgt_cache();
 #endif
+		}
 	}
 }
 
 static char reboot_mode = 'h';
 
-void __init reboot_setup(char *str, int *ints)
+int __init reboot_setup(char *str)
 {
 	reboot_mode = str[0];
+	return 0;
 }
 
+__setup("reboot=", reboot_setup);
+
 void machine_restart(char * __unused)
 {
+	/*
+	 * Turn off caches, interrupts, etc
+	 */
+	cpu_proc_fin();
+
 	arch_reset(reboot_mode);
-	panic("Reboot failed\n");
+
+	printk("Reboot failed -- System halted\n");
+
 	while (1);
 }
 
@@ -135,6 +148,35 @@
 #endif
 }
 
+void show_fpregs(struct user_fp *regs)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		unsigned long *p;
+		char type;
+
+		p = (unsigned long *)(regs->fpregs + i);
+
+		switch (regs->ftype[i]) {
+			case 1: type = 'f'; break;
+			case 2: type = 'd'; break;
+			case 3: type = 'e'; break;
+			default: type = '?'; break;
+		}
+		if (regs->init_flag)
+			type = '?';
+
+		printk("  f%d(%c): %08lx %08lx %08lx%c",
+			i, type, p[0], p[1], p[2], i & 1 ? '\n' : ' ');
+	}
+			
+
+	printk("FPSR: %08lx FPCR: %08lx\n",
+		(unsigned long)regs->fpsr,
+		(unsigned long)regs->fpcr);
+}
+
 /*
  * Task structure and kernel stack allocation.
  *
@@ -206,6 +248,7 @@
 void flush_thread(void)
 {
 	memset(&current->thread.debug, 0, sizeof(current->thread.debug));
+	memset(&current->thread.fpstate, 0, sizeof(current->thread.fpstate));
 	current->used_math = 0;
 	current->flags &= ~PF_USEDFPU;
 }
@@ -237,12 +280,10 @@
  */
 int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
 {
-	int fpvalid = 0;
-
 	if (current->used_math)
-		memcpy (fp, &current->thread.fpstate.soft, sizeof (fp));
+		memcpy(fp, &current->thread.fpstate.soft, sizeof (fp));
 
-	return fpvalid;
+	return current->used_math;
 }
 
 /*
@@ -281,6 +322,7 @@
  */
 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
+	extern long sys_exit(int) __attribute__((noreturn));
 	pid_t __ret;
 
 	__asm__ __volatile__(
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- v2.3.22/linux/arch/arm/kernel/ptrace.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/ptrace.c	Wed Oct 20 16:29:08 1999
@@ -447,8 +447,8 @@
 			unsigned long tmp;
 
 			ret = read_long(child, addr, &tmp);
-			if (ret)
-				put_user(tmp, (unsigned long *) data);
+			if (!ret)
+				ret = put_user(tmp, (unsigned long *) data);
 			goto out;
 		}
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c
--- v2.3.22/linux/arch/arm/kernel/semaphore.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/semaphore.c	Wed Oct 20 16:29:08 1999
@@ -8,6 +8,7 @@
  * Modified for ARM by Russell King
  */
 #include <linux/sched.h>
+#include <linux/errno.h>
 
 #include <asm/semaphore.h>
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.3.22/linux/arch/arm/kernel/setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/setup.c	Wed Oct 20 16:29:08 1999
@@ -10,36 +10,27 @@
  */
 
 #include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/major.h>
 #include <linux/utsname.h>
 #include <linux/blk.h>
-#include <linux/init.h>
 #include <linux/console.h>
+#include <linux/init.h>
 
 #include <asm/elf.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
 #include <asm/procinfo.h>
-#include <asm/segment.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 
+#ifndef MEM_SIZE
 #define MEM_SIZE	(16*1024*1024)
-#define COMMAND_LINE_SIZE 256
+#endif
 
 #ifndef CONFIG_CMDLINE
 #define CONFIG_CMDLINE ""
@@ -50,7 +41,6 @@
 #endif
 
 extern void reboot_setup(char *str, int *ints);
-extern void fpe_init(void);
 extern void disable_hlt(void);
 
 struct drive_info_struct { char dummy[32]; } drive_info;
@@ -64,10 +54,9 @@
 };
 
 extern int root_mountflags;
-extern int _etext, _edata, _end;
+extern int _text, _etext, _edata, _end;
 
 unsigned char aux_device_present;
-
          char elf_platform[ELF_PLATFORM_SIZE];
 unsigned int  elf_hwcap;
 
@@ -76,13 +65,16 @@
  */
 unsigned int processor_id;
 unsigned int __machine_arch_type;
+unsigned int vram_size;
+unsigned int system_rev;
+unsigned int system_serial_low;
+unsigned int system_serial_high;
 #ifdef MULTI_CPU
 struct processor processor;
 #endif
 #ifdef CONFIG_ARCH_ACORN
-int memc_ctrl_reg;
-int number_mfm_drives;
-unsigned int vram_size;
+unsigned int memc_ctrl_reg;
+unsigned int number_mfm_drives;
 #endif
 
 static struct proc_info_item proc_info;
@@ -95,39 +87,41 @@
  * symbol to be empty if not configured.
  */
 
-/*
- * initial ram disk
- */
-#ifdef CONFIG_BLK_DEV_INITRD
-static void __init
-check_initrd(unsigned long mem_start, unsigned long mem_end)
+static void __init setup_processor(void)
 {
-	if (initrd_end > mem_end) {
-		printk ("initrd extends beyond end of memory "
-			"(0x%08lx > 0x%08lx) - disabling initrd\n",
-			initrd_end, mem_end);
-		initrd_start = 0;
-	}
-}
+	extern struct proc_info_list __proc_info_begin, __proc_info_end;
+	struct proc_info_list *list;
 
-#else
-#define check_initrd(ms,me)
-#endif
+	/*
+	 * locate processor in the list of supported processor
+	 * types.  The linker builds this table for us from the
+	 * entries in arch/arm/mm/proc-*.S
+	 */
+	for (list = &__proc_info_begin; list < &__proc_info_end ; list++)
+		if ((processor_id & list->cpu_mask) == list->cpu_val)
+			break;
 
-void __init
-setup_processor(void)
-{
-	armidindex = 0;
+	/*
+	 * If processor type is unrecognised, then we
+	 * can do nothing...
+	 */
+	if (list >= &__proc_info_end) {
+		printk("CPU configuration botched (ID %08x), unable "
+		       "to continue.\n", processor_id);
+		while (1);
+	}
 
-	while ((armidlist[armidindex].id ^ processor_id) &
-	       armidlist[armidindex].mask)
-		armidindex += 1;
+	proc_info = *list->info;
 
-	if (armidlist[armidindex].id == 0)
-		while (1);
+#ifdef MULTI_CPU
+	processor = *list->proc;
+#endif
 
-	processor = *armidlist[armidindex].proc;
-	processor._proc_init();
+	sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
+	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
+	elf_hwcap = list->elf_hwcap;
+
+	cpu_proc_init();
 }
 
 static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
@@ -135,12 +129,13 @@
        char saved_command_line[COMMAND_LINE_SIZE];
 
 static void __init
-setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_sz)
+setup_mem(char *cmd_line, unsigned long *mem_sz)
 {
 	char c = ' ', *to = command_line;
 	int len = 0;
 
-	*mem_start = (unsigned long)&_end;
+	if (!*mem_sz)
+		*mem_sz = MEM_SIZE;
 
 	for (;;) {
 		if (c == ' ') {
@@ -181,24 +176,27 @@
 }
 
 static void __init
-setup_ram(int doload, int prompt, int image_start)
+setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
 {
 #ifdef CONFIG_BLK_DEV_RAM
 	extern int rd_doload;
 	extern int rd_prompt;
 	extern int rd_image_start;
+	extern int rd_size;
 
 	rd_image_start = image_start;
 	rd_prompt = prompt;
 	rd_doload = doload;
+
+	if (rd_sz)
+		rd_size = rd_sz;
 #endif
 }
 
 /*
  * initial ram disk
  */
-static void __init
-setup_initrd(unsigned int start, unsigned int size)
+static void __init setup_initrd(unsigned int start, unsigned int size)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (start) {
@@ -211,30 +209,62 @@
 #endif
 }
 
-#ifdef CONFIG_ARCH_ACORN
-int memc_ctrl_reg;
-int number_mfm_drives;
-unsigned int vram_size;
+static void __init check_initrd(unsigned long mem_end)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_end > mem_end) {
+		printk ("initrd extends beyond end of memory "
+			"(0x%08lx > 0x%08lx) - disabling initrd\n",
+			initrd_end, mem_end);
+		initrd_start = 0;
+	}
 #endif
+}
 
-#ifndef PARAMS_BASE
-#define PARAMS_BASE NULL
-#endif
+/*
+ * Standard memory resources
+ */
+static struct resource system_ram  = { "System RAM",  0, 0, IORESOURCE_MEM | IORESOURCE_BUSY };
+static struct resource video_ram   = { "Video RAM",   0, 0, IORESOURCE_MEM };
+static struct resource kernel_code = { "Kernel code", 0, 0, IORESOURCE_MEM };
+static struct resource kernel_data = { "Kernel data", 0, 0, IORESOURCE_MEM };
+static struct resource lpt1 = { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY };
+static struct resource lpt2 = { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY };
+static struct resource lpt3 = { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY };
 
-static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
-#define ENDIANNESS ((char)endian_test.l)
+static void __init request_standard_resources(unsigned long end)
+{
+	kernel_code.start  = __virt_to_bus((unsigned long) &_text);
+	kernel_code.end    = __virt_to_bus((unsigned long) &_etext - 1);
+	kernel_data.start  = __virt_to_bus((unsigned long) &_etext);
+	kernel_data.end    = __virt_to_bus((unsigned long) &_edata - 1);
+	system_ram.start   = __virt_to_bus(PAGE_OFFSET);
+	system_ram.end     = __virt_to_bus(end - 1);
+
+	request_resource(&iomem_resource, &system_ram);
+	request_resource(&system_ram, &kernel_code);
+	request_resource(&system_ram, &kernel_data);
+	if (video_ram.start != video_ram.end)
+		request_resource(&iomem_resource, &video_ram);
 
-void __init
-setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
+	/*
+	 * Some machines don't have the possibility of ever
+	 * possessing LPT1 (lp0) and LPT3 (lp2)
+	 */
+	if (machine_is_ebsa110() || machine_is_riscpc() ||
+	    machine_is_netwinder())
+		request_resource(&ioport_resource, &lpt1);
+	if (machine_is_riscpc())
+		request_resource(&ioport_resource, &lpt2);
+	if (machine_is_ebsa110() || machine_is_netwinder())
+		request_resource(&ioport_resource, &lpt3);
+}
+
+void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
 	struct param_struct *params = (struct param_struct *)PARAMS_BASE;
-	static unsigned char smptrap;
 	unsigned long memory_end = 0;
-	char *from = NULL;
-
-	if (smptrap == 1)
-		return;
-	smptrap = 1;
+	char *from = default_command_line;
 
 #if defined(CONFIG_ARCH_ARC)
 	__machine_arch_type = MACH_TYPE_ARCHIMEDES;
@@ -244,10 +274,11 @@
 
 	setup_processor();
 
-	init_mm.start_code = TASK_SIZE;
-	init_mm.end_code   = TASK_SIZE + (unsigned long) &_etext;
-	init_mm.end_data   = TASK_SIZE + (unsigned long) &_edata;
-	init_mm.brk	   = TASK_SIZE + (unsigned long) &_end;
+	/*
+	 * Defaults
+	 */
+	ROOT_DEV = MKDEV(0, 255);
+	setup_ramdisk(1, 1, 0, 0);
 
 	/*
 	 * Add your machine dependencies here
@@ -256,14 +287,35 @@
 	case MACH_TYPE_EBSA110:
 		/* EBSA110 locks if we execute 'wait for interrupt' */
 		disable_hlt();
-		if (params && params->u1.s.page_size != 4096)
+		if (params && params->u1.s.page_size != PAGE_SIZE)
 			params = NULL;
 		break;
 
+#ifdef CONFIG_ARCH_ACORN
+#ifdef CONFIG_ARCH_RPC
 	case MACH_TYPE_RISCPC:
 		/* RiscPC can't handle half-word loads and stores */
 		elf_hwcap &= ~HWCAP_HALF;
+		{
+			extern void init_dram_banks(struct param_struct *);
+			init_dram_banks(params);
+		}
+
+		switch (params->u1.s.pages_in_vram) {
+		case 512:
+			vram_size += PAGE_SIZE * 256;
+		case 256:
+			vram_size += PAGE_SIZE * 256;
+		default:
+			break;
+		}
+#endif
+	case MACH_TYPE_ARCHIMEDES:
+	case MACH_TYPE_A5K:
+		memc_ctrl_reg	  = params->u1.s.memc_control_reg;
+		number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
 		break;
+#endif
 
 	case MACH_TYPE_EBSA285:
 		if (params) {
@@ -271,6 +323,8 @@
 			ORIG_Y		 = params->u1.s.video_y;
 			ORIG_VIDEO_COLS  = params->u1.s.video_num_cols;
 			ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
+			video_ram.start  = 0x0a0000;
+			video_ram.end    = 0x0bffff;
 		}
 		break;
 
@@ -288,53 +342,67 @@
 		break;
 
 	case MACH_TYPE_CATS:
-		/* CATS must use soft-reboot */
+		/* CATS uses soft-reboot by default, since hard reboots
+		 * fail on early boards.
+		 */
 		reboot_setup("s", NULL);
+		params = NULL;
+		ORIG_VIDEO_LINES = 25;
+		ORIG_VIDEO_POINTS = 16;
+		ORIG_Y = 24;
+		video_ram.start = 0x0a0000;
+		video_ram.end   = 0x0bffff;
 		break;
 
 	case MACH_TYPE_NETWINDER:
 		/*
 		 * to be fixed in a future NeTTrom
 		 */
-		if (params->u1.s.page_size == 4096) {
+		if (params->u1.s.page_size == PAGE_SIZE) {
 			if (params->u1.s.nr_pages != 0x2000 &&
 			    params->u1.s.nr_pages != 0x4000) {
 				printk("Warning: bad NeTTrom parameters detected, using defaults\n");
-			    	/*
-			    	 * This stuff doesn't appear to be initialised
-			    	 * properly by NeTTrom 2.0.6 and 2.0.7
-			    	 */
+				/*
+				 * This stuff doesn't appear to be initialised
+				 * properly by NeTTrom 2.0.6 and 2.0.7
+				 */
 				params->u1.s.nr_pages = 0x2000;	/* 32MB */
 				params->u1.s.ramdisk_size = 0;
 				params->u1.s.flags = FLAG_READONLY;
 				params->u1.s.initrd_start = 0;
 				params->u1.s.initrd_size = 0;
 				params->u1.s.rd_start = 0;
-				params->u1.s.video_x = 0;
-				params->u1.s.video_y = 0;
-				params->u1.s.video_num_cols = 80;
-				params->u1.s.video_num_rows = 30;
 			}
 		} else {
 			printk("Warning: no NeTTrom parameter page detected, using "
 			       "compiled-in settings\n");
 			params = NULL;
 		}
+		video_ram.start = 0x0a0000;
+		video_ram.end   = 0x0bffff;
 		break;
 
 	default:
 		break;
 	}
 
-	if (params) {
-		memory_end	  = params->u1.s.page_size *
-				    params->u1.s.nr_pages;
-
-		ROOT_DEV	  = to_kdev_t(params->u1.s.rootdev);
+	if (params && params->u1.s.page_size != PAGE_SIZE) {
+		printk("Warning: wrong page size configuration, "
+		       "trying to continue\n");
+		params = NULL;
+	}
 
-		setup_ram((params->u1.s.flags & FLAG_RDLOAD) == 0,
-			  (params->u1.s.flags & FLAG_RDPROMPT) == 0,
-			  params->u1.s.rd_start);
+	if (params) {
+		memory_end	   = PAGE_SIZE * params->u1.s.nr_pages;
+		ROOT_DEV	   = to_kdev_t(params->u1.s.rootdev);
+		system_rev	   = params->u1.s.system_rev;
+		system_serial_low  = params->u1.s.system_serial_low;
+		system_serial_high = params->u1.s.system_serial_high;
+
+		setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0,
+			      (params->u1.s.flags & FLAG_RDPROMPT) == 0,
+			      params->u1.s.rd_start,
+			      params->u1.s.ramdisk_size);
 
 		setup_initrd(params->u1.s.initrd_start,
 			     params->u1.s.initrd_size);
@@ -342,57 +410,27 @@
 		if (!(params->u1.s.flags & FLAG_READONLY))
 			root_mountflags &= ~MS_RDONLY;
 
-#ifdef CONFIG_ARCH_ACORN
-#ifdef CONFIG_ARCH_RPC
-		{
-			extern void init_dram_banks(struct param_struct *);
-			init_dram_banks(params);
-		}
-#endif
-
-		memc_ctrl_reg	  = params->u1.s.memc_control_reg;
-		number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
-		vram_size	  = 0;
-
-		switch (params->u1.s.pages_in_vram) {
-		case 512:
-			vram_size += PAGE_SIZE * 256;
-		case 256:
-			vram_size += PAGE_SIZE * 256;
-		default:
-			break;
-		}
-
-		memory_end -= vram_size;
-#endif
-
 		from = params->commandline;
-	} else {
-		ROOT_DEV	  = to_kdev_t(0x00ff);
-
-		setup_ram(1, 1, 0);
-		setup_initrd(0, 0);
 	}
 
-	if (!memory_end)
-		memory_end = MEM_SIZE;
-
-	if (!from)
-		from = default_command_line;
-
-#ifdef CONFIG_NWFPE
-	fpe_init();
-#endif
-
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
 	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
-	setup_mem(from, memory_start_p, &memory_end);
+	setup_mem(from, &memory_end);
 
 	memory_end += PAGE_OFFSET;
 
-	check_initrd(*memory_start_p, memory_end);
+	*cmdline_p         = command_line;
+	init_mm.start_code = (unsigned long) &_text;
+	init_mm.end_code   = (unsigned long) &_etext;
+	init_mm.end_data   = (unsigned long) &_edata;
+	init_mm.brk	   = (unsigned long) &_end;
+	*memory_start_p    = (unsigned long) &_end;
+	*memory_end_p      = memory_end;
+
+	request_standard_resources(memory_end);
+	check_initrd(memory_end);
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
@@ -401,40 +439,49 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
-
-	*cmdline_p = command_line;
-	*memory_end_p = memory_end;
 }
 
 static const char *machine_desc[] = {
-	"EBSA110",
-	"Acorn-RiscPC",
+	/* Machine name		Allocater			*/
+	"EBSA110",		/* RMK				*/
+	"Acorn-RiscPC",		/* RMK				*/
 	"unknown",
-	"Nexus-FTV/PCI",
-	"EBSA285",
-	"Rebel-NetWinder",
-	"Chalice-CATS",
-	"unknown-TBOX",
-	"co-EBSA285",
-	"CL-PS7110",
-	"Acorn-Archimedes",
-	"Acorn-A5000"
+	"Nexus-FTV/PCI",	/* Philip Blundell		*/
+	"EBSA285",		/* RMK				*/
+	"Rebel-NetWinder",	/* RMK				*/
+	"Chalice-CATS",		/* Philip Blundell		*/
+	"unknown-TBOX",		/* Philip Blundell		*/
+	"co-EBSA285",		/* Mark van Doesburg		*/
+	"CL-PS7110",		/* Werner Almesberger		*/
+	"Acorn-Archimedes",	/* RMK/DAG			*/
+	"Acorn-A5000",		/* RMK/PB			*/
+	"Etoile",		/* Alex de Vries		*/
+	"LaCie_NAS",		/* Benjamin Herrenschmidt	*/
+	"CL-PS7500",		/* Philip Blundell		*/
+	"Shark"			/* Alexander Schulz		*/
 };
 
 int get_cpuinfo(char * buffer)
 {
-	int len;
+	char *p = buffer;
+
+	p += sprintf(p, "Processor\t: %s %s rev %d (%s)\n",
+		     proc_info.manufacturer, proc_info.cpu_name,
+		     (int)processor_id & 15, elf_platform);
+
+	p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n",
+		     (loops_per_sec+2500) / 500000,
+		     ((loops_per_sec+2500) / 5000) % 100);
+
+	p += sprintf(p, "Hardware\t: %s\n",
+		     machine_desc[machine_arch_type]);
+
+	p += sprintf(p, "Revision\t: %04x\n",
+		     system_rev);
+
+	p += sprintf(p, "Serial\t\t: %08x%08x\n",
+		     system_serial_high,
+		     system_serial_low);
 
-	len = sprintf(buffer,
-		"Processor\t: %s %s rev %d (%s)\n"
-		"BogoMips\t: %lu.%02lu\n"
-		"Hardware\t: %s\n",
-		proc_info.manufacturer,
-		proc_info.cpu_name,
-		(int)processor_id & 15,
-		elf_platform,
-		(loops_per_sec+2500) / 500000,
-		((loops_per_sec+2500) / 5000) % 100,
-		machine_desc[machine_arch_type]);
-	return len;
+	return p - buffer;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
--- v2.3.22/linux/arch/arm/kernel/signal.c	Mon Aug  2 10:19:52 1999
+++ linux/arch/arm/kernel/signal.c	Wed Oct 20 16:29:08 1999
@@ -16,6 +16,8 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/binfmts.h>
+#include <linux/tty.h>
 
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -550,6 +552,7 @@
 			default:
 				lock_kernel();
 				sigaddset(&current->signal, signr);
+				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
 				do_exit(exit_code);
 				/* NOTREACHED */
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.3.22/linux/arch/arm/kernel/sys_arm.c	Thu Jun 24 23:56:23 1999
+++ linux/arch/arm/kernel/sys_arm.c	Wed Oct 20 16:29:08 1999
@@ -19,6 +19,7 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.3.22/linux/arch/arm/kernel/traps.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/arm/kernel/traps.c	Wed Oct 20 16:29:08 1999
@@ -365,7 +365,6 @@
 	{
 		pgd_t *pgd;
 
-		printk ("current->thread.memmap = %08lX\n", current->thread.memmap);
 		pgd = pgd_offset(current->mm, addr);
 		printk ("*pgd = %08lx", pgd_val (*pgd));
 		if (!pgd_none (*pgd)) {
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.3.22/linux/arch/arm/lib/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/lib/Makefile	Wed Oct 20 16:29:08 1999
@@ -1,11 +1,11 @@
 #
 # linux/arch/arm/lib/Makefile
 #
-# Copyright (C) 1995-1998 Russell King
+# Copyright (C) 1995-1999 Russell King
 #
 
 L_TARGET := lib.a
-L_OBJS   := backtrace.o bitops.o checksum.o delay.o memcpy.o \
+L_OBJS   := backtrace.o bitops.o checksum.o delay.o \
 	    string.o system.o uaccess.o
 
 ifeq ($(PROCESSOR),armo)
@@ -13,7 +13,7 @@
 endif
 
 ifdef CONFIG_ARCH_ACORN
-  L_OBJS += loaders.o io-acorn.o
+  L_OBJS += io-acorn.o
   ifdef CONFIG_ARCH_A5K
     L_OBJS += floppydma.o
   endif
@@ -34,13 +34,13 @@
 
 include $(TOPDIR)/Rules.make
 
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+
 constants.h: getconsdata.o extractconstants.pl
 	$(PERL) extractconstants.pl $(OBJDUMP) > $@
 
 getconsdata.o: getconsdata.c
 	$(CC) $(CFLAGS) -c getconsdata.c
 
-checksum.o: constants.h
-
-%.o: %.S
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
+checksum.o string.o: constants.h
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/backtrace.S linux/arch/arm/lib/backtrace.S
--- v2.3.22/linux/arch/arm/lib/backtrace.S	Fri May  8 00:42:38 1998
+++ linux/arch/arm/lib/backtrace.S	Wed Oct 20 16:29:08 1999
@@ -21,6 +21,11 @@
 		mov	r0, fp
 
 ENTRY(c_backtrace)
+
+#ifndef CONFIG_FRAME_POINTER
+		mov	pc, lr
+#else
+
 		stmfd	sp!, {r4 - r8, lr}	@ Save an extra register so we have a location...
 #ifdef CONFIG_CPU_32
 		tst	r1, #0x10		@ 26 or 32-bit?
@@ -103,3 +108,5 @@
 		.align
 .Ldsi:		.word	0x00e92dd8 >> 2
 		.word	0x00e92d00 >> 2
+
+#endif
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/checksum.S linux/arch/arm/lib/checksum.S
--- v2.3.22/linux/arch/arm/lib/checksum.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/lib/checksum.S	Wed Oct 20 16:29:08 1999
@@ -74,8 +74,9 @@
 		stmfd	sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc}
 		.endm
 
-#define LOAD_REGS(cond)					\
-		LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r8, fp, sp, pc})
+		.macro	load_regs,flags
+		ldm\flags	fp, {r1, r2, r4-r8, fp, sp, pc}
+		.endm
 
 		.macro	load1b,	reg1
 9999:		ldrbt	\reg1, [r0], $1
@@ -134,8 +135,9 @@
 		mov	r9, r9, lsr #24
 		.endm
 
-#define LOAD_REGS(cond)					\
-		LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r9, fp, sp, pc})
+		.macro	load_regs,flags
+		ldm\flags	fp, {r1, r2, r4-r9, fp, sp, pc}^
+		.endm
 
 		.macro	load1b,	reg1
 		tst	r9, #0x01
@@ -245,7 +247,7 @@
 		adcs	r3, r3, r4
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOAD_REGS(eq)
+		load_regs	eqea
 		load1l	r4
 		tst	r2, #2
 		beq	.exit
@@ -259,11 +261,11 @@
 		andne	r4, r4, #255
 		adcnes	r3, r3, r4
 		adcs	r0, r3, #0
-		LOAD_REGS(al)
+		load_regs	ea
 
 .too_small_user:
 		teq	r2, #0
-		LOAD_REGS(eq)
+		load_regs	eqea
 		cmp	r2, #2
 		blt	.too_small_user1
 		load2b	ip, r8
@@ -278,7 +280,7 @@
 		strb	ip, [r1], #1
 		adcs	r3, r3, ip
 .csum_exit:	adc	r0, r3, #0
-		LOAD_REGS(al)
+		load_regs	ea
 
 .src_not_aligned_user:
 		cmp	r2, #4
@@ -331,7 +333,7 @@
 		mov	r4, r5, lsr #8
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOAD_REGS(eq)
+		load_regs	eqea
 		tst	r2, #2
 		beq	.exit
 		adcs	r3, r3, r4, lsl #16
@@ -384,7 +386,7 @@
 		mov	r4, r5, lsr #16
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOAD_REGS(eq)
+		load_regs	eqea
 		tst	r2, #2
 		beq	.exit
 		adcs	r3, r3, r4, lsl #16
@@ -437,7 +439,7 @@
 		mov	r4, r5, lsr #24
 4:		ands	r2, r2, #3
 		adceq	r0, r3, #0
-		LOAD_REGS(eq)
+		load_regs	eqea
 		tst	r2, #2
 		beq	.exit
 		adcs	r3, r3, r4, lsl #16
@@ -461,7 +463,7 @@
 6002:		teq	r2, r1
 		strneb	r3, [r1], #1
 		bne	6002b
-		LOAD_REGS(al)
+		load_regs	ea
 #if defined(CONFIG_CPU_32)
 		.previous
 #endif
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c
--- v2.3.22/linux/arch/arm/lib/getconsdata.c	Mon Aug  2 10:19:52 1999
+++ linux/arch/arm/lib/getconsdata.c	Wed Oct 20 16:29:08 1999
@@ -6,7 +6,7 @@
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/unistd.h>
+
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
@@ -15,13 +15,6 @@
 #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n)
 #define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n)
 
-#ifdef KERNEL_DOMAIN
-unsigned long DOM_KERNELDOMAIN = KERNEL_DOMAIN;
-#endif
-#ifdef USER_DOMAIN
-unsigned long DOM_USERDOMAIN = USER_DOMAIN;
-#endif
-
 unsigned long TSK_STATE = OFF_TSK(state);
 unsigned long TSK_FLAGS = OFF_TSK(flags);
 unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched);
@@ -34,10 +27,7 @@
 
 unsigned long TSS_SAVE = OFF_TSK(thread.save);
 unsigned long TSS_FPESAVE = OFF_TSK(thread.fpstate.soft.save);
-#ifdef CONFIG_CPU_26
-unsigned long TSS_MEMMAP = OFF_TSK(thread.memmap);
-unsigned long TSS_MEMCMAP = OFF_TSK(thread.memcmap);
-#elif defined(CONFIG_CPU_32)
+#ifdef CONFIG_CPU_32
 unsigned long TSS_DOMAIN = OFF_TSK(thread.domain);
 #endif
 
@@ -85,6 +75,8 @@
 unsigned long LPTE_EXEC       = L_PTE_EXEC;
 unsigned long LPTE_DIRTY      = L_PTE_DIRTY;
 #endif
+
+unsigned long PAGE_SZ = PAGE_SIZE;
 
 unsigned long KSWI_BASE = 0x900000;
 unsigned long KSWI_SYS_BASE = 0x9f0000;
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/loaders.S linux/arch/arm/lib/loaders.S
--- v2.3.22/linux/arch/arm/lib/loaders.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/lib/loaders.S	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-/*
- * linux/arch/arm/lib/loaders.S
- *
- * This file contains the ROM loaders for buggy cards
- */
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
-/*
- * Oak SCSI
- */
-
-ENTRY(oak_scsi_loader)
-			b	Loak_scsi_read
-			.word	0
-Loak_scsi_reset:	bic	r10, r11, #0x00ff0000
-			ldr	r2, [r10]
-			RETINSTR(mov,pc,lr)
-
-Loak_scsi_read:		mov	r2, r1, lsr #3
-			and	r2, r2, #15 << 9
-			bic	r10, r11, #0x00ff0000
-			ldr	r2, [r10, r2]
-			mov	r2, r1, lsl #20
-			ldrb	r0, [r11, r2, lsr #18]
-			ldr	r2, [r10]
-			RETINSTR(mov,pc,lr)
-
-ENTRY(atomwide_serial_loader)
-			b	Latomwide_serial_read
-			.word	0
-Latomwide_serial_reset:	mov	r2, #0x3c00
-			strb	r2, [r11, r2]
-			RETINSTR(mov,pc,lr)
-
-Latomwide_serial_read:	cmp	r1, #0x8000
-			RETINSTR(movhi,pc,lr)
-			add	r0, r1, #0x800
-			mov	r0, r0, lsr #11
-			mov	r3, #0x3c00
-			strb	r0, [r11, r3]
-			mov	r2, r1, lsl #21
-			ldrb	r0, [r11, r2, lsr #19]
-			strb	r2, [r11, r3]
-			RETINSTR(mov,pc,lr)
-
-/*
- * Cards we don't know about yet
- */
-ENTRY(noloader)
-			mov	r0, r0
-			mov	r0, #0
-			RETINSTR(mov,pc,lr)
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S
--- v2.3.22/linux/arch/arm/lib/memcpy.S	Sun Apr 12 11:42:15 1998
+++ linux/arch/arm/lib/memcpy.S	Wed Dec 31 16:00:00 1969
@@ -1,319 +0,0 @@
-/*
- * linux/arch/arm/lib/segment.S
- *
- * Copyright (C) 1995, 1996 Russell King
- * Except memcpy/memmove routine.
- */
-
-#include <asm/assembler.h>
-#include <linux/linkage.h>
-
-#ifndef ENTRY
-#define ENTRY(x...)				\
-		.globl	_##x;			\
-_##x:
-#endif
-
-		.text
-#define ENTER	\
-		mov	ip,sp	;\
-		stmfd	sp!,{r4-r9,fp,ip,lr,pc}	;\
-		sub	fp,ip,#4
-
-#define EXIT	\
-		LOADREGS(ea, fp, {r4 - r9, fp, sp, pc})
-
-#define EXITEQ	\
-		LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc})
-
-# Prototype: void memcpy(void *to,const void *from,unsigned long n);
-# ARM3: cant use memcopy here!!!
-
-ENTRY(memcpy)
-ENTRY(memmove)
-		ENTER
-		cmp	r1, r0
-		bcc	19f
-		subs	r2, r2, #4
-		blt	6f
-		ands	ip, r0, #3
-		bne	7f
-		ands	ip, r1, #3
-		bne	8f
-
-1:		subs	r2, r2, #8
-		blt	5f
-		subs	r2, r2, #0x14
-		blt	3f
-2:		ldmia	r1!,{r3 - r9, ip}
-		stmia	r0!,{r3 - r9, ip}
-		subs	r2, r2, #32
-		bge	2b
-		cmn	r2, #16
-		ldmgeia	r1!, {r3 - r6}
-		stmgeia	r0!, {r3 - r6}
-		subge	r2, r2, #0x10
-3:		adds	r2, r2, #0x14
-4:		ldmgeia	r1!, {r3 - r5}
-		stmgeia	r0!, {r3 - r5}
-		subges	r2, r2, #12
-		bge	4b
-5:		adds	r2, r2, #8
-		blt	6f
-		subs	r2, r2, #4
-		ldrlt	r3, [r1], #4
-		strlt	r3, [r0], #4
-		ldmgeia	r1!, {r3, r4}
-		stmgeia	r0!, {r3, r4}
-		subge	r2, r2, #4
-
-6:		adds	r2, r2, #4
-		EXITEQ
-		cmp	r2, #2
-		ldrb	r3, [r1], #1
-		strb	r3, [r0], #1
-		ldrgeb	r3, [r1], #1
-		strgeb	r3, [r0], #1
-		ldrgtb	r3, [r1], #1
-		strgtb	r3, [r0], #1
-		EXIT
-
-7:		rsb	ip, ip, #4
-		cmp	ip, #2
-		ldrb	r3, [r1], #1
-		strb	r3, [r0], #1
-		ldrgeb	r3, [r1], #1
-		strgeb	r3, [r0], #1
-		ldrgtb	r3, [r1], #1
-		strgtb	r3, [r0], #1
-		subs	r2, r2, ip
-		blt	6b
-		ands	ip, r1, #3
-		beq	1b
-
-8:		bic	r1, r1, #3
-		ldr	r7, [r1], #4
-		cmp	ip, #2
-		bgt	15f
-		beq	11f
-		cmp	r2, #12
-		blt	10f
-		sub	r2, r2, #12
-9:		mov	r3, r7, lsr #8
-		ldmia	r1!, {r4 - r7}
-		orr	r3, r3, r4, lsl #24
-		mov	r4, r4, lsr #8
-		orr	r4, r4, r5, lsl #24
-		mov	r5, r5, lsr #8
-		orr	r5, r5, r6, lsl #24
-		mov	r6, r6, lsr #8
-		orr	r6, r6, r7, lsl #24
-		stmia	r0!, {r3 - r6}
-		subs	r2, r2, #16
-		bge	9b
-		adds	r2, r2, #12
-		blt	100f
-10:		mov	r3, r7, lsr #8
-		ldr	r7, [r1], #4
-		orr	r3, r3, r7, lsl #24
-		str	r3, [r0], #4
-		subs	r2, r2, #4
-		bge	10b
-100:		sub	r1, r1, #3
-		b	6b
-
-11:		cmp	r2, #12
-		blt	13f		/* */
-		sub	r2, r2, #12
-12:		mov	r3, r7, lsr #16
-		ldmia	r1!, {r4 - r7}
-		orr	r3, r3, r4, lsl #16
-		mov	r4, r4, lsr #16
-		orr	r4, r4, r5, lsl #16
-		mov	r5, r5, lsr #16
-		orr	r5, r5, r6, lsl #16
-		mov	r6, r6, lsr #16
-		orr	r6, r6, r7,LSL#16
-		stmia	r0!, {r3 - r6}
-		subs	r2, r2, #16
-		bge	12b
-		adds	r2, r2, #12
-		blt	14f
-13:		mov	r3, r7, lsr #16
-		ldr	r7, [r1], #4
-		orr	r3, r3, r7, lsl #16
-		str	r3, [r0], #4
-		subs	r2, r2, #4
-		bge	13b
-14:		sub	r1, r1, #2
-		b	6b
-
-15:		cmp	r2, #12
-		blt	17f
-		sub	r2, r2, #12
-16:		mov	r3, r7, lsr #24
-		ldmia	r1!,{r4 - r7}
-		orr	r3, r3, r4, lsl #8
-		mov	r4, r4, lsr #24
-		orr	r4, r4, r5, lsl #8
-		mov	r5, r5, lsr #24
-		orr	r5, r5, r6, lsl #8
-		mov	r6, r6, lsr #24
-		orr	r6, r6, r7, lsl #8
-		stmia	r0!, {r3 - r6}
-		subs	r2, r2, #16
-		bge	16b
-		adds	r2, r2, #12
-		blt	18f
-17:		mov	r3, r7, lsr #24
-		ldr	r7, [r1], #4
-		orr	r3, r3, r7, lsl#8
-		str	r3, [r0], #4
-		subs	r2, r2, #4
-		bge	17b
-18:		sub	r1, r1, #1
-		b	6b
-
-
-19:		add	r1, r1, r2
-		add	r0, r0, r2
-		subs	r2, r2, #4
-		blt	24f
-		ands	ip, r0, #3
-		bne	25f
-		ands	ip, r1, #3
-		bne	26f
-
-20:		subs	r2, r2, #8
-		blt	23f
-		subs	r2, r2, #0x14
-		blt	22f
-21:		ldmdb	r1!, {r3 - r9, ip}
-		stmdb	r0!, {r3 - r9, ip}
-		subs	r2, r2, #32
-		bge	21b
-22:		cmn	r2, #16
-		ldmgedb	r1!, {r3 - r6}
-		stmgedb	r0!, {r3 - r6}
-		subge	r2, r2, #16
-		adds	r2, r2, #20
-		ldmgedb	r1!, {r3 - r5}
-		stmgedb	r0!, {r3 - r5}
-		subge	r2, r2, #12
-23:		adds	r2, r2, #8
-		blt	24f
-		subs	r2, r2, #4
-		ldrlt	r3, [r1, #-4]!
-		strlt	r3, [r0, #-4]!
-		ldmgedb	r1!, {r3, r4}
-		stmgedb	r0!, {r3, r4}
-		subge	r2, r2, #4
-
-24:		adds	r2, r2, #4
-		EXITEQ
-		cmp	r2, #2
-		ldrb	r3, [r1, #-1]!
-		strb	r3, [r0, #-1]!
-		ldrgeb	r3, [r1, #-1]!
-		strgeb	r3, [r0, #-1]!
-		ldrgtb	r3, [r1, #-1]!
-		strgtb	r3, [r0, #-1]!
-		EXIT
-
-25:		cmp	ip, #2
-		ldrb	r3, [r1, #-1]!
-		strb	r3, [r0, #-1]!
-		ldrgeb	r3, [r1, #-1]!
-		strgeb	r3, [r0, #-1]!
-		ldrgtb	r3, [r1, #-1]!
-		strgtb	r3, [r0, #-1]!
-		subs	r2, r2, ip
-		blt	24b
-		ands	ip, r1, #3
-		beq	20b
-
-26:		bic	r1, r1, #3
-		ldr	r3, [r1], #0
-		cmp	ip, #2
-		blt	34f
-		beq	30f
-		cmp	r2, #12
-		blt	28f
-		sub	r2, r2, #12
-27:		mov	r7, r3, lsl #8
-		ldmdb	r1!, {r3, r4, r5, r6}
-		orr	r7, r7, r6, lsr #24
-		mov	r6, r6, lsl #8
-		orr	r6, r6, r5, lsr #24
-		mov	r5, r5, lsl #8
-		orr	r5, r5, r4, lsr #24
-		mov	r4, r4, lsl #8
-		orr	r4, r4, r3, lsr #24
-		stmdb	r0!, {r4, r5, r6, r7}
-		subs	r2, r2, #16
-		bge	27b
-		adds	r2, r2, #12
-		blt	29f
-28:		mov	ip, r3, lsl #8
-		ldr	r3, [r1, #-4]!
-		orr	ip, ip, r3, lsr #24
-		str	ip, [r0, #-4]!
-		subs	r2, r2, #4
-		bge	28b
-29:		add	r1, r1, #3
-		b	24b
-
-30:		cmp	r2, #12
-		blt	32f
-		sub	r2, r2, #12
-31:		mov	r7, r3, lsl #16
-		ldmdb	r1!, {r3, r4, r5, r6}
-		orr	r7, r7, r6, lsr #16
-		mov	r6, r6, lsl #16
-		orr	r6, r6, r5, lsr #16
-		mov	r5, r5, lsl #16
-		orr	r5, r5, r4, lsr #16
-		mov	r4, r4, lsl #16
-		orr	r4, r4, r3, lsr #16
-		stmdb	r0!, {r4, r5, r6, r7}
-		subs	r2, r2, #16
-		bge	31b
-		adds	r2, r2, #12
-		blt	33f
-32:		mov	ip, r3, lsl #16
-		ldr	r3, [r1, #-4]!
-		orr	ip, ip, r3, lsr #16
-		str	ip, [r0, #-4]!
-		subs	r2, r2, #4
-		bge	32b
-33:		add	r1, r1, #2
-		b	24b
-
-34:		cmp	r2, #12
-		blt	36f
-		sub	r2, r2, #12
-35:		mov	r7, r3, lsl #24
-		ldmdb	r1!, {r3, r4, r5, r6}
-		orr	r7, r7, r6, lsr #8
-		mov	r6, r6, lsl #24
-		orr	r6, r6, r5, lsr #8
-		mov	r5, r5, lsl #24
-		orr	r5, r5, r4, lsr #8
-		mov	r4, r4, lsl #24
-		orr	r4, r4, r3, lsr #8
-		stmdb	r0!, {r4, r5, r6, r7}
-		subs	r2, r2, #16
-		bge	35b
-		adds	r2, r2, #12
-		blt	37f
-36:		mov	ip, r3, lsl #24
-		ldr	r3, [r1, #-4]!
-		orr	ip, ip, r3, lsr #8
-		str	ip, [r0, #-4]!
-		subs	r2, r2, #4
-		bge	36b
-37:		add	r1, r1, #1
-		b	24b
-
-		.align
-
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/string.S linux/arch/arm/lib/string.S
--- v2.3.22/linux/arch/arm/lib/string.S	Fri May  8 00:42:38 1998
+++ linux/arch/arm/lib/string.S	Wed Oct 20 16:29:08 1999
@@ -1,69 +1,112 @@
 /*
  * linux/arch/arm/lib/string.S
  *
- * Copyright (C) 1995-1998 Russell King
+ * Copyright (C) 1995-1999 Russell King
  *
- * This is commonly used to clear the frame buffer and the frame
- * backing buffer.  As such, it will be rarely called with r2 < 32.
+ * ASM optimised string functions
  *
- * Optimisations by Matthew Wilcox
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "constants.h"
+
 		.text
-# Prototype: char *strrchr(const char *s,char c);
 
 /*
  * Prototype: void memzero(void *d, size_t n)
  */
-ENTRY(memzero)
-		mov	r2, r1
-		mov	r1, #0
+1:		@ 4 <= r1
+		cmp	ip, #2				@	1
+		strltb	r2, [r0], #1			@	1
+		strleb	r2, [r0], #1			@	1
+		strb	r2, [r0], #1			@	1
+		rsb	ip, ip, #4			@	1
+		sub	r1, r1, ip			@	1
+		cmp	r1, #3				@	1
+		bgt	2f				@	1	@ +8
+		b	4f				@	1	@ +9
+
+		.align	5
+
+ENTRY(__memzero)
+		mov	r2, #0				@	1
+		cmp	r1, #4				@	1
+		blt	4f				@	1	@ = 3
+
+		@ r1 >= 4
+
+		ands	ip, r0, #3			@	1
+		bne	1b				@	1	@ = 5
+
+2:		@ r1 >= 4 && (r0 & 3) = 0				@ = 5 or 11
+
+		str	lr, [sp, #-4]!			@	1
+		mov	r3, #0				@	1
+		mov	ip, #0				@	1
+		mov	lr, #0				@	1
+
+		@ 4 <= r1 <= 32						@ = 9 or 15
+
+3:		subs	r1, r1, #32			@	1
+		stmgeia	r0!, {r2, r3, ip, lr}		@	4
+		stmgeia	r0!, {r2, r3, ip, lr}		@	4
+		bgt	3b				@	1
+		LOADREGS(eqfd, sp!, {pc})		@	1/2
+
+		@ -28 <= r1 <= -1
+
+		cmp	r1, #-16			@	1
+		stmgeia	r0!, {r2, r3, ip, lr}		@	4
+		ldr	lr, [sp], #4			@	1
+		addlts	r1, r1, #16			@	1
+		RETINSTR(moveq,pc,lr)			@	1
+
+		@ -12 <= r1 <= -1
+
+		cmp	r1, #-8				@	1
+		stmgeia	r0!, {r2, r3}			@	2
+		addlts	r1, r1, #8			@	1
+		RETINSTR(moveq,pc,lr)			@	1
+
+		@ -4 <= r1 <= -1
+
+		cmp	r1, #-4				@	1
+		strge	r2, [r0], #4			@	1
+		adds	r1, r1, #4			@	1
+		RETINSTR(moveq,pc,lr)			@	1
+
+4:		@ 1 <= r1 <= 3
+		cmp	r1, #2				@	1
+		strgtb	r2, [r0], #1			@	1
+		strgeb	r2, [r0], #1			@	1
+		strb	r2, [r0], #1			@	1
+		RETINSTR(mov,pc,lr)			@	1
+
 /*
- * Prototype: void memsetl(unsigned long *d, unsigned long c, size_t n)
+ * StrongARM optimised copy_page routine
+ * now 1.72bytes/cycle, was 1.60 bytes/cycle
+ * (50MHz bus -> 86MB/s)
  */
-ENTRY(memsetl)
-		teq	r2, #0
-		RETINSTR(moveq,pc,lr)
-		stmfd	sp!, {lr}
-		mov	lr, r1
-		mov	r3, r1
-		mov	ip, r1
-
-		@ r2 = {32 ... 4}
-
-1:		subs	r2, r2, #32
-		stmgeia	r0!, {r1, r3, ip, lr}
-		stmgeia	r0!, {r1, r3, ip, lr}
-		bgt	1b
-		LOADREGS(eqfd, sp!, {pc})
-
-		@ r2 can be {-4 ... -28}
 
-		cmp	r2, #-16
-		stmgeia	r0!, {r1, r3, ip, lr}
-		addlts	r2, r2, #16
-		LOADREGS(eqfd, sp!, {pc})
-
-		@ r2 can be {-4 ... -12}
-
-		cmp	r2, #-8
-		stmgeia	r0!, {r1, r3}
-		strne	r1, [r0]
-		LOADREGS(fd, sp!, {pc})
-
-		.global	__page_memcpy
-__page_memcpy:	stmfd	sp!, {r4, r5, lr}
-1:		subs	r2, r2, #4*8
-		ldmgeia	r1!, {r3, r4, r5, ip}
-		stmgeia	r0!, {r3, r4, r5, ip}
-		ldmgeia	r1!, {r3, r4, r5, ip}
-		stmgeia	r0!, {r3, r4, r5, ip}
-		bgt	1b
-		LOADREGS(fd, sp!, {r4, r5, pc})
-
-		.global	memset
-memset:		mov	r3, r0
+ENTRY(copy_page)
+		stmfd	sp!, {r4, lr}			@	2
+		mov	r2, #PAGE_SZ/64			@	1
+1:		ldmia	r1!, {r3, r4, ip, lr}		@	4
+		subs	r2, r2, #1			@	1
+		stmia	r0!, {r3, r4, ip, lr}		@	4
+		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+		stmia	r0!, {r3, r4, ip, lr}		@	4
+		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+		stmia	r0!, {r3, r4, ip, lr}		@	4
+		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+		stmia	r0!, {r3, r4, ip, lr}		@	4
+		bne	1b				@	1
+		LOADREGS(fd, sp!, {r4, pc})		@	3
+
+		.align	5
+ENTRY(memset)		/* needed for some versions of gcc */
+ENTRY(__memset)
+		mov	r3, r0
 		cmp	r2, #16
 		blt	6f
 		ands	ip, r3, #3
@@ -168,3 +211,309 @@
 2:		movne	r0, #0
 		subeq	r0, r0, #1
 		LOADREGS(fd, sp!, {pc})
+
+
+#define ENTER	\
+		mov	ip,sp	;\
+		stmfd	sp!,{r4-r9,fp,ip,lr,pc}	;\
+		sub	fp,ip,#4
+
+#define EXIT	\
+		LOADREGS(ea, fp, {r4 - r9, fp, sp, pc})
+
+#define EXITEQ	\
+		LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc})
+
+/*
+ * Prototype: void memcpy(void *to,const void *from,unsigned long n);
+ * ARM3: cant use memcopy here!!!
+ */
+ENTRY(memcpy)
+ENTRY(memmove)
+		ENTER
+		cmp	r1, r0
+		bcc	19f
+		subs	r2, r2, #4
+		blt	6f
+		ands	ip, r0, #3
+		bne	7f
+		ands	ip, r1, #3
+		bne	8f
+
+1:		subs	r2, r2, #8
+		blt	5f
+		subs	r2, r2, #0x14
+		blt	3f
+2:		ldmia	r1!,{r3 - r9, ip}
+		stmia	r0!,{r3 - r9, ip}
+		subs	r2, r2, #32
+		bge	2b
+		cmn	r2, #16
+		ldmgeia	r1!, {r3 - r6}
+		stmgeia	r0!, {r3 - r6}
+		subge	r2, r2, #0x10
+3:		adds	r2, r2, #0x14
+4:		ldmgeia	r1!, {r3 - r5}
+		stmgeia	r0!, {r3 - r5}
+		subges	r2, r2, #12
+		bge	4b
+5:		adds	r2, r2, #8
+		blt	6f
+		subs	r2, r2, #4
+		ldrlt	r3, [r1], #4
+		strlt	r3, [r0], #4
+		ldmgeia	r1!, {r3, r4}
+		stmgeia	r0!, {r3, r4}
+		subge	r2, r2, #4
+
+6:		adds	r2, r2, #4
+		EXITEQ
+		cmp	r2, #2
+		ldrb	r3, [r1], #1
+		strb	r3, [r0], #1
+		ldrgeb	r3, [r1], #1
+		strgeb	r3, [r0], #1
+		ldrgtb	r3, [r1], #1
+		strgtb	r3, [r0], #1
+		EXIT
+
+7:		rsb	ip, ip, #4
+		cmp	ip, #2
+		ldrb	r3, [r1], #1
+		strb	r3, [r0], #1
+		ldrgeb	r3, [r1], #1
+		strgeb	r3, [r0], #1
+		ldrgtb	r3, [r1], #1
+		strgtb	r3, [r0], #1
+		subs	r2, r2, ip
+		blt	6b
+		ands	ip, r1, #3
+		beq	1b
+
+8:		bic	r1, r1, #3
+		ldr	r7, [r1], #4
+		cmp	ip, #2
+		bgt	15f
+		beq	11f
+		cmp	r2, #12
+		blt	10f
+		sub	r2, r2, #12
+9:		mov	r3, r7, lsr #8
+		ldmia	r1!, {r4 - r7}
+		orr	r3, r3, r4, lsl #24
+		mov	r4, r4, lsr #8
+		orr	r4, r4, r5, lsl #24
+		mov	r5, r5, lsr #8
+		orr	r5, r5, r6, lsl #24
+		mov	r6, r6, lsr #8
+		orr	r6, r6, r7, lsl #24
+		stmia	r0!, {r3 - r6}
+		subs	r2, r2, #16
+		bge	9b
+		adds	r2, r2, #12
+		blt	100f
+10:		mov	r3, r7, lsr #8
+		ldr	r7, [r1], #4
+		orr	r3, r3, r7, lsl #24
+		str	r3, [r0], #4
+		subs	r2, r2, #4
+		bge	10b
+100:		sub	r1, r1, #3
+		b	6b
+
+11:		cmp	r2, #12
+		blt	13f		/* */
+		sub	r2, r2, #12
+12:		mov	r3, r7, lsr #16
+		ldmia	r1!, {r4 - r7}
+		orr	r3, r3, r4, lsl #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r5, lsl #16
+		mov	r5, r5, lsr #16
+		orr	r5, r5, r6, lsl #16
+		mov	r6, r6, lsr #16
+		orr	r6, r6, r7,LSL#16
+		stmia	r0!, {r3 - r6}
+		subs	r2, r2, #16
+		bge	12b
+		adds	r2, r2, #12
+		blt	14f
+13:		mov	r3, r7, lsr #16
+		ldr	r7, [r1], #4
+		orr	r3, r3, r7, lsl #16
+		str	r3, [r0], #4
+		subs	r2, r2, #4
+		bge	13b
+14:		sub	r1, r1, #2
+		b	6b
+
+15:		cmp	r2, #12
+		blt	17f
+		sub	r2, r2, #12
+16:		mov	r3, r7, lsr #24
+		ldmia	r1!,{r4 - r7}
+		orr	r3, r3, r4, lsl #8
+		mov	r4, r4, lsr #24
+		orr	r4, r4, r5, lsl #8
+		mov	r5, r5, lsr #24
+		orr	r5, r5, r6, lsl #8
+		mov	r6, r6, lsr #24
+		orr	r6, r6, r7, lsl #8
+		stmia	r0!, {r3 - r6}
+		subs	r2, r2, #16
+		bge	16b
+		adds	r2, r2, #12
+		blt	18f
+17:		mov	r3, r7, lsr #24
+		ldr	r7, [r1], #4
+		orr	r3, r3, r7, lsl#8
+		str	r3, [r0], #4
+		subs	r2, r2, #4
+		bge	17b
+18:		sub	r1, r1, #1
+		b	6b
+
+
+19:		add	r1, r1, r2
+		add	r0, r0, r2
+		subs	r2, r2, #4
+		blt	24f
+		ands	ip, r0, #3
+		bne	25f
+		ands	ip, r1, #3
+		bne	26f
+
+20:		subs	r2, r2, #8
+		blt	23f
+		subs	r2, r2, #0x14
+		blt	22f
+21:		ldmdb	r1!, {r3 - r9, ip}
+		stmdb	r0!, {r3 - r9, ip}
+		subs	r2, r2, #32
+		bge	21b
+22:		cmn	r2, #16
+		ldmgedb	r1!, {r3 - r6}
+		stmgedb	r0!, {r3 - r6}
+		subge	r2, r2, #16
+		adds	r2, r2, #20
+		ldmgedb	r1!, {r3 - r5}
+		stmgedb	r0!, {r3 - r5}
+		subge	r2, r2, #12
+23:		adds	r2, r2, #8
+		blt	24f
+		subs	r2, r2, #4
+		ldrlt	r3, [r1, #-4]!
+		strlt	r3, [r0, #-4]!
+		ldmgedb	r1!, {r3, r4}
+		stmgedb	r0!, {r3, r4}
+		subge	r2, r2, #4
+
+24:		adds	r2, r2, #4
+		EXITEQ
+		cmp	r2, #2
+		ldrb	r3, [r1, #-1]!
+		strb	r3, [r0, #-1]!
+		ldrgeb	r3, [r1, #-1]!
+		strgeb	r3, [r0, #-1]!
+		ldrgtb	r3, [r1, #-1]!
+		strgtb	r3, [r0, #-1]!
+		EXIT
+
+25:		cmp	ip, #2
+		ldrb	r3, [r1, #-1]!
+		strb	r3, [r0, #-1]!
+		ldrgeb	r3, [r1, #-1]!
+		strgeb	r3, [r0, #-1]!
+		ldrgtb	r3, [r1, #-1]!
+		strgtb	r3, [r0, #-1]!
+		subs	r2, r2, ip
+		blt	24b
+		ands	ip, r1, #3
+		beq	20b
+
+26:		bic	r1, r1, #3
+		ldr	r3, [r1], #0
+		cmp	ip, #2
+		blt	34f
+		beq	30f
+		cmp	r2, #12
+		blt	28f
+		sub	r2, r2, #12
+27:		mov	r7, r3, lsl #8
+		ldmdb	r1!, {r3, r4, r5, r6}
+		orr	r7, r7, r6, lsr #24
+		mov	r6, r6, lsl #8
+		orr	r6, r6, r5, lsr #24
+		mov	r5, r5, lsl #8
+		orr	r5, r5, r4, lsr #24
+		mov	r4, r4, lsl #8
+		orr	r4, r4, r3, lsr #24
+		stmdb	r0!, {r4, r5, r6, r7}
+		subs	r2, r2, #16
+		bge	27b
+		adds	r2, r2, #12
+		blt	29f
+28:		mov	ip, r3, lsl #8
+		ldr	r3, [r1, #-4]!
+		orr	ip, ip, r3, lsr #24
+		str	ip, [r0, #-4]!
+		subs	r2, r2, #4
+		bge	28b
+29:		add	r1, r1, #3
+		b	24b
+
+30:		cmp	r2, #12
+		blt	32f
+		sub	r2, r2, #12
+31:		mov	r7, r3, lsl #16
+		ldmdb	r1!, {r3, r4, r5, r6}
+		orr	r7, r7, r6, lsr #16
+		mov	r6, r6, lsl #16
+		orr	r6, r6, r5, lsr #16
+		mov	r5, r5, lsl #16
+		orr	r5, r5, r4, lsr #16
+		mov	r4, r4, lsl #16
+		orr	r4, r4, r3, lsr #16
+		stmdb	r0!, {r4, r5, r6, r7}
+		subs	r2, r2, #16
+		bge	31b
+		adds	r2, r2, #12
+		blt	33f
+32:		mov	ip, r3, lsl #16
+		ldr	r3, [r1, #-4]!
+		orr	ip, ip, r3, lsr #16
+		str	ip, [r0, #-4]!
+		subs	r2, r2, #4
+		bge	32b
+33:		add	r1, r1, #2
+		b	24b
+
+34:		cmp	r2, #12
+		blt	36f
+		sub	r2, r2, #12
+35:		mov	r7, r3, lsl #24
+		ldmdb	r1!, {r3, r4, r5, r6}
+		orr	r7, r7, r6, lsr #8
+		mov	r6, r6, lsl #24
+		orr	r6, r6, r5, lsr #8
+		mov	r5, r5, lsl #24
+		orr	r5, r5, r4, lsr #8
+		mov	r4, r4, lsl #24
+		orr	r4, r4, r3, lsr #8
+		stmdb	r0!, {r4, r5, r6, r7}
+		subs	r2, r2, #16
+		bge	35b
+		adds	r2, r2, #12
+		blt	37f
+36:		mov	ip, r3, lsl #24
+		ldr	r3, [r1, #-4]!
+		orr	ip, ip, r3, lsr #8
+		str	ip, [r0, #-4]!
+		subs	r2, r2, #4
+		bge	36b
+37:		add	r1, r1, #1
+		b	24b
+
+		.align
+
+
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/system.S linux/arch/arm/lib/system.S
--- v2.3.22/linux/arch/arm/lib/system.S	Sun Sep  6 10:44:47 1998
+++ linux/arch/arm/lib/system.S	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/* 
- * linux/arch/arm/lib/system.S
- *
- * Copyright (C) 1995, 1996 Russell King
- *
- * 07/06/96: Now support tasks running in SVC mode.
- */
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
-		.text
-
-ENTRY(abort)
-		adr	r0, .abort_msg
-		mov	r1, lr
-		b	SYMBOL_NAME(panic)
-
-.abort_msg:	.ascii	"Eek! Got to an abort() from %p! "
-		.ascii	"(Please report to rmk@arm.uk.linux.org)\n\0"
-		.align
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/system.c linux/arch/arm/lib/system.c
--- v2.3.22/linux/arch/arm/lib/system.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/system.c	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,22 @@
+/*
+ * linux/arch/arm/lib/system.c
+ *
+ * Copyright (C) 1999 Russell King
+ *
+ * Converted from ASM version 04/09/1999
+ */
+#include <linux/kernel.h>
+
+extern void abort(void)
+{
+	void *lr = __builtin_return_address(0);
+
+	printk(KERN_CRIT "kernel abort from %p!  (Please report to rmk@arm.linux.org.uk)\n",
+		lr);
+
+	/* force an oops */
+	*(int *)0 = 0;
+
+	/* if that doesn't kill us, halt */
+	panic("Oops failed to kill thread");
+}
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/uaccess-armo.S linux/arch/arm/lib/uaccess-armo.S
--- v2.3.22/linux/arch/arm/lib/uaccess-armo.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/lib/uaccess-armo.S	Wed Oct 20 16:29:08 1999
@@ -30,7 +30,7 @@
 		.word	__arch_copy_to_user
 		.word	__arch_clear_user
 		.word	__arch_strncpy_from_user
-		.word	__arch_strlen_user
+		.word	__arch_strnlen_user
 
 
 @ In : r0 = x, r1 = addr, r2 = error
diff -u --recursive --new-file v2.3.22/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S
--- v2.3.22/linux/arch/arm/lib/uaccess.S	Sun Sep  6 10:44:47 1998
+++ linux/arch/arm/lib/uaccess.S	Wed Oct 20 16:29:08 1999
@@ -42,11 +42,11 @@
 		rsb	ip, ip, #4
 		cmp	ip, #2
 		ldrb	r3, [r1], #1
-USER(		strbt	r3, [r0], #1)			// May fault
+USER(		strbt	r3, [r0], #1)			@ May fault
 		ldrgeb	r3, [r1], #1
-USER(		strgebt	r3, [r0], #1)			// May fault
+USER(		strgebt	r3, [r0], #1)			@ May fault
 		ldrgtb	r3, [r1], #1
-USER(		strgtbt	r3, [r0], #1)			// May fault
+USER(		strgtbt	r3, [r0], #1)			@ May fault
 		sub	r2, r2, ip
 		b	.c2u_dest_aligned
 
@@ -69,8 +69,8 @@
 		addmi	ip, r2, #4
 		bmi	.c2u_0nowords
 		ldr	r3, [r1], #4
-USER(		strt	r3, [r0], #4)			// May fault
-		mov	ip, r0, lsl #32 - PAGE_SHIFT	// On each page, use a ld/st??t instruction
+USER(		strt	r3, [r0], #4)			@ May fault
+		mov	ip, r0, lsl #32 - PAGE_SHIFT	@ On each page, use a ld/st??t instruction
 		rsb	ip, ip, #0
 		movs	ip, ip, lsr #32 - PAGE_SHIFT
 		beq	.c2u_0fupi
@@ -84,31 +84,31 @@
 		blt	.c2u_0rem8lp
 
 .c2u_0cpy8lp:	ldmia	r1!, {r3 - r6}
-		stmia	r0!, {r3 - r6}			// Shouldn't fault
+		stmia	r0!, {r3 - r6}			@ Shouldn't fault
 		ldmia	r1!, {r3 - r6}
-		stmia	r0!, {r3 - r6}			// Shouldn't fault
+		stmia	r0!, {r3 - r6}			@ Shouldn't fault
 		subs	ip, ip, #32
 		bpl	.c2u_0cpy8lp
 .c2u_0rem8lp:	cmn	ip, #16
 		ldmgeia	r1!, {r3 - r6}
-		stmgeia	r0!, {r3 - r6}			// Shouldn't fault
+		stmgeia	r0!, {r3 - r6}			@ Shouldn't fault
 		tst	ip, #8
 		ldmneia	r1!, {r3 - r4}
-		stmneia	r0!, {r3 - r4}			// Shouldn't fault
+		stmneia	r0!, {r3 - r4}			@ Shouldn't fault
 		tst	ip, #4
 		ldrne	r3, [r1], #4
-		strnet	r3, [r0], #4			// Shouldn't fault
+		strnet	r3, [r0], #4			@ Shouldn't fault
 		ands	ip, ip, #3
 		beq	.c2u_0fupi
 .c2u_0nowords:	teq	ip, #0
 		beq	.c2u_finished
 .c2u_nowords:	cmp	ip, #2
 		ldrb	r3, [r1], #1
-USER(		strbt	r3, [r0], #1)			// May fault
+USER(		strbt	r3, [r0], #1)			@ May fault
 		ldrgeb	r3, [r1], #1
-USER(		strgebt	r3, [r0], #1)			// May fault
+USER(		strgebt	r3, [r0], #1)			@ May fault
 		ldrgtb	r3, [r1], #1
-USER(		strgtbt	r3, [r0], #1)			// May fault
+USER(		strgtbt	r3, [r0], #1)			@ May fault
 		b	.c2u_finished
 
 .c2u_not_enough:
@@ -129,7 +129,7 @@
 		mov	r3, r7, lsr #8
 		ldr	r7, [r1], #4
 		orr	r3, r3, r7, lsl #24
-USER(		strt	r3, [r0], #4)			// May fault
+USER(		strt	r3, [r0], #4)			@ May fault
 		mov	ip, r0, lsl #32 - PAGE_SHIFT
 		rsb	ip, ip, #0
 		movs	ip, ip, lsr #32 - PAGE_SHIFT
@@ -149,7 +149,7 @@
 		orr	r5, r5, r6, lsl #24
 		mov	r6, r6, lsr #8
 		orr	r6, r6, r7, lsl #24
-		stmia	r0!, {r3 - r6}			// Shouldn't fault
+		stmia	r0!, {r3 - r6}			@ Shouldn't fault
 		subs	ip, ip, #16
 		bpl	.c2u_1cpy8lp
 .c2u_1rem8lp:	tst	ip, #8
@@ -158,23 +158,23 @@
 		orrne	r3, r3, r4, lsl #24
 		movne	r4, r4, lsr #8
 		orrne	r4, r4, r7, lsl #24
-		stmneia	r0!, {r3 - r4}			// Shouldn't fault
+		stmneia	r0!, {r3 - r4}			@ Shouldn't fault
 		tst	ip, #4
 		movne	r3, r7, lsr #8
 		ldrne	r7, [r1], #4
 		orrne	r3, r3, r7, lsl #24
-		strnet	r3, [r0], #4			// Shouldn't fault
+		strnet	r3, [r0], #4			@ Shouldn't fault
 		ands	ip, ip, #3
 		beq	.c2u_1fupi
 .c2u_1nowords:	mov	r3, r7, lsr #8
 		teq	ip, #0
 		beq	.c2u_finished
 		cmp	ip, #2
-USER(		strbt	r3, [r0], #1)			// May fault
+USER(		strbt	r3, [r0], #1)			@ May fault
 		movge	r3, r3, lsr #8
-USER(		strgebt	r3, [r0], #1)			// May fault
+USER(		strgebt	r3, [r0], #1)			@ May fault
 		movgt	r3, r3, lsr #8
-USER(		strgtbt	r3, [r0], #1)			// May fault
+USER(		strgtbt	r3, [r0], #1)			@ May fault
 		b	.c2u_finished
 
 .c2u_2fupi:	subs	r2, r2, #4
@@ -183,7 +183,7 @@
 		mov	r3, r7, lsr #16
 		ldr	r7, [r1], #4
 		orr	r3, r3, r7, lsl #16
-USER(		strt	r3, [r0], #4)			// May fault
+USER(		strt	r3, [r0], #4)			@ May fault
 		mov	ip, r0, lsl #32 - PAGE_SHIFT
 		rsb	ip, ip, #0
 		movs	ip, ip, lsr #32 - PAGE_SHIFT
@@ -203,7 +203,7 @@
 		orr	r5, r5, r6, lsl #16
 		mov	r6, r6, lsr #16
 		orr	r6, r6, r7, lsl #16
-		stmia	r0!, {r3 - r6}			// Shouldn't fault
+		stmia	r0!, {r3 - r6}			@ Shouldn't fault
 		subs	ip, ip, #16
 		bpl	.c2u_2cpy8lp
 .c2u_2rem8lp:	tst	ip, #8
@@ -212,23 +212,23 @@
 		orrne	r3, r3, r4, lsl #16
 		movne	r4, r4, lsr #16
 		orrne	r4, r4, r7, lsl #16
-		stmneia	r0!, {r3 - r4}			// Shouldn't fault
+		stmneia	r0!, {r3 - r4}			@ Shouldn't fault
 		tst	ip, #4
 		movne	r3, r7, lsr #16
 		ldrne	r7, [r1], #4
 		orrne	r3, r3, r7, lsl #16
-		strnet	r3, [r0], #4			// Shouldn't fault
+		strnet	r3, [r0], #4			@ Shouldn't fault
 		ands	ip, ip, #3
 		beq	.c2u_2fupi
 .c2u_2nowords:	mov	r3, r7, lsr #16
 		teq	ip, #0
 		beq	.c2u_finished
 		cmp	ip, #2
-USER(		strbt	r3, [r0], #1)			// May fault
+USER(		strbt	r3, [r0], #1)			@ May fault
 		movge	r3, r3, lsr #8
-USER(		strgebt	r3, [r0], #1)			// May fault
+USER(		strgebt	r3, [r0], #1)			@ May fault
 		ldrgtb	r3, [r1], #0
-USER(		strgtbt	r3, [r0], #1)			// May fault
+USER(		strgtbt	r3, [r0], #1)			@ May fault
 		b	.c2u_finished
 
 .c2u_3fupi:	subs	r2, r2, #4
@@ -237,7 +237,7 @@
 		mov	r3, r7, lsr #24
 		ldr	r7, [r1], #4
 		orr	r3, r3, r7, lsl #8
-USER(		strt	r3, [r0], #4)			// May fault
+USER(		strt	r3, [r0], #4)			@ May fault
 		mov	ip, r0, lsl #32 - PAGE_SHIFT
 		rsb	ip, ip, #0
 		movs	ip, ip, lsr #32 - PAGE_SHIFT
@@ -257,7 +257,7 @@
 		orr	r5, r5, r6, lsl #8
 		mov	r6, r6, lsr #24
 		orr	r6, r6, r7, lsl #8
-		stmia	r0!, {r3 - r6}			// Shouldn't fault
+		stmia	r0!, {r3 - r6}			@ Shouldn't fault
 		subs	ip, ip, #16
 		bpl	.c2u_3cpy8lp
 .c2u_3rem8lp:	tst	ip, #8
@@ -266,23 +266,23 @@
 		orrne	r3, r3, r4, lsl #8
 		movne	r4, r4, lsr #24
 		orrne	r4, r4, r7, lsl #8
-		stmneia	r0!, {r3 - r4}			// Shouldn't fault
+		stmneia	r0!, {r3 - r4}			@ Shouldn't fault
 		tst	ip, #4
 		movne	r3, r7, lsr #24
 		ldrne	r7, [r1], #4
 		orrne	r3, r3, r7, lsl #8
-		strnet	r3, [r0], #4			// Shouldn't fault
+		strnet	r3, [r0], #4			@ Shouldn't fault
 		ands	ip, ip, #3
 		beq	.c2u_3fupi
 .c2u_3nowords:	mov	r3, r7, lsr #24
 		teq	ip, #0
 		beq	.c2u_finished
 		cmp	ip, #2
-USER(		strbt	r3, [r0], #1)			// May fault
+USER(		strbt	r3, [r0], #1)			@ May fault
 		ldrge	r3, [r1], #0
-USER(		strgebt	r3, [r0], #1)			// May fault
+USER(		strgebt	r3, [r0], #1)			@ May fault
 		movgt	r3, r3, lsr #8
-USER(		strgtbt	r3, [r0], #1)			// May fault
+USER(		strgtbt	r3, [r0], #1)			@ May fault
 		b	.c2u_finished
 
 #ifndef TESTING
@@ -302,11 +302,11 @@
 .cfu_dest_not_aligned:
 		rsb	ip, ip, #4
 		cmp	ip, #2
-USER(		ldrbt	r3, [r1], #1)			// May fault
+USER(		ldrbt	r3, [r1], #1)			@ May fault
 		strb	r3, [r0], #1
-USER(		ldrgebt	r3, [r1], #1)			// May fault
+USER(		ldrgebt	r3, [r1], #1)			@ May fault
 		strgeb	r3, [r0], #1
-USER(		ldrgtbt	r3, [r1], #1)			// May fault
+USER(		ldrgtbt	r3, [r1], #1)			@ May fault
 		strgtb	r3, [r0], #1
 		sub	r2, r2, ip
 		b	.cfu_dest_aligned
@@ -330,7 +330,7 @@
 		bmi	.cfu_0nowords
 USER(		ldrt	r3, [r1], #4)
 		str	r3, [r0], #4
-		mov	ip, r1, lsl #32 - PAGE_SHIFT	// On each page, use a ld/st??t instruction
+		mov	ip, r1, lsl #32 - PAGE_SHIFT	@ On each page, use a ld/st??t instruction
 		rsb	ip, ip, #0
 		movs	ip, ip, lsr #32 - PAGE_SHIFT
 		beq	.cfu_0fupi
@@ -343,31 +343,31 @@
 		subs	ip, ip, #32
 		blt	.cfu_0rem8lp
 
-.cfu_0cpy8lp:	ldmia	r1!, {r3 - r6}			// Shouldn't fault
+.cfu_0cpy8lp:	ldmia	r1!, {r3 - r6}			@ Shouldn't fault
 		stmia	r0!, {r3 - r6}
-		ldmia	r1!, {r3 - r6}			// Shouldn't fault
+		ldmia	r1!, {r3 - r6}			@ Shouldn't fault
 		stmia	r0!, {r3 - r6}
 		subs	ip, ip, #32
 		bpl	.cfu_0cpy8lp
 .cfu_0rem8lp:	cmn	ip, #16
-		ldmgeia	r1!, {r3 - r6}			// Shouldn't fault
+		ldmgeia	r1!, {r3 - r6}			@ Shouldn't fault
 		stmgeia	r0!, {r3 - r6}
 		tst	ip, #8
-		ldmneia	r1!, {r3 - r4}			// Shouldn't fault
+		ldmneia	r1!, {r3 - r4}			@ Shouldn't fault
 		stmneia	r0!, {r3 - r4}
 		tst	ip, #4
-		ldrnet	r3, [r1], #4			// Shouldn't fault
+		ldrnet	r3, [r1], #4			@ Shouldn't fault
 		strne	r3, [r0], #4
 		ands	ip, ip, #3
 		beq	.cfu_0fupi
 .cfu_0nowords:	teq	ip, #0
 		beq	.cfu_finished
 .cfu_nowords:	cmp	ip, #2
-USER(		ldrbt	r3, [r1], #1)			// May fault
+USER(		ldrbt	r3, [r1], #1)			@ May fault
 		strb	r3, [r0], #1
-USER(		ldrgebt	r3, [r1], #1)			// May fault
+USER(		ldrgebt	r3, [r1], #1)			@ May fault
 		strgeb	r3, [r0], #1
-USER(		ldrgtbt	r3, [r1], #1)			// May fault
+USER(		ldrgtbt	r3, [r1], #1)			@ May fault
 		strgtb	r3, [r0], #1
 		b	.cfu_finished
 
@@ -380,7 +380,7 @@
 
 .cfu_src_not_aligned:
 		bic	r1, r1, #3
-USER(		ldrt	r7, [r1], #4)			// May fault
+USER(		ldrt	r7, [r1], #4)			@ May fault
 		cmp	ip, #2
 		bgt	.cfu_3fupi
 		beq	.cfu_2fupi
@@ -388,7 +388,7 @@
 		addmi	ip, r2, #4
 		bmi	.cfu_1nowords
 		mov	r3, r7, lsr #8
-USER(		ldrt	r7, [r1], #4)			// May fault
+USER(		ldrt	r7, [r1], #4)			@ May fault
 		orr	r3, r3, r7, lsl #24
 		str	r3, [r0], #4
 		mov	ip, r1, lsl #32 - PAGE_SHIFT
@@ -402,7 +402,7 @@
 		blt	.cfu_1rem8lp
 
 .cfu_1cpy8lp:	mov	r3, r7, lsr #8
-		ldmia	r1!, {r4 - r7}			// Shouldn't fault
+		ldmia	r1!, {r4 - r7}			@ Shouldn't fault
 		orr	r3, r3, r4, lsl #24
 		mov	r4, r4, lsr #8
 		orr	r4, r4, r5, lsl #24
@@ -415,14 +415,14 @@
 		bpl	.cfu_1cpy8lp
 .cfu_1rem8lp:	tst	ip, #8
 		movne	r3, r7, lsr #8
-		ldmneia	r1!, {r4, r7}			// Shouldn't fault
+		ldmneia	r1!, {r4, r7}			@ Shouldn't fault
 		orrne	r3, r3, r4, lsl #24
 		movne	r4, r4, lsr #8
 		orrne	r4, r4, r7, lsl #24
 		stmneia	r0!, {r3 - r4}
 		tst	ip, #4
 		movne	r3, r7, lsr #8
-USER(		ldrnet	r7, [r1], #4)			// May fault
+USER(		ldrnet	r7, [r1], #4)			@ May fault
 		orrne	r3, r3, r7, lsl #24
 		strne	r3, [r0], #4
 		ands	ip, ip, #3
@@ -442,7 +442,7 @@
 		addmi	ip, r2, #4
 		bmi	.cfu_2nowords
 		mov	r3, r7, lsr #16
-USER(		ldrt	r7, [r1], #4)			// May fault
+USER(		ldrt	r7, [r1], #4)			@ May fault
 		orr	r3, r3, r7, lsl #16
 		str	r3, [r0], #4
 		mov	ip, r1, lsl #32 - PAGE_SHIFT
@@ -456,7 +456,7 @@
 		blt	.cfu_2rem8lp
 
 .cfu_2cpy8lp:	mov	r3, r7, lsr #16
-		ldmia	r1!, {r4 - r7}			// Shouldn't fault
+		ldmia	r1!, {r4 - r7}			@ Shouldn't fault
 		orr	r3, r3, r4, lsl #16
 		mov	r4, r4, lsr #16
 		orr	r4, r4, r5, lsl #16
@@ -469,14 +469,14 @@
 		bpl	.cfu_2cpy8lp
 .cfu_2rem8lp:	tst	ip, #8
 		movne	r3, r7, lsr #16
-		ldmneia	r1!, {r4, r7}			// Shouldn't fault
+		ldmneia	r1!, {r4, r7}			@ Shouldn't fault
 		orrne	r3, r3, r4, lsl #16
 		movne	r4, r4, lsr #16
 		orrne	r4, r4, r7, lsl #16
 		stmneia	r0!, {r3 - r4}
 		tst	ip, #4
 		movne	r3, r7, lsr #16
-USER(		ldrnet	r7, [r1], #4)			// May fault
+USER(		ldrnet	r7, [r1], #4)			@ May fault
 		orrne	r3, r3, r7, lsl #16
 		strne	r3, [r0], #4
 		ands	ip, ip, #3
@@ -488,7 +488,7 @@
 		strb	r3, [r0], #1
 		movge	r3, r3, lsr #8
 		strgeb	r3, [r0], #1
-USER(		ldrgtbt	r3, [r1], #0)			// May fault
+USER(		ldrgtbt	r3, [r1], #0)			@ May fault
 		strgtb	r3, [r0], #1
 		b	.cfu_finished
 
@@ -496,7 +496,7 @@
 		addmi	ip, r2, #4
 		bmi	.cfu_3nowords
 		mov	r3, r7, lsr #24
-USER(		ldrt	r7, [r1], #4)			// May fault
+USER(		ldrt	r7, [r1], #4)			@ May fault
 		orr	r3, r3, r7, lsl #8
 		str	r3, [r0], #4
 		mov	ip, r1, lsl #32 - PAGE_SHIFT
@@ -510,7 +510,7 @@
 		blt	.cfu_3rem8lp
 
 .cfu_3cpy8lp:	mov	r3, r7, lsr #24
-		ldmia	r1!, {r4 - r7}			// Shouldn't fault
+		ldmia	r1!, {r4 - r7}			@ Shouldn't fault
 		orr	r3, r3, r4, lsl #8
 		mov	r4, r4, lsr #24
 		orr	r4, r4, r5, lsl #8
@@ -523,14 +523,14 @@
 		bpl	.cfu_3cpy8lp
 .cfu_3rem8lp:	tst	ip, #8
 		movne	r3, r7, lsr #24
-		ldmneia	r1!, {r4, r7}			// Shouldn't fault
+		ldmneia	r1!, {r4, r7}			@ Shouldn't fault
 		orrne	r3, r3, r4, lsl #8
 		movne	r4, r4, lsr #24
 		orrne	r4, r4, r7, lsl #8
 		stmneia	r0!, {r3 - r4}
 		tst	ip, #4
 		movne	r3, r7, lsr #24
-USER(		ldrnet	r7, [r1], #4)			// May fault
+USER(		ldrnet	r7, [r1], #4)			@ May fault
 		orrne	r3, r3, r7, lsl #8
 		strne	r3, [r0], #4
 		ands	ip, ip, #3
@@ -540,7 +540,7 @@
 		beq	.cfu_finished
 		cmp	ip, #2
 		strb	r3, [r0], #1
-USER(		ldrget	r3, [r1], #0)			// May fault
+USER(		ldrget	r3, [r1], #0)			@ May fault
 		strgeb	r3, [r0], #1
 		movgt	r3, r3, lsr #8
 		strgtb	r3, [r0], #1
@@ -553,7 +553,8 @@
 		   data was copied.  */
 9001:		ldr	r0, [sp], #4
 		ldr	r1, [sp]
-		bl	SYMBOL_NAME(memzero)
+		teq	r1, #0
+		blne	SYMBOL_NAME(__memzero)
 		LOADREGS(fd,sp!, {r0, r4 - r7, pc})
 		.previous
 #endif
@@ -597,19 +598,23 @@
 9001:		LOADREGS(fd,sp!, {r0, pc})
 		.previous
 
-/* Prototype: int __arch_strlen_user(char *str)
+/* Prototype: unsigned long __arch_strnlen_user(const char *str, long n)
  * Purpose  : get length of a string in user memory
  * Params   : str - address of string in user memory
- * Returns  : length of string *including terminator*, or zero on error
+ * Returns  : length of string *including terminator*
+ *	      or zero on exception, or n + 1 if too long
  */
-ENTRY(__arch_strlen_user)
+ENTRY(__arch_strnlen_user)
 		stmfd	sp!, {lr}
 		mov	r2, r0
 1:
-USER(		ldrbt	r1, [r0], #1)
-		teq	r1, #0
+USER(		ldrbt	r3, [r0], #1)
+		teq	r3, #0
+		beq	2f
+		subs	r1, r1, #1
 		bne	1b
-		sub	r0, r0, r2
+		add	r0, r0, #1
+2:		sub	r0, r0, r2
 		LOADREGS(fd,sp!, {pc})
 
 		.section .fixup,"ax"
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile
--- v2.3.22/linux/arch/arm/mm/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/Makefile	Wed Oct 20 16:29:08 1999
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET	:= mm.o
-O_OBJS		:= init.o extable.o fault-$(PROCESSOR).o small_page.o
+O_OBJS		:= init.o extable.o fault-$(PROCESSOR).o mm-$(PROCESSOR).o \
+		   small_page.o
 
 ifeq ($(CONFIG_CPU_26),y)
   O_OBJS	+= proc-arm2,3.o
@@ -24,13 +25,16 @@
   ifeq ($(CONFIG_CPU_SA110),y)
     P_OBJS	+= proc-sa110.o
   endif
+  ifeq ($(CONFIG_CPU_SA1100),y)
+    P_OBJS	+= proc-sa110.o
+  endif
   O_OBJS	+= mm-$(MACHINE).o ioremap.o $(sort $(P_OBJS))
 endif
 
 include $(TOPDIR)/Rules.make
 
-%.o: %.S
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $<
 
 # Special dependencies
 fault-armv.o: fault-common.c
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c
--- v2.3.22/linux/arch/arm/mm/fault-armo.c	Sun Jul 25 13:45:25 1999
+++ linux/arch/arm/mm/fault-armo.c	Wed Oct 20 16:29:08 1999
@@ -23,61 +23,12 @@
 #define FAULT_CODE_FORCECOW	0x80
 #define FAULT_CODE_PREFETCH	0x04
 #define FAULT_CODE_WRITE	0x02
-#define FAULT_CODE_USER		0x01
 
 #define DO_COW(m)		((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
 #define READ_FAULT(m)		(!((m) & FAULT_CODE_WRITE))
 
 #include "fault-common.c"
 
-static void *alloc_table(int size, int prio)
-{
-	if (size != 128)
-		printk("invalid table size\n");
-	return (void *)get_page_8k(prio);
-}
-
-void free_table(void *table)
-{
-	free_page_8k((unsigned long)table);
-}
-
-pgd_t *get_pgd_slow(void)
-{
-	pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
-	pgd_t *init;
-
-	if (pgd) {
-		init = pgd_offset(&init_mm, 0);
-		memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
-		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
-	}
-	return pgd;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
-			set_pmd(pmd, mk_pmd(pte));
-			return pte + offset;
-		}
-		set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
-		return NULL;
-	}
-	free_table((void *)pte);
-	if (pmd_bad(*pmd)) {
-		__bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 /*
  * Handle a data abort.  Note that we have to handle a range of addresses
  * on ARM2/3 for ldm.  If both pages are zero-mapped, then we have to force
@@ -96,11 +47,11 @@
 do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
 {
 #if 0
-	if (the memc mapping for this page exists - can check now...) {
+	if (the memc mapping for this page exists) {
 		printk ("Page in, but got abort (undefined instruction?)\n");
 		return 0;
 	}
 #endif
-	do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs);
+	do_page_fault(addr, FAULT_CODE_PREFETCH, regs);
 	return 1;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.3.22/linux/arch/arm/mm/fault-armv.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/fault-armv.c	Wed Oct 20 16:29:08 1999
@@ -25,104 +25,12 @@
 #include <asm/unaligned.h>
 
 #define FAULT_CODE_READ		0x02
-#define FAULT_CODE_USER		0x01
 
 #define DO_COW(m)		(!((m) & FAULT_CODE_READ))
 #define READ_FAULT(m)		((m) & FAULT_CODE_READ)
 
 #include "fault-common.c"
 
-/*
- * need to get a 16k page for level 1
- */
-pgd_t *get_pgd_slow(void)
-{
-	pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
-	pgd_t *init;
-	pmd_t *new_pmd;
-
-	if (pgd) {
-		init = pgd_offset(&init_mm, 0);
-		memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
-		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
-		clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR);
-
-		/*
-		 * On ARM, first page must always be allocated
-		 */
-		if (!pmd_alloc(pgd, 0))
-			goto nomem;
-		else {
-			pmd_t *old_pmd = pmd_offset(init, 0);
-			new_pmd = pmd_offset(pgd, 0);
-
-			if (!pte_alloc(new_pmd, 0))
-				goto nomem_pmd;
-			else {
-				pte_t *new_pte = pte_offset(new_pmd, 0);
-				pte_t *old_pte = pte_offset(old_pmd, 0);
-
-				set_pte (new_pte, *old_pte);
-			}
-		}
-	}
-	return pgd;
-
-nomem_pmd:
-	pmd_free(new_pmd);
-nomem:
-	return NULL;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *)get_page_2k(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
-			clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
-			pte += PTRS_PER_PTE;
-			set_pmd(pmd, mk_user_pmd(pte));
-			return pte + offset;
-		}
-		set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
-		return NULL;
-	}
-	free_page_2k((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *)get_page_2k(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
-			clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
-			pte += PTRS_PER_PTE;
-			set_pmd(pmd, mk_kernel_pmd(pte));
-			return pte + offset;
-		}
-		set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
-		return NULL;
-	}
-	free_page_2k((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 #ifdef DEBUG
 static int sp_valid(unsigned long *sp)
 {
@@ -406,6 +314,10 @@
 
 #endif
 
+#define BUG_PROC_MSG \
+  "Buggy processor (%08X), trying to continue.\n" \
+  "Please read http://www.arm.linux.org.uk/state.html for more information"
+
 asmlinkage void
 do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
 {
@@ -416,17 +328,11 @@
 				/*
 				 * I want statistical information on this problem!
 				 */
-				printk(KERN_ERR "Buggy processor (%08X), "
-					"trying to continue.\n"
-					"Please send contents of /proc/cpuinfo "
-					"and this message to linux@arm.linux.org.uk",
-					fsr);
+				printk(KERN_ERR BUG_PROC_MSG, fsr);
 				first = 0;
 			}
 			return;
 		}
-
-		error_code |= FAULT_CODE_USER;
 	}
 
 #define DIE(signr,nam)\
@@ -522,6 +428,6 @@
 asmlinkage int
 do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
 {
-	do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
+	do_page_fault(addr, FAULT_CODE_READ, regs);
 	return 1;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.3.22/linux/arch/arm/mm/fault-common.c	Mon Aug  2 10:19:52 1999
+++ linux/arch/arm/mm/fault-common.c	Wed Oct 20 16:29:08 1999
@@ -30,7 +30,7 @@
  * This is useful to dump out the page tables associated with
  * 'addr' in mm 'mm'.
  */
-void show_pte(struct mm_struct *mm, unsigned long addr)
+static void show_pte(struct mm_struct *mm, unsigned long addr)
 {
 	pgd_t *pgd;
 
@@ -62,7 +62,9 @@
 
 		pte = pte_offset(pmd, addr);
 		printk(", *pte = %08lx", pte_val(*pte));
+#ifdef CONFIG_CPU_32
 		printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
+#endif
 	} while(0);
 
 	printk("\n");
@@ -73,7 +75,7 @@
  * terminate things with extreme prejudice.
  */
 static void
-kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
+kernel_page_fault(unsigned long addr, int write_access, struct pt_regs *regs,
 		  struct task_struct *tsk, struct mm_struct *mm)
 {
 	char *reason;
@@ -90,7 +92,7 @@
 
 	printk(KERN_ALERT "pgd = %p\n", mm->pgd);
 	show_pte(mm, addr);
-	die("Oops", regs, mode);
+	die("Oops", regs, write_access);
 
 	do_exit(SIGKILL);
 }
@@ -153,7 +155,7 @@
 	up(&mm->mmap_sem);
 
 	/* User mode accesses just cause a SIGSEGV */
-	if (mode & FAULT_CODE_USER) {
+	if (user_mode(regs)) {
 		tsk->thread.error_code = mode;
 		tsk->thread.trap_no = 14;
 #ifdef CONFIG_DEBUG_USER
@@ -194,7 +196,7 @@
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
-	if (!(mode & FAULT_CODE_USER))
+	if (!user_mode(regs))
 		goto no_context;
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.3.22/linux/arch/arm/mm/init.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/init.c	Thu Oct 21 12:15:36 1999
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/mm/init.c
  *
- *  Copyright (C) 1995, 1996  Russell King
+ *  Copyright (C) 1995-1999  Russell King
  */
 
 #include <linux/config.h>
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/swapctl.h>
 #include <linux/smp.h>
 #include <linux/init.h>
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -26,14 +27,18 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 #include <asm/hardware.h>
-#include <asm/proc/mm-init.h>
+
+#include "map.h"
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
 #ifndef CONFIG_NO_PGT_CACHE
 struct pgtable_cache_struct quicklists;
 #endif
 
-extern char _etext, _stext, _edata, __bss_start, _end;
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern void show_net_buffers(void);
+
+extern char _etext, _text, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
 int do_check_pgt_cache(int low, int high)
@@ -67,7 +72,6 @@
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-#if PTRS_PER_PTE != 1
 pte_t *empty_bad_page_table;
 
 pte_t *__bad_pagetable(void)
@@ -81,7 +85,6 @@
 
 	return empty_bad_page_table;
 }
-#endif
 
 unsigned long *empty_zero_page;
 unsigned long *empty_bad_page;
@@ -94,27 +97,39 @@
 
 void show_mem(void)
 {
-	extern void show_net_buffers(void);
-	int i,free = 0,total = 0,reserved = 0;
-	int shared = 0;
+	int free = 0, total = 0, reserved = 0;
+	int shared = 0, cached = 0;
+	struct page *page, *end;
 
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	i = MAP_NR(high_memory);
-	while (i-- > 0) {
+	for (page = mem_map, end = mem_map + max_mapnr;
+	     page < end; page++) {
+		if (PageSkip(page)) {
+			if (page->next_hash < page)
+				break;
+			page = page->next_hash;
+		}
 		total++;
-		if (PageReserved(mem_map+i))
+		if (PageReserved(page))
 			reserved++;
-		else if (!atomic_read(&mem_map[i].count))
+		else if (PageSwapCache(page))
+			cached++;
+		else if (!atomic_read(&page->count))
 			free++;
 		else
-			shared += atomic_read(&mem_map[i].count) - 1;
+			shared += atomic_read(&page->count) - 1;
 	}
-	printk("%d pages of RAM\n",total);
-	printk("%d free pages\n",free);
-	printk("%d reserved pages\n",reserved);
-	printk("%d pages shared\n",shared);
+	printk("%d pages of RAM\n", total);
+	printk("%d free pages\n", free);
+	printk("%d reserved pages\n", reserved);
+	printk("%d pages shared\n", shared);
+	printk("%d pages swap cached\n", cached);
+#ifndef CONFIG_NO_PGT_CACHE
+	printk("%ld page tables cached\n", pgtable_cache_size);
+#endif
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -125,25 +140,24 @@
  */
 unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-	extern unsigned long free_area_init(unsigned long, unsigned long);
-
 	start_mem = PAGE_ALIGN(start_mem);
+
 	empty_zero_page = (unsigned long *)start_mem;
+	memzero(empty_zero_page, PAGE_SIZE);
 	start_mem += PAGE_SIZE;
+
 	empty_bad_page = (unsigned long *)start_mem;
 	start_mem += PAGE_SIZE;
-#if PTRS_PER_PTE != 1
+
 #ifdef CONFIG_CPU_32
 	start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
 #endif
 	empty_bad_page_table = (pte_t *)start_mem;
 	start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
-#endif
-	memzero (empty_zero_page, PAGE_SIZE);
-	start_mem = setup_pagetables (start_mem, end_mem);
+
+	start_mem = setup_page_tables(start_mem, end_mem);
 
 	flush_tlb_all();
-	update_memc_all();
 
 	end_mem &= PAGE_MASK;
 	high_memory = (void *)end_mem;
@@ -151,6 +165,31 @@
 	return free_area_init(start_mem, end_mem);
 }
 
+static inline void free_unused_mem_map(void)
+{
+	struct page *page, *end;
+
+	end = mem_map + max_mapnr;
+
+	for (page = mem_map; page < end; page++) {
+		unsigned long low, high;
+
+		if (!PageSkip(page))
+			continue;
+
+		low = PAGE_ALIGN((unsigned long)(page + 1));
+		if (page->next_hash < page)
+			high = ((unsigned long)end) & PAGE_MASK;
+		else
+			high = ((unsigned long)page->next_hash) & PAGE_MASK;
+
+		while (low < high) {
+			clear_bit(PG_reserved, &mem_map[MAP_NR(low)].flags);
+			low += PAGE_SIZE;
+		}
+	}
+}
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -158,28 +197,48 @@
  */
 void __init mem_init(unsigned long start_mem, unsigned long end_mem)
 {
-	extern void sound_init(void);
 	int codepages = 0;
 	int reservedpages = 0;
 	int datapages = 0;
-	int initpages = 0;
+	int initpages = 0, i, min_nr;
 	unsigned long tmp;
 
-	end_mem &= PAGE_MASK;
-	high_memory = (void *)end_mem;
-	max_mapnr = num_physpages = MAP_NR(end_mem);
+	end_mem      &= PAGE_MASK;
+	high_memory   = (void *)end_mem;
+	max_mapnr     = MAP_NR(end_mem);
+	num_physpages = 0;
+
+	/* setup address validity bitmap */
+	start_mem = create_mem_holes(start_mem, end_mem);
+
+	start_mem = PAGE_ALIGN(start_mem);
 
 	/* mark usable pages in the mem_map[] */
-	mark_usable_memory_areas(&start_mem, end_mem);
+	mark_usable_memory_areas(start_mem, end_mem);
+
+	/* free unused mem_map[] entries */
+	free_unused_mem_map();
 
 #define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \
 			    (w) < (unsigned long)(max))
 
 	for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
+		if (PageSkip(mem_map+MAP_NR(tmp))) {
+			unsigned long next;
+
+			next = mem_map[MAP_NR(tmp)].next_hash - mem_map;
+
+			next = (next << PAGE_SHIFT) + PAGE_OFFSET;
+
+			if (next < tmp || next >= end_mem)
+				break;
+			tmp = next;
+		}
+		num_physpages++;
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
 			if (BETWEEN(tmp, &__init_begin, &__init_end))
 				initpages++;
-			else if (BETWEEN(tmp, &_stext, &_etext))
+			else if (BETWEEN(tmp, &_text, &_etext))
 				codepages++;
 			else if (BETWEEN(tmp, &_etext, &_edata))
 				datapages++;
@@ -200,11 +259,24 @@
 
 	printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n",
 		 (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
-		 max_mapnr >> (20 - PAGE_SHIFT),
-		 codepages << (PAGE_SHIFT-10),
+		 num_physpages >> (20 - PAGE_SHIFT),
+		 codepages     << (PAGE_SHIFT-10),
 		 reservedpages << (PAGE_SHIFT-10),
-		 datapages << (PAGE_SHIFT-10),
-		 initpages << (PAGE_SHIFT-10));
+		 datapages     << (PAGE_SHIFT-10),
+		 initpages     << (PAGE_SHIFT-10));
+
+	i = nr_free_pages >> 7;
+	if (PAGE_SIZE < 32768)
+		min_nr = 10;
+	else
+		min_nr = 2;
+	if (i < min_nr)
+		i = min_nr;
+	if (i > 256)
+		i = 256;
+	freepages.min = i;
+	freepages.low = i * 2;
+	freepages.high = i * 3;
 
 #ifdef CONFIG_CPU_26
 	if (max_mapnr <= 128) {
@@ -240,14 +312,16 @@
 
 #ifdef CONFIG_FOOTBRIDGE
 	{
-	extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end;
+	extern int __netwinder_begin, __netwinder_end,
+		   __ebsa285_begin, __ebsa285_end;
 
 	if (!machine_is_netwinder())
 		free_area((unsigned long)(&__netwinder_begin),
 			  (unsigned long)(&__netwinder_end),
 			  "netwinder");
 
-	if (!machine_is_ebsa285() && !machine_is_cats() && !machine_is_co285())
+	if (!machine_is_ebsa285() && !machine_is_cats() &&
+	    !machine_is_co285())
 		free_area((unsigned long)(&__ebsa285_begin),
 			  (unsigned long)(&__ebsa285_end),
 			  "ebsa285/cats");
@@ -259,22 +333,28 @@
 
 void si_meminfo(struct sysinfo *val)
 {
-	int i;
+	struct page *page, *end;
 
-	i = MAP_NR(high_memory);
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
 	val->bufferram = atomic_read(&buffermem);
-	while (i-- > 0)  {
-		if (PageReserved(mem_map+i))
+	for (page = mem_map, end = mem_map + max_mapnr;
+	     page < end; page++) {
+		if (PageSkip(page)) {
+			if (page->next_hash < page)
+				break;
+			page = page->next_hash;
+		}
+		if (PageReserved(page))
 			continue;
 		val->totalram++;
-		if (!atomic_read(&mem_map[i].count))
+		if (!atomic_read(&page->count))
 			continue;
-		val->sharedram += atomic_read(&mem_map[i].count) - 1;
+		val->sharedram += atomic_read(&page->count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
+	val->totalbig = 0;
+	val->freebig = 0;
 }
-
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c
--- v2.3.22/linux/arch/arm/mm/ioremap.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/ioremap.c	Wed Oct 20 16:29:08 1999
@@ -27,8 +27,12 @@
  * FIFO.  Unfortunately, it is not possible to tell the DC21285 to
  * flush this - flushing the area causes the bus to lock.
  */
-
+#include <linux/errno.h>
+#include <linux/mm.h>
 #include <linux/vmalloc.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/io.h>
 
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
@@ -145,5 +149,5 @@
 
 void __iounmap(void *addr)
 {
-	return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+	vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/map.h linux/arch/arm/mm/map.h
--- v2.3.22/linux/arch/arm/mm/map.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/map.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,32 @@
+/*
+ *  linux/arch/arm/mm/map.h
+ *
+ *  Copyright (C) 1999 Russell King
+ *
+ *  Page table mapping constructs and function prototypes
+ */
+struct map_desc {
+	unsigned long virtual;
+	unsigned long physical;
+	unsigned long length;
+	int domain:4,
+	    prot_read:1,
+	    prot_write:1,
+	    cacheable:1,
+	    bufferable:1;
+};
+
+struct mem_desc {
+	unsigned long virt_start;
+	unsigned long virt_end;
+};
+
+extern struct map_desc	io_desc[];
+extern unsigned int	io_desc_size;
+extern struct mem_desc	mem_desc[];
+extern unsigned int	mem_desc_size;
+
+extern void mark_usable_memory_areas(unsigned long start, unsigned long end);
+extern unsigned long create_mem_holes(unsigned long start, unsigned long end);
+extern unsigned long setup_page_tables(unsigned long start, unsigned long end);
+
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c
--- v2.3.22/linux/arch/arm/mm/mm-armo.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/mm-armo.c	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,170 @@
+/*
+ * arch/arm/mm/mm-armo.c
+ *
+ * Page table sludge for older ARM processor architectures.
+ *
+ * Copyright (C) 1998-1999 Russell King
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/arch/memory.h>
+
+#include "map.h"
+
+#define MEMC_TABLE_SIZE (256*sizeof(unsigned long))
+#define PGD_TABLE_SIZE	(PTRS_PER_PGD * BYTES_PER_PTR)
+
+/*
+ * FIXME: the following over-allocates by 6400%
+ */
+static inline void *alloc_table(int size, int prio)
+{
+	if (size != 128)
+		printk("invalid table size\n");
+	return (void *)get_page_8k(prio);
+}
+
+/*
+ * Allocate a page table.  Note that we place the MEMC
+ * table before the page directory.  This means we can
+ * easily get to both tightly-associated data structures
+ * with a single pointer.  This function is slightly
+ * better - it over-allocates by only 711%
+ */
+static inline void *alloc_pgd_table(int priority)
+{
+	unsigned long pg8k;
+
+	pg8k = get_page_8k(priority);
+	if (pg8k)
+		pg8k += MEMC_TABLE_SIZE;
+
+	return (void *)pg8k;
+}
+
+void free_table(void *table)
+{
+	unsigned long tbl = (unsigned long)table;
+
+	tbl &= ~8191;
+	free_page_8k(tbl);
+}
+
+pgd_t *get_pgd_slow(void)
+{
+	pgd_t *pgd = (pgd_t *)alloc_pgd_table(GFP_KERNEL);
+	pmd_t *new_pmd;
+
+	if (pgd) {
+		pgd_t *init = pgd_offset(&init_mm, 0);
+		
+		memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+
+		/*
+		 * On ARM, first page must always be allocated
+		 */
+		if (!pmd_alloc(pgd, 0))
+			goto nomem;
+		else {
+			pmd_t *old_pmd = pmd_offset(init, 0);
+			new_pmd = pmd_offset(pgd, 0);
+
+			if (!pte_alloc(new_pmd, 0))
+				goto nomem_pmd;
+			else {
+				pte_t *new_pte = pte_offset(new_pmd, 0);
+				pte_t *old_pte = pte_offset(old_pmd, 0);
+
+				set_pte (new_pte, *old_pte);
+			}
+		}
+		/* update MEMC tables */
+		cpu_memc_update_all(pgd);
+	}
+	return pgd;
+
+nomem_pmd:
+	pmd_free(new_pmd);
+nomem:
+	free_table(pgd);
+	return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			set_pmd(pmd, mk_pmd(pte));
+			return pte + offset;
+		}
+		set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+		return NULL;
+	}
+	free_table((void *)pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pmd(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+/*
+ * This contains the code to setup the memory map on an ARM2/ARM250/ARM3
+ * machine. This is both processor & architecture specific, and requires
+ * some more work to get it to fit into our separate processor and
+ * architecture structure.
+ */
+int page_nr;
+
+#define PTE_SIZE	(PTRS_PER_PTE * BYTES_PER_PTR)
+
+static inline void setup_swapper_dir (int index, pte_t *ptep)
+{
+	set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep));
+}
+
+unsigned long __init
+setup_page_tables(unsigned long start_mem, unsigned long end_mem)
+{
+	unsigned int i;
+	union { unsigned long l; pte_t *pte; } u;
+
+	page_nr = MAP_NR(end_mem);
+
+	/* map in pages for (0x0000 - 0x8000) */
+	u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1));
+	start_mem = u.l + PTE_SIZE;
+	memzero (u.pte, PTE_SIZE);
+	u.pte[0] = mk_pte(PAGE_OFFSET + 491520, PAGE_READONLY);
+	setup_swapper_dir (0, u.pte);
+
+	for (i = 1; i < PTRS_PER_PGD; i++)
+		pgd_val(swapper_pg_dir[i]) = 0;
+
+	return start_mem;
+}
+
+unsigned long __init
+create_mem_holes(unsigned long start, unsigned long end)
+{
+	return start;
+}
+
+void __init
+mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem)
+{
+	while (start_mem < end_mem) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
+		start_mem += PAGE_SIZE;
+	}
+}
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- v2.3.22/linux/arch/arm/mm/mm-armv.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/mm-armv.c	Wed Oct 20 16:29:08 1999
@@ -1,72 +1,375 @@
 /*
  * arch/arm/mm/mm-armv.c
  *
- * Common routines for ARM v3 and v4 architectures.
+ * Page table sludge for ARM v3 and v4 processor architectures.
  *
- * Copyright (C) 1998 Russell King
- *
- * Do not compile this file directly!
+ * Copyright (C) 1998-1999 Russell King
  */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
 
-#ifndef MAPPING
-#error MAPPING not defined - do not compile this file individually
-#endif
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
 
-static const struct mapping {
-	unsigned long virtual;
-	unsigned long physical;
-	unsigned long length;
-	int domain:4,
-	    prot_read:1,
-	    prot_write:1;
-} mapping[] __initdata = {
-	MAPPING
-};
+#include "map.h"
+
+unsigned long *valid_addr_bitmap;
+
+/*
+ * need to get a 16k page for level 1
+ */
+pgd_t *get_pgd_slow(void)
+{
+	pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
+	pmd_t *new_pmd;
+
+	if (pgd) {
+		pgd_t *init = pgd_offset(&init_mm, 0);
+		
+		memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+		clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR);
+
+		/*
+		 * On ARM, first page must always be allocated
+		 */
+		if (!pmd_alloc(pgd, 0))
+			goto nomem;
+		else {
+			pmd_t *old_pmd = pmd_offset(init, 0);
+			new_pmd = pmd_offset(pgd, 0);
+
+			if (!pte_alloc(new_pmd, 0))
+				goto nomem_pmd;
+			else {
+				pte_t *new_pte = pte_offset(new_pmd, 0);
+				pte_t *old_pte = pte_offset(old_pmd, 0);
+
+				set_pte (new_pte, *old_pte);
+			}
+		}
+	}
+	return pgd;
+
+nomem_pmd:
+	pmd_free(new_pmd);
+nomem:
+	free_pages((unsigned long)pgd, 2);
+	return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *)get_page_2k(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
+			clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			pte += PTRS_PER_PTE;
+			set_pmd(pmd, mk_user_pmd(pte));
+			return pte + offset;
+		}
+		set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+		return NULL;
+	}
+	free_page_2k((unsigned long)pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pmd(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *)get_page_2k(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
+			clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			pte += PTRS_PER_PTE;
+			set_pmd(pmd, mk_kernel_pmd(pte));
+			return pte + offset;
+		}
+		set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+		return NULL;
+	}
+	free_page_2k((unsigned long)pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pmd_kernel(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+/*
+ * Create a SECTION PGD between VIRT and PHYS in domain
+ * DOMAIN with protection PROT
+ */
+static inline void
+alloc_init_section(unsigned long virt, unsigned long phys, int prot)
+{
+	pmd_t pmd;
+
+	pmd_val(pmd) = phys | prot;
+
+	set_pmd(pmd_offset(pgd_offset_k(virt), virt), pmd);
+}
+
+/*
+ * Add a PAGE mapping between VIRT and PHYS in domain
+ * DOMAIN with protection PROT.  Note that due to the
+ * way we map the PTEs, we must allocate two PTE_SIZE'd
+ * blocks - one for the Linux pte table, and one for
+ * the hardware pte table.
+ */
+static inline void
+alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
+{
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	pmdp = pmd_offset(pgd_offset_k(virt), virt);
+
+#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR)
+
+	if (pmd_none(*pmdp)) {
+		unsigned long memory = *mem;
+
+		memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1);
+
+		ptep = (pte_t *)memory;
+		memzero(ptep, PTE_SIZE);
+		memory += PTE_SIZE;
+
+		ptep = (pte_t *)memory;
+		memzero(ptep, PTE_SIZE);
+
+		set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
+
+		*mem = memory + PTE_SIZE;
+	}
 
-#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0]))
+#undef PTE_SIZE
 
-unsigned long __init setup_io_pagetables(unsigned long start_mem)
+	ptep = pte_offset(pmdp, virt);
+
+	set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
+}
+
+/*
+ * Clear any PGD mapping.  On a two-level page table system,
+ * the clearance is done by the middle-level functions (pmd)
+ * rather than the top-level (pgd) functions.
+ */
+static inline void
+free_init_section(unsigned long virt)
+{
+	pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
+}
+
+/*
+ * Create the page directory entries and any necessary
+ * page tables for the mapping specified by `md'.  We
+ * are able to cope here with varying sizes and address
+ * offsets, and we take full advantage of sections.
+ */
+static void __init
+create_mapping(unsigned long *mem_ptr, struct map_desc *md)
 {
-	const struct mapping *mp;
-	int i;
+	unsigned long virt, length;
+	int prot_sect, prot_pte;
+	long off;
+
+	prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+		   (md->prot_read  ? L_PTE_USER       : 0) |
+		   (md->prot_write ? L_PTE_WRITE      : 0) |
+		   (md->cacheable  ? L_PTE_CACHEABLE  : 0) |
+		   (md->bufferable ? L_PTE_BUFFERABLE : 0);
+
+	prot_sect = PMD_TYPE_SECT | PMD_DOMAIN(md->domain) |
+		    (md->prot_read  ? PMD_SECT_AP_READ    : 0) |
+		    (md->prot_write ? PMD_SECT_AP_WRITE   : 0) |
+		    (md->cacheable  ? PMD_SECT_CACHEABLE  : 0) |
+		    (md->bufferable ? PMD_SECT_BUFFERABLE : 0);
+
+	virt   = md->virtual;
+	off    = md->physical - virt;
+	length = md->length;
+
+	while ((virt & 1048575 || (virt + off) & 1048575) && length >= PAGE_SIZE) {
+		alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte);
 
-	for (i = 0, mp = mapping; i < SIZEOFMAP; i++, mp++) {
-		unsigned long virtual, physical, length;
-		int prot;
+		virt   += PAGE_SIZE;
+		length -= PAGE_SIZE;
+	}
+
+	while (length >= PGDIR_SIZE) {
+		alloc_init_section(virt, virt + off, prot_sect);
 
-		virtual = mp->virtual;
-		physical = mp->physical;
-		length = mp->length;
-		prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
-			| L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
+		virt   += PGDIR_SIZE;
+		length -= PGDIR_SIZE;
+	}
 
-		while ((virtual & 1048575 || physical & 1048575) && length >= PAGE_SIZE) {
-			alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
-			length -= PAGE_SIZE;
-			virtual += PAGE_SIZE;
-			physical += PAGE_SIZE;
+	while (length >= PAGE_SIZE) {
+		alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte);
+
+		virt   += PAGE_SIZE;
+		length -= PAGE_SIZE;
+	}
+}
+
+/*
+ * Initial boot-time mapping.  This covers just the
+ * zero page, kernel and the flush area.  NB: it
+ * must be sorted by virtual address, and no
+ * virtual address overlaps.
+ *  init_map[2..4] are for architectures with small
+ *  amounts of banked memory.
+ */
+static struct map_desc init_map[] __initdata = {
+	{ 0, 0, PAGE_SIZE,  DOMAIN_USER,   0, 0, 1, 0 }, /* zero page     */
+	{ 0, 0, 0,          DOMAIN_KERNEL, 0, 1, 1, 1 }, /* kernel memory */
+	{ 0, 0, 0,          DOMAIN_KERNEL, 0, 1, 1, 1 },
+	{ 0, 0, 0,          DOMAIN_KERNEL, 0, 1, 1, 1 },
+	{ 0, 0, 0,          DOMAIN_KERNEL, 0, 1, 1, 1 },
+	{ 0, 0, PGDIR_SIZE, DOMAIN_KERNEL, 1, 0, 1, 1 }, /* cache flush 1 */
+	{ 0, 0, 0,          DOMAIN_KERNEL, 1, 0, 1, 0 }  /* cache flush 2 */
+};
+
+#define NR_INIT_MAPS (sizeof(init_map) / sizeof(init_map[0]))
+
+unsigned long __init
+setup_page_tables(unsigned long start_mem, unsigned long end_mem)
+{
+	unsigned long address = 0;
+	int idx = 0;
+
+	/*
+	 * Correct the above mappings
+	 */
+	init_map[0].physical =
+	init_map[1].physical = __virt_to_phys(PAGE_OFFSET);
+	init_map[1].virtual  = PAGE_OFFSET;
+	init_map[1].length   = end_mem - PAGE_OFFSET;
+	init_map[5].physical = FLUSH_BASE_PHYS;
+	init_map[5].virtual  = FLUSH_BASE;
+#ifdef FLUSH_BASE_MINICACHE
+	init_map[6].physical = FLUSH_BASE_PHYS + PGDIR_SIZE;
+	init_map[6].virtual  = FLUSH_BASE_MINICACHE;
+	init_map[6].length   = PGDIR_SIZE;
+#endif
+
+	/*
+	 * Firstly, go through the initial mappings,
+	 * but clear out any pgdir entries that are
+	 * not in the description.
+	 */
+	do {
+		if (address < init_map[idx].virtual || idx == NR_INIT_MAPS) {
+			free_init_section(address);
+			address += PGDIR_SIZE;
+		} else {
+			create_mapping(&start_mem, init_map + idx);
+
+			address = init_map[idx].virtual + init_map[idx].length;
+			address = (address + PGDIR_SIZE - 1) & PGDIR_MASK;
+
+			do {
+				idx += 1;
+			} while (init_map[idx].length == 0 && idx < NR_INIT_MAPS);
 		}
+	} while (address != 0);
+
+	/*
+	 * Now, create the architecture specific mappings
+	 */
+	for (idx = 0; idx < io_desc_size; idx++)
+		create_mapping(&start_mem, io_desc + idx);
+
+	flush_cache_all();
+
+	return start_mem;
+}
+
+/*
+ * The mem_map array can get very big.  Mark the end of the
+ * valid mem_map banks with PG_skip, and setup the address
+ * validity bitmap.
+ */
+unsigned long __init
+create_mem_holes(unsigned long start_mem, unsigned long end_mem)
+{
+	struct page *pg = NULL;
+	unsigned int sz, i;
+
+	if (!machine_is_riscpc())
+		return start_mem;
+
+	sz = (end_mem - PAGE_OFFSET) >> 20;
+	sz = (sz + 31) >> 3;
 
-		prot = (mp->prot_read ? PMD_SECT_AP_READ : 0) |
-		       (mp->prot_write ? PMD_SECT_AP_WRITE : 0);
+	valid_addr_bitmap = (unsigned long *)start_mem;
+	start_mem += sz;
 
-		while (length >= 1048576) {
-			alloc_init_section(&start_mem, virtual, physical, mp->domain, prot);
-			length -= 1048576;
-			virtual += 1048576;
-			physical += 1048576;
+	memset(valid_addr_bitmap, 0, sz);
+
+	if (start_mem > mem_desc[0].virt_end)
+		printk(KERN_CRIT "*** Error: RAM bank 0 too small\n");
+
+	for (i = 0; i < mem_desc_size; i++) {
+		unsigned int idx, end;
+
+		if (pg) {
+			pg->next_hash = mem_map +
+				 MAP_NR(mem_desc[i].virt_start);
+			pg = NULL;
 		}
 
-		prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
-			| L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
+		idx = __kern_valid_idx(mem_desc[i].virt_start);
+		end = __kern_valid_idx(mem_desc[i].virt_end);
 
-		while (length >= PAGE_SIZE) {
-			alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
-			length -= PAGE_SIZE;
-			virtual += PAGE_SIZE;
-			physical += PAGE_SIZE;
+		do
+			set_bit(idx, valid_addr_bitmap);
+		while (++idx < end);
+
+		if (mem_desc[i].virt_end < end_mem) {
+			pg = mem_map + MAP_NR(mem_desc[i].virt_end);
+
+			set_bit(PG_skip, &pg->flags);
 		}
 	}
 
+	if (pg)
+		pg->next_hash = NULL;
+
 	return start_mem;
 }
+
+void __init
+mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem)
+{
+	/*
+	 * Mark all of memory from the end of kernel to end of memory
+	 */
+	while (start_mem < end_mem) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
+		start_mem += PAGE_SIZE;
+	}
+
+	/*
+	 * Mark memory from page 1 to start of the swapper page directory
+	 */
+	start_mem = PAGE_OFFSET + PAGE_SIZE;
+	while (start_mem < (unsigned long)&swapper_pg_dir) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
+		start_mem += PAGE_SIZE;
+	}
+}	
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c
--- v2.3.22/linux/arch/arm/mm/mm-ebsa110.c	Sun Sep  6 10:44:47 1998
+++ linux/arch/arm/mm/mm-ebsa110.c	Wed Oct 20 16:29:08 1999
@@ -3,19 +3,27 @@
  *
  * Extra MM routines for the EBSA-110 architecture
  *
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998-1999 Russell King
  */
-#include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/io.h>
-#include <asm/proc/mm-init.h>
+
+#include "map.h"
  
-#define MAPPING \
-	{ IO_BASE - PGDIR_SIZE	, 0xc0000000	, PGDIR_SIZE	, DOMAIN_IO, 0, 1 }, \
-	{ IO_BASE		, IO_START	, IO_SIZE	, DOMAIN_IO, 0, 1 }
+struct mem_desc mem_desc[] __initdata = {
+	0, 0
+};
+
+unsigned int __initdata mem_desc_size = 0;
+
+const struct map_desc io_desc[] __initdata = {
+	{ IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
+	{ IO_BASE             , IO_START  , IO_SIZE   , DOMAIN_IO, 0, 1, 0, 0 }
+};
+
+#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0]))
 
-#include "mm-armv.c"
+unsigned int __initdata io_desc_size = SIZEOFMAP;
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c
--- v2.3.22/linux/arch/arm/mm/mm-footbridge.c	Sat May  8 11:06:57 1999
+++ linux/arch/arm/mm/mm-footbridge.c	Wed Oct 20 16:29:08 1999
@@ -1,9 +1,9 @@
 /*
- * arch/arm/mm/mm-ebsa285.c
+ * arch/arm/mm/mm-footbridge.c
  *
  * Extra MM routines for the EBSA285 architecture
  *
- * Copyright (C) 1998 Russell King, Dave Gilbert.
+ * Copyright (C) 1998-1999 Russell King, Dave Gilbert.
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -13,9 +13,10 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/io.h>
-#include <asm/proc/mm-init.h>
 #include <asm/dec21285.h>
 
+#include "map.h"
+
 /*
  * The first entry allows us to fiddle with the EEPROM from user-space.
  *  This entry will go away in time, once the fmu32 can mmap() the
@@ -32,15 +33,15 @@
  * The mapping when the footbridge is in host mode.
  */
 #define MAPPING \
- { FLASH_BASE,   DC21285_FLASH,			FLASH_SIZE,	DOMAIN_IO, 0, 1 }, \
- { PCIMEM_BASE,  DC21285_PCI_MEM,		PCIMEM_SIZE,	DOMAIN_IO, 0, 1 }, \
- { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG,	PCICFG0_SIZE,	DOMAIN_IO, 0, 1 }, \
- { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG,	PCICFG1_SIZE,	DOMAIN_IO, 0, 1 }, \
- { PCIIACK_BASE, DC21285_PCI_IACK,		PCIIACK_SIZE,	DOMAIN_IO, 0, 1 }, \
- { WFLUSH_BASE,  DC21285_OUTBOUND_WRITE_FLUSH,	WFLUSH_SIZE,	DOMAIN_IO, 0, 1 }, \
- { ARMCSR_BASE,  DC21285_ARMCSR_BASE,		ARMCSR_SIZE,	DOMAIN_IO, 0, 1 }, \
- { PCIO_BASE,    DC21285_PCI_IO,		PCIO_SIZE,	DOMAIN_IO, 0, 1 }, \
- { XBUS_BASE,    0x40000000,			XBUS_SIZE,	DOMAIN_IO, 0, 1 }
+ { FLASH_BASE,   DC21285_FLASH,			FLASH_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCIMEM_BASE,  DC21285_PCI_MEM,		PCIMEM_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG,	PCICFG0_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG,	PCICFG1_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCIIACK_BASE, DC21285_PCI_IACK,		PCIIACK_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { WFLUSH_BASE,  DC21285_OUTBOUND_WRITE_FLUSH,	WFLUSH_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { ARMCSR_BASE,  DC21285_ARMCSR_BASE,		ARMCSR_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCIO_BASE,    DC21285_PCI_IO,		PCIO_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { XBUS_BASE,    0x40000000,			XBUS_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }
 
 #else
 
@@ -79,13 +80,26 @@
  * The mapping when the footbridge is in add-in mode.
  */
 #define MAPPING \
- { PCIO_BASE,	 DC21285_PCI_IO,		PCIO_SIZE,	DOMAIN_IO, 0, 1 }, \
- { XBUS_BASE,	 0x40000000,			XBUS_SIZE,	DOMAIN_IO, 0, 1 }, \
- { ARMCSR_BASE,  DC21285_ARMCSR_BASE,		ARMCSR_SIZE,	DOMAIN_IO, 0, 1 }, \
- { WFLUSH_BASE,	 DC21285_OUTBOUND_WRITE_FLUSH,	WFLUSH_SIZE,	DOMAIN_IO, 0, 1 }, \
- { FLASH_BASE,	 DC21285_FLASH,			FLASH_SIZE,	DOMAIN_IO, 0, 1 }, \
- { PCIMEM_BASE,	 DC21285_PCI_MEM,		PCIMEM_SIZE,	DOMAIN_IO, 0, 1 }
+ { PCIO_BASE,	 DC21285_PCI_IO,		PCIO_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { XBUS_BASE,	 0x40000000,			XBUS_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { ARMCSR_BASE,  DC21285_ARMCSR_BASE,		ARMCSR_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { WFLUSH_BASE,	 DC21285_OUTBOUND_WRITE_FLUSH,	WFLUSH_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { FLASH_BASE,	 DC21285_FLASH,			FLASH_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCIMEM_BASE,	 DC21285_PCI_MEM,		PCIMEM_SIZE,	DOMAIN_IO, 0, 1, 0, 0 }
 
 #endif
 
-#include "mm-armv.c"
+struct mem_desc mem_desc[] __initdata = {
+	0, 0
+};
+
+unsigned int __initdata mem_desc_size = 0;
+
+struct map_desc io_desc[] __initdata = {
+	MAPPING
+};
+
+#define SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+unsigned int __initdata io_desc_size = SIZE(io_desc);
+
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-nexuspci.c linux/arch/arm/mm/mm-nexuspci.c
--- v2.3.22/linux/arch/arm/mm/mm-nexuspci.c	Sat Jul 18 11:55:23 1998
+++ linux/arch/arm/mm/mm-nexuspci.c	Wed Oct 20 16:29:08 1999
@@ -5,7 +5,7 @@
  * Extra MM routines for the NexusPCI architecture
  *
  * Copyright (C) 1998 Phil Blundell
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998-1999 Russell King
  */
 
 #include <linux/sched.h>
@@ -15,13 +15,23 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/io.h>
-#include <asm/proc/mm-init.h>
+
+#include "map.h"
  
-#define MAPPING								\
- 	{ 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffc00000, 0x60000000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xfe000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xfd000000, 0x88000000, 0x00100000, DOMAIN_IO, 0, 1 }
+struct mem_desc mem_desc[] __initdata = {
+	0, 0
+};
+
+unsigned int __initdata mem_desc_size = 0;
+
+const struct map_desc io_desc[] __initdata = {
+ 	{ 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffc00000, 0x60000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xfe000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xfd000000, 0x88000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }
+};
+
+#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0]))
 
-#include "mm-armv.c"
+unsigned int __initdata io_desc_size = SIZEOFMAP;
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c
--- v2.3.22/linux/arch/arm/mm/mm-rpc.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/mm-rpc.c	Wed Oct 20 16:29:08 1999
@@ -3,95 +3,48 @@
  *
  * Extra MM routines for RiscPC architecture
  *
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998-1999 Russell King
  */
-#include <linux/sched.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 
-#include <asm/pgtable.h>
+#include <asm/hardware.h>
+#include <asm/page.h>
+#include <asm/proc/domain.h>
 #include <asm/setup.h>
-#include <asm/io.h>
-#include <asm/proc/mm-init.h>
-#include <asm/arch/mm-init.h>
 
-#define NR_DRAM_BANKS	4
-#define NR_VRAM_BANKS	1
+#include "map.h"
 
-#define NR_BANKS	(NR_DRAM_BANKS + NR_VRAM_BANKS)
+#define SIZE(x) (sizeof(x) / sizeof(x[0]))
 
-#define FIRST_BANK	0
-#define FIRST_DRAM_BANK	0
-#define FIRST_VRAM_BANK	NR_DRAM_BANKS
-
-#define BANK_SHIFT	26
-#define FIRST_DRAM_ADDR	0x10000000
-
-#define PHYS_TO_BANK(x)	(((x) >> BANK_SHIFT) & (NR_DRAM_BANKS - 1))
-#define BANK_TO_PHYS(x)	((FIRST_DRAM_ADDR) + \
-			    (((x) - FIRST_DRAM_BANK) << BANK_SHIFT))
-
-struct ram_bank {
-	unsigned int virt_addr;		/* virtual address of the *end* of this bank + 1 */
-	  signed int phys_offset;	/* offset to physical address of this bank */
+struct mem_desc mem_desc[] __initdata = {
+	{ 0xc0000000, 0xc0000000 },
+	{ 0xc4000000, 0xc4000000 },
+	{ 0xc8000000, 0xc8000000 },
+	{ 0xcc000000, 0xcc000000 }
 };
 
-static struct ram_bank rambank[NR_BANKS];
-
-/*
- * Return the physical (0x10000000 -> 0x20000000) address of
- * the virtual (0xc0000000 -> 0xd0000000) address
- */
-unsigned long __virt_to_phys(unsigned long vpage)
-{
-	unsigned int bank = FIRST_BANK;
-
-	while (vpage >= rambank[bank].virt_addr && bank < NR_BANKS)
-		bank ++;
-
-	return vpage - rambank[bank].phys_offset;
-}
-
-/*
- * Return the virtual (0xc0000000 -> 0xd0000000) address of
- * the physical (0x10000000 -> 0x20000000) address
- */
-unsigned long __phys_to_virt(unsigned long phys)
-{
-	unsigned int bank;
-
-	if (phys > FIRST_DRAM_ADDR)
-		bank = PHYS_TO_BANK(phys);
-	else
-		bank = FIRST_VRAM_BANK;
-
-	return phys + rambank[bank].phys_offset;
-}
+unsigned int __initdata mem_desc_size = SIZE(mem_desc);
 
 void __init
 init_dram_banks(struct param_struct *params)
 {
 	unsigned int bank;
-	unsigned int bytes = 0;
 
-	for (bank = FIRST_DRAM_BANK; bank < NR_DRAM_BANKS; bank++) {
-		rambank[bank].phys_offset = PAGE_OFFSET + bytes
-						- BANK_TO_PHYS(bank);
+	for (bank = 0; bank < mem_desc_size; bank++)
+		mem_desc[bank].virt_end += PAGE_SIZE *
+				  params->u1.s.pages_in_bank[bank];
 
-		bytes += params->u1.s.pages_in_bank[bank - FIRST_DRAM_BANK] * PAGE_SIZE;
-
-		rambank[bank].virt_addr   = PAGE_OFFSET + bytes;
-	}
-
-	rambank[FIRST_VRAM_BANK].phys_offset = 0xd6000000;
-	rambank[FIRST_VRAM_BANK].virt_addr   = 0xd8000000;
+	params->u1.s.nr_pages = mem_desc[3].virt_end - PAGE_OFFSET;
+	params->u1.s.nr_pages /= PAGE_SIZE;
 }
 
-#define MAPPING \
-	{ SCREEN2_BASE,	SCREEN_START,	2*1048576, DOMAIN_IO, 0, 1 },	/* VRAM		*/ \
-	{ IO_BASE,	IO_START,	IO_SIZE	 , DOMAIN_IO, 0, 1 },	/* IO space	*/ \
-	{ EASI_BASE,	EASI_START,	EASI_SIZE, DOMAIN_IO, 0, 1 }	/* EASI space	*/
-/*
- * Include common routine to set up page tables
- */
-#include "mm-armv.c"
+struct map_desc io_desc[] __initdata = {
+	/* VRAM		*/
+	{ SCREEN2_BASE,	SCREEN_START,	2*1048576, DOMAIN_IO, 0, 1, 0, 0 },
+	/* IO space	*/
+	{ IO_BASE,	IO_START,	IO_SIZE	 , DOMAIN_IO, 0, 1, 0, 0 },
+	/* EASI space	*/
+	{ EASI_BASE,	EASI_START,	EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 }
+};
+
+unsigned int __initdata io_desc_size = SIZE(io_desc);
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c
--- v2.3.22/linux/arch/arm/mm/mm-sa1100.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/mm-sa1100.c	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mm/mm-sa1100.c
+ *
+ * Extra MM routines for the SA1100 architecture
+ *
+ * Copyright (C) 1998-1999 Russell King
+ * Copyright (C) 1999 Hugo Fiennes
+ *
+ * 1999/09/12 Nicolas Pitre <nico@visuaide.com>
+ *	Specific RAM implementation details are in
+ *	linux/include/asm/arch-sa1100/memory.h now.
+ *	Allows for better macro optimisations when possible.
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include "map.h"
+ 
+#define SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+/*
+ * These are the memory size mappings for the
+ * SA1100.  Note that LART is a special case -
+ * it doesn't use physical address A23 on the
+ * DRAM, so we effectively have 4 * 8MB in
+ * two banks.
+ */
+struct mem_desc mem_desc[] __initdata = {
+	/* virt start virt end */
+#if defined(CONFIG_SA1100_BRUTUS)
+	{ 0xc0000000, 0xc0400000 },	/* 4MB */
+	{ 0xc1000000, 0xc1400000 },	/* 4MB */
+	{ 0xc2000000, 0xc2400000 },	/* 4MB */
+	{ 0xc3000000, 0xc3400000 }	/* 4MB */
+#elif defined(CONFIG_SA1100_EMPEG)
+	{ 0xc0000000, 0xc0400000 },	/* 4MB */
+	{ 0xc1000000, 0xc1400000 }	/* 4MB */
+#elif defined(CONFIG_SA1100_LART)
+	{ 0xc0000000, 0xc0800000 },	/* 16MB */
+	{ 0xc1000000, 0xc1800000 },
+	{ 0xc2000000, 0xc2800000 },	/* 16MB */
+	{ 0xc3000000, 0xc3800000 }
+#elif defined(CONFIG_SA1100_VICTOR)
+	{ 0xc0000000, 0xc0400000 }	/* 4MB */
+#elif defined(CONFIG_SA1100_TIFON)
+	{ 0xc0000000, 0xc1000000 },	/* 16MB */
+	{ 0xc1000000, 0xc2000000 }	/* 16MB */
+#else
+#error missing memory configuration
+#endif
+};
+
+unsigned int __initdata mem_desc_size = SIZE(mem_desc);
+
+struct map_desc io_desc[] __initdata = {
+	/* virtual           physical     length     domain    r  w  c  b */
+#if defined(CONFIG_SA1100_VICTOR)
+	{ 0xd0000000,      0x00000000,  0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+#elif defined(CONFIG_SA1100_EMPEG)
+	{ EMPEG_FLASHBASE, 0x00000000,  0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+#elif defined(CONFIG_SA1100_TIFON)
+	{ 0xd0000000,      0x00000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+	{ 0xd0800000,      0x08000000,  0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
+#endif
+#ifdef CONFIG_SA1101
+	{ 0xdc000000,      SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */
+#endif
+	{ 0xe0000000,      0x20000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
+	{ 0xe4000000,      0x30000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
+	{ 0xe8000000,      0x28000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */
+	{ 0xec000000,      0x38000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */
+	{ 0xf0000000,      0x2c000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */
+	{ 0xf4000000,      0x3c000000,  0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */
+	{ 0xf8000000,      0x80000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
+	{ 0xfa000000,      0x90000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
+	{ 0xfc000000,      0xa0000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
+	{ 0xfe000000,      0xb0000000,  0x02000000, DOMAIN_IO, 0, 1, 0, 0 }  /* LCD + DMA */
+};
+
+unsigned int __initdata io_desc_size = SIZE(io_desc);
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/mm-tbox.c linux/arch/arm/mm/mm-tbox.c
--- v2.3.22/linux/arch/arm/mm/mm-tbox.c	Sat Jul 18 11:55:23 1998
+++ linux/arch/arm/mm/mm-tbox.c	Wed Oct 20 16:29:08 1999
@@ -5,7 +5,7 @@
  * Extra MM routines for the Tbox architecture
  *
  * Copyright (C) 1998 Phil Blundell
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998-1999 Russell King
  */
 
 #include <linux/sched.h>
@@ -15,9 +15,15 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <asm/proc/mm-init.h>
- 
+
+#include "map.h"
  
+struct mem_desc mem_desc[] __initdata = {
+	0, 0
+};
+
+unsigned int __initdata mem_desc_size = 0;
+
 /*    Logical    Physical
  * 0xffff1000	0x00100000	DMA registers
  * 0xffff2000	0x00200000	MPEG
@@ -34,23 +40,26 @@
  * 0xffffd000	0x00d00000	Interrupt reset
  * 0xffffe000	0x00e00000	MPEG DMA throttle
  */
- 
-#define MAPPING								\
-  	{ 0xffff0000, 0x01000000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff1000, 0x00100000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff2000, 0x00200000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff3000, 0x00300000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff4000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xfe000000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff5000, 0x00500000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff6000, 0x00600000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff7000, 0x00700000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff8000, 0x00800000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffff9000, 0x00900000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffffa000, 0x00a00000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffffb000, 0x00b00000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffffc000, 0x00c00000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffffd000, 0x00d00000, 0x00001000, DOMAIN_IO, 0, 1 },	\
- 	{ 0xffffe000, 0x00e00000, 0x00001000, DOMAIN_IO, 0, 1 }
 
-#include "mm-armv.c"
+const struct map_desc io_desc[] __initdata = {
+  	{ 0xffff0000, 0x01000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff1000, 0x00100000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff2000, 0x00200000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff3000, 0x00300000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff4000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xfe000000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff5000, 0x00500000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff6000, 0x00600000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff7000, 0x00700000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff8000, 0x00800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffff9000, 0x00900000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffffa000, 0x00a00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffffb000, 0x00b00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffffc000, 0x00c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffffd000, 0x00d00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
+ 	{ 0xffffe000, 0x00e00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }
+};
+
+#define SIZEOFMAP (sizeof(mapping) / sizeof(mapping[0]))
+
+unsigned int __initdata io_desc_size = SIZEOFMAP;
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S
--- v2.3.22/linux/arch/arm/mm/proc-arm2,3.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/proc-arm2,3.S	Wed Oct 20 16:29:08 1999
@@ -12,349 +12,184 @@
 #include "../lib/constants.h"
 
 /*
- * Code common to all processors - MEMC specific not processor
- * specific!
+ * MEMC workhorse code.  It's both a horse which things it's a pig.
  */
-
-LC1:		.word	SYMBOL_NAME(page_nr)
 /*
- * Function: arm2_3_update_map (struct task_struct *tsk)
- *
- * Params  : tsk	Task structure to be updated
- *
- * Purpose : Re-generate memc maps for task from its pseudo page tables
- */
-_arm2_3_update_map:
-		mov	ip, sp
-		stmfd	sp!, {r4 - r6, fp, ip, lr, pc}
-		sub	fp, ip, #4
-		add	r1, r0, #TSS_MEMCMAP
-		ldr	r2, LC1
-		ldr	r2, [r2]
-		mov	r3, #0x03f00000
-		orr	r3, r3, #0x00000f00
-		orr	r4, r3, #1
-		orr	r5, r3, #2
-		orr	r6, r3, #3
-1:		stmia	r1!, {r3, r4, r5, r6}		@ Default mapping (null mapping)
-		add	r3, r3, #4
-		add	r4, r4, #4
-		add	r5, r5, #4
-		add	r6, r6, #4
-		stmia	r1!, {r3, r4, r5, r6}		@ Default mapping (null mapping)
-		add	r3, r3, #4
-		add	r4, r4, #4
-		add	r5, r5, #4
-		add	r6, r6, #4
-		subs	r2, r2, #8
-		bhi	1b
-
-		adr	r2, Lphystomemc32		@ r2 = conversion table to logical page number
-		ldr	r4, [r0, #TSS_MEMMAP]		@ r4 = active mem map
-		add	r5, r4, #32 << 2		@ r5 = end of active mem map
-		add	r0, r0, #TSS_MEMCMAP		@ r0 = memc map
-
-		mov	r6, #0
-2:		ldmia	r4!, {r1, r3}
-		tst	r1, #PAGE_PRESENT
-		blne	update_map_pgd
-		add	r6, r6, #32 << 2
-		tst	r3, #PAGE_PRESENT
-		blne	update_map_pgd3
-		add	r6, r6, #32 << 2
-		cmp	r4, r5
-		blt	2b
-		ldmea	fp, {r4 - r6, fp, sp, pc}^
-
-@ r0,r2,r3,r4,r5 = preserve
-@ r1,ip = available
-@ r0 = memc map
-@ r1 = pgd entry
-@ r2 = conversion table
-@ r6 = logical page no << 2
-
-update_map_pgd3:
-		mov	r1, r3
-update_map_pgd: stmfd	sp!, {r3, r4, r5, lr}
-		bic	r4, r1, #3			@ r4 = page table
-		sub	r5, r6, #1 << 2
-		add	ip, r4, #32 << 2		@ ip = end of page table
-
-1:		ldr	r1, [r4], #4			@ get entry
-		add	r5, r5, #1 << 2
-		tst	r1, #PAGE_PRESENT		@ page present?
-		blne	Lconvertmemc			@ yes
-		ldr	r1, [r4], #4			@ get entry
-		add	r5, r5, #1 << 2
-		tst	r1, #PAGE_PRESENT		@ page present?
-		blne	Lconvertmemc			@ yes
-		ldr	r1, [r4], #4			@ get entry
-		add	r5, r5, #1 << 2
-		tst	r1, #PAGE_PRESENT		@ page present?
-		blne	Lconvertmemc			@ yes
-		ldr	r1, [r4], #4			@ get entry
-		add	r5, r5, #1 << 2
-		tst	r1, #PAGE_PRESENT		@ page present?
-		blne	Lconvertmemc			@ yes
-		cmp	r4, ip
-		blt	1b
-		ldmfd	sp!, {r3, r4, r5, pc}^
-
-Lconvertmemc:	mov	r3, r1, lsr #13			@
-		and	r3, r3, #0x3fc			@ Convert to memc physical page no
-		ldr	r3, [r2, r3]			@
-
-		tst	r1, #PAGE_OLD|PAGE_NOT_USER	@ check for MEMC read
-		biceq	r3, r3, #0x200			@
-		tsteq	r1, #PAGE_READONLY|PAGE_CLEAN	@ check for MEMC write
-		biceq	r3, r3, #0x300			@
-
-		orr	r3, r3, r5, lsl #13
-		and	r1, r5, #0x01800000 >> 13
-		orr	r3, r3, r1
-
-		and	r1, r3, #255
-		str	r3, [r0, r1, lsl #2]
-		movs	pc, lr
-
-/*
- * Function: arm2_3_update_cache (struct task_struct *tsk, unsigned long addr, pte_t pte)
- * Params  : tsk      Task to update
- *	     address  Address of fault.
- *	     pte      New PTE at address
- * Purpose : Update the mapping for this address.
- * Notes   : does the ARM3 run faster if you do not use the result in the next instruction?
- */
-_arm2_3_update_cache:
-		tst	r2, #PAGE_PRESENT
-		moveqs	pc, lr
-		mov	r3, r2, lsr #13			@ Physical page no.
-		adr	ip, Lphystomemc32		@ Convert to logical page number
+ * Function: cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long addr)
+ * Params  : pgd	Page tables/MEMC mapping
+ *         : phys_pte	physical address, or PTE
+ *         : addr	virtual address
+ */
+ENTRY(cpu_memc_update_entry)
+		tst	r1, #PAGE_PRESENT		@ is the page present
+		orreq	r1, r1, #PAGE_OLD | PAGE_CLEAN
+		moveq	r2, #0x01f00000
+		mov	r3, r1, lsr #13			@ convert to physical page nr
 		and	r3, r3, #0x3fc
-		mov	r1, r1, lsr #15
-		ldr	r3, [ip, r3]			@ Convert to memc phys page no.
-		tst	r2, #PAGE_OLD|PAGE_NOT_USER
+		adr	ip, memc_phys_table_32
+		ldr	r3, [ip, r3]
+		tst	r1, #PAGE_OLD | PAGE_NOT_USER
 		biceq	r3, r3, #0x200
-		tsteq	r2, #PAGE_READONLY|PAGE_CLEAN
+		tsteq	r1, #PAGE_READONLY | PAGE_CLEAN
 		biceq	r3, r3, #0x300
-		mov	ip, sp, lsr #13
-		orr	r3, r3, r1, lsl #15
-		mov	ip, ip, lsl #13
-		and	r1, r1, #0x300
-		teq	ip, r0
-		orr	r3, r3, r1, lsl #2
-		add	r0, r0, #TSS_MEMCMAP
+		mov	r2, r2, lsr #15			@ virtual -> nr
+		orr	r3, r3, r2, lsl #15
+		and	r2, r2, #0x300
+		orr	r3, r3, r2, lsl #2
 		and	r2, r3, #255
-		streqb	r3, [r3]
+		sub	r0, r0, #256 * 4
 		str	r3, [r0, r2, lsl #2]
-		movs    pc, lr
-
-#define PCD(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \
-		.long	a0| 0x03800300; .long	a1| 0x03800300;\
-		.long	a2| 0x03800300; .long	a3| 0x03800300;\
-		.long	a4| 0x03800300; .long	a5| 0x03800300;\
-		.long	a6| 0x03800300; .long	a7| 0x03800300;\
-		.long	a8| 0x03800300; .long	a9| 0x03800300;\
-		.long	aa| 0x03800300; .long	ab| 0x03800300;\
-		.long	ac| 0x03800300; .long	ad| 0x03800300;\
-		.long	ae| 0x03800300; .long	af| 0x03800300
-
-@ Table to map from page number to vidc page number
-Lphystomemc32:	PCD(0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78)
-		PCD(0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39,0x41,0x49,0x51,0x59,0x61,0x69,0x71,0x79)
-		PCD(0x04,0x0C,0x14,0x1C,0x24,0x2C,0x34,0x3C,0x44,0x4C,0x54,0x5C,0x64,0x6C,0x74,0x7C)
-		PCD(0x05,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7D)
-		PCD(0x02,0x0A,0x12,0x1A,0x22,0x2A,0x32,0x3A,0x42,0x4A,0x52,0x5A,0x62,0x6A,0x72,0x7A)
-		PCD(0x03,0x0B,0x13,0x1B,0x23,0x2B,0x33,0x3B,0x43,0x4B,0x53,0x5B,0x63,0x6B,0x73,0x7B)
-		PCD(0x06,0x0E,0x16,0x1E,0x26,0x2E,0x36,0x3E,0x46,0x4E,0x56,0x5E,0x66,0x6E,0x76,0x7E)
-		PCD(0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F)
-		PCD(0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8)
-		PCD(0x81,0x89,0x91,0x99,0xA1,0xA9,0xB1,0xB9,0xC1,0xC9,0xD1,0xD9,0xE1,0xE9,0xF1,0xF9)
-		PCD(0x84,0x8C,0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,0xE4,0xEC,0xF4,0xFC)
-		PCD(0x85,0x8D,0x95,0x9D,0xA5,0xAD,0xB5,0xBD,0xC5,0xCD,0xD5,0xDD,0xE5,0xED,0xF5,0xFD)
-		PCD(0x82,0x8A,0x92,0x9A,0xA2,0xAA,0xB2,0xBA,0xC2,0xCA,0xD2,0xDA,0xE2,0xEA,0xF2,0xFA)
-		PCD(0x83,0x8B,0x93,0x9B,0xA3,0xAB,0xB3,0xBB,0xC3,0xCB,0xD3,0xDB,0xE3,0xEB,0xF3,0xFB)
-		PCD(0x86,0x8E,0x96,0x9E,0xA6,0xAE,0xB6,0xBE,0xC6,0xCE,0xD6,0xDE,0xE6,0xEE,0xF6,0xFE)
-		PCD(0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF)
-
-/*
- * Function: arm2_3_data_abort ()
- *
- * Params  : r0 = address of aborted instruction
- *
- * Purpose :
- *
- * Returns : r0 = address of abort
- *	   : r1 = FSR
- *	   : r2 != 0 if writing
- */
-
-_arm2_3_data_abort:
+		strb	r3, [r3]
 		movs	pc, lr
-
-_arm2_3_check_bugs:
-		bics	pc, lr, #0x04000000		@ Clear FIQ disable bit
-
-/*
- * Processor specific - ARM2
- */
-
-LC0:		.word	SYMBOL_NAME(page_nr)
 /*
- * Function: arm2_switch_to (struct task_struct *prev, struct task_struct *next)
- * Params  : prev	Old task structure
- *	   : next	New task structure for process to run
- * Returns : prev
- * Purpose : Perform a task switch, saving the old processes state, and restoring
- *	     the new.
- * Notes   : We don't fiddle with the FP registers here - we postpone this until
- *	     the new task actually uses FP.  This way, we don't swap FP for tasks
- *	     that do not require it.
- */
-_arm2_switch_to:
-		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
-		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
-		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		mov	r4, r1
-		add	r7, r1, #TSS_MEMCMAP		@ Remap MEMC
-		ldr	r1, LC0
-		ldr	r1, [r1]
-1:		ldmia	r7!, {r2, r3, r5, r6}
-		strb	r2, [r2]
-		strb	r3, [r3]
-		strb	r5, [r5]
-		strb	r6, [r6]
-		ldmia	r7!, {r2, r3, r5, r6}
-		strb	r2, [r2]
-		strb	r3, [r3]
-		strb	r5, [r5]
-		strb	r6, [r6]
-		subs	r1, r1, #8
-		bhi	1b
-		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
-
-/*
- * Function: arm2_remap_memc (struct task_struct *tsk)
- *
- * Params  : tsk	Task structure specifing the new mapping structure
- *
- * Purpose : remap MEMC tables
- */
-_arm2_remap_memc:
-		stmfd	sp!, {lr}
-		add	r0, r0, #TSS_MEMCMAP
-		ldr	r1, LC0
-		ldr	r1, [r1]
-1:		ldmia	r0!, {r2, r3, ip, lr}
-		strb	r2, [r2]
-		strb	r3, [r3]
-		strb	ip, [ip]
-		strb	lr, [lr]
-		ldmia	r0!, {r2, r3, ip, lr}
-		strb	r2, [r2]
-		strb	r3, [r3]
-		strb	ip, [ip]
-		strb	lr, [lr]
-		subs	r1, r1, #8
-		bhi	1b
-		ldmfd	sp!, {pc}^
+ * Params  : r0 = preserved
+ *         : r1 = memc table base (preserved)
+ *         : r2 = page table entry
+ *         : r3 = preserved
+ *         : r4 = unused
+ *         : r5 = memc physical address translation table
+ *         : ip = virtual address (preserved)
+ */
+update_pte:
+		mov	r4, r2, lsr #13
+		and	r4, r4, #0x3fc
+		ldr	r4, [r5, r4]			@ covert to MEMC page
+
+		tst	r2, #PAGE_OLD | PAGE_NOT_USER	@ check for MEMC read
+		biceq	r4, r4, #0x200
+		tsteq	r2, #PAGE_READONLY | PAGE_CLEAN	@ check for MEMC write
+		biceq	r4, r4, #0x300
+
+		orr	r4, r4, ip
+		and	r2, ip, #0x01800000
+		orr	r4, r4, r2, lsr #13
 
-/*
- * Function: arm2_xchg_1 (int new, volatile void *ptr)
- *
- * Params  : new	New value to store at...
- *	   : ptr	pointer to byte-wide location
- *
- * Purpose : Performs an exchange operation
- *
- * Returns : Original byte data at 'ptr'
- *
- * Notes   : This will have to be changed if we ever use multi-processing using these
- *	     processors, but that is very unlikely...
- */
-_arm2_xchg_1:	mov	r2, pc
-		orr	r2, r2, #I_BIT
-		teqp	r2, #0
-		ldrb	r2, [r1]
-		strb	r0, [r1]
-		mov	r0, r2
+		and	r2, r4, #255
+		str	r4, [r1, r2, lsl #2]
 		movs	pc, lr
 
 /*
- * Function: arm2_xchg_4 (int new, volatile void *ptr)
- *
- * Params  : new	New value to store at...
- *	   : ptr	pointer to word-wide location
- *
- * Purpose : Performs an exchange operation
- *
- * Returns : Original word data at 'ptr'
- *
- * Notes   : This will have to be changed if we ever use multi-processing using these
- *	     processors, but that is very unlikely...
+ * Params  : r0 = preserved
+ *         : r1 = memc table base (preserved)
+ *         : r2 = page table base
+ *         : r3 = preserved
+ *         : r4 = unused
+ *         : r5 = memc physical address translation table
+ *         : ip = virtual address (updated)
+ */
+update_pte_table:
+		stmfd	sp!, {r0, lr}
+		bic	r0, r2, #3
+1:		ldr	r2, [r0], #4			@ get entry
+		tst	r2, #PAGE_PRESENT		@ page present
+		blne	update_pte			@ process pte
+		add	ip, ip, #32768			@ increment virt addr
+		ldr	r2, [r0], #4			@ get entry
+		tst	r2, #PAGE_PRESENT		@ page present
+		blne	update_pte			@ process pte
+		add	ip, ip, #32768			@ increment virt addr
+		ldr	r2, [r0], #4			@ get entry
+		tst	r2, #PAGE_PRESENT		@ page present
+		blne	update_pte			@ process pte
+		add	ip, ip, #32768			@ increment virt addr
+		ldr	r2, [r0], #4			@ get entry
+		tst	r2, #PAGE_PRESENT		@ page present
+		blne	update_pte			@ process pte
+		add	ip, ip, #32768			@ increment virt addr
+		tst	ip, #32768 * 31			@ finished?
+		bne	1b
+		ldmfd	sp!, {r0, pc}^
+
+/*
+ * Function: cpu_memc_update_all(pgd_t *pgd)
+ * Params  : pgd	Page tables/MEMC mapping
+ * Notes   : this is optimised for 32k pages
+ */
+ENTRY(cpu_memc_update_all)
+		stmfd	sp!, {r4, r5, lr}
+		bl	clear_tables
+		sub	r1, r0, #256 * 4		@ start of MEMC tables
+		adr	r5, memc_phys_table_32		@ Convert to logical page number
+		mov	ip, #0				@ virtual address
+1:		ldmia	r0!, {r2, r3}
+		tst	r2, #PAGE_PRESENT
+		addeq	ip, ip, #1048576
+		blne	update_pte_table
+		mov	r2, r3
+		tst	r2, #PAGE_PRESENT
+		addeq	ip, ip, #1048576
+		blne	update_pte_table
+		teq	ip, #32 * 1048576
+		bne	1b
+		ldmfd	sp!, {r4, r5, pc}^
+
+/*
+ * Build the table to map from physical page number to memc page number
+ */
+		.type	memc_phys_table_32, #object
+memc_phys_table_32:
+		.irp	b7, 0x00, 0x80
+		.irp	b6, 0x00, 0x02
+		.irp	b5, 0x00, 0x04
+		.irp	b4, 0x00, 0x01
+
+		.irp	b3, 0x00, 0x40
+		.irp	b2, 0x00, 0x20
+		.irp	b1, 0x00, 0x10
+		.irp	b0, 0x00, 0x08
+		.long	0x03800300 + \b7 + \b6 + \b5 + \b4 + \b3 + \b2 + \b1 + \b0
+		.endr
+		.endr
+		.endr
+		.endr
+
+		.endr
+		.endr
+		.endr
+		.endr
+		.size	memc_phys_table_32, . - memc_phys_table_32
+
+/*
+ * helper for cpu_memc_update_all, this clears out all
+ * mappings, setting them close to the top of memory,
+ * and inaccessible (0x01f00000).
+ * Params  : r0 = page table pointer
  */
-_arm2_xchg_4:	mov	r2, pc
-		orr	r2, r2, #I_BIT
-		teqp	r2, #0
+clear_tables:	ldr	r1, _arm3_set_pgd - 4
 		ldr	r2, [r1]
-		str	r0, [r1]
-		mov	r0, r2
-/*
- * fall through
- */
-/*
- * Function: arm2_proc_init (void)
- *	   : arm2_proc_fin (void)
- *
- * Purpose : Initialise / finalise processor specifics (none required)
- */
-_arm2_proc_init:
-_arm2_proc_fin:	movs	pc, lr
+		sub	r1, r0, #256 * 4		@ start of MEMC tables
+		add	r2, r1, r2, lsl #2		@ end of tables
+		mov	r3, #0x03f00000			@ Default mapping (null mapping)
+		orr	r3, r3, #0x00000f00
+		orr	r4, r3, #1
+		orr	r5, r3, #2
+		orr	ip, r3, #3
+1:		stmia	r1!, {r3, r4, r5, ip}
+		add	r3, r3, #4
+		add	r4, r4, #4
+		add	r5, r5, #4
+		add	ip, ip, #4
+		stmia	r1!, {r3, r4, r5, ip}
+		add	r3, r3, #4
+		add	r4, r4, #4
+		add	r5, r5, #4
+		add	ip, ip, #4
+		teq	r1, r2
+		bne	1b
+		mov	pc, lr
+
 /*
- * Function: arm3_switch_to (struct task_struct *prev, struct task_struct *next)
- * Params  : prev	Old task structure
- *	   : next	New task structure for process to run
- * Returns : prev
- * Purpose : Perform a task switch, saving the old processes state, and restoring
- *	     the new.
- * Notes   : We don't fiddle with the FP registers here - we postpone this until
- *	     the new task actually uses FP.  This way, we don't swap FP for tasks
- *	     that do not require it.
- */
-_arm3_switch_to:
-		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
-		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
-		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		mov	r4, r1
-		add	r7, r1, #TSS_MEMCMAP		@ Remap MEMC
-		ldr	r1, LC0
-		ldr	r1, [r1]
-1:		ldmia	r7!, {r2, r3, r5, r6}
-		strb	r2, [r2]
-		strb	r3, [r3]
-		strb	r5, [r5]
-		strb	r6, [r6]
-		ldmia	r7!, {r2, r3, r5, r6}
-		strb	r2, [r2]
-		strb	r3, [r3]
-		strb	r5, [r5]
-		strb	r6, [r6]
-		subs	r1, r1, #8
-		bhi	1b
-		mcr	p15, 0, r7, c1, c0, 0		@ flush cache
-		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
-/*
- * Function: arm3_remap_memc (struct task_struct *tsk)
- *
- * Params  : tsk	Task structure specifing the new mapping structure
- *
- * Purpose : remap MEMC tables
- */
-_arm3_remap_memc:
-		stmfd	sp!, {lr}
-		add	r0, r0, #TSS_MEMCMAP
-		ldr	r1, LC0
-		ldr	r1, [r1]
+ * Function: *_set_pgd(pgd_t *pgd)
+ * Params  : pgd	New page tables/MEMC mapping
+ * Purpose : update MEMC hardware with new mapping
+ */
+		.word	SYMBOL_NAME(page_nr)
+_arm3_set_pgd:	mcr	p15, 0, r1, c1, c0, 0		@ flush cache
+_arm2_set_pgd:	stmfd	sp!, {lr}
+		ldr	r1, _arm3_set_pgd - 4
+		ldr	r2, [r1]
+		sub	r0, r0, #256 * 4		@ start of MEMC tables
+		add	r1, r0, r2, lsl #2		@ end of tables
 1:		ldmia	r0!, {r2, r3, ip, lr}
 		strb	r2, [r2]
 		strb	r3, [r3]
@@ -365,14 +200,12 @@
 		strb	r3, [r3]
 		strb	ip, [ip]
 		strb	lr, [lr]
-		subs	r1, r1, #8
-		bhi	1b
-		mcr	p15, 0, r0, c1, c0, 0		@ flush cache
+		teq	r0, r1
+		bne	1b
 		ldmfd	sp!, {pc}^
 
 /*
- * Function: arm3_proc_init (void)
- *
+ * Function: *_proc_init (void)
  * Purpose : Initialise the cache control registers
  */
 _arm3_proc_init:
@@ -386,43 +219,55 @@
 		mcr     p15, 0, r0, c1, c0		@ ARM3 Flush
 		mov	r0, #3
 		mcr     p15, 0, r0, c2, c0		@ ARM3 Control
+_arm2_proc_init:
 		movs	pc, lr
 
 /*
- * Function: arm3_proc_fin (void)
- *
+ * Function: *_proc_fin (void)
  * Purpose : Finalise processor (disable caches)
  */
 _arm3_proc_fin:	mov	r0, #2
 		mcr	p15, 0, r0, c2, c0
-		movs	pc, lr
+_arm2_proc_fin:	orrs	pc, lr, #I_BIT|F_BIT
 
 /*
- * Function: arm3_xchg_1 (int new, volatile void *ptr)
- *
+ * Function: *_xchg_1 (int new, volatile void *ptr)
  * Params  : new	New value to store at...
  *	   : ptr	pointer to byte-wide location
- *
  * Purpose : Performs an exchange operation
- *
  * Returns : Original byte data at 'ptr'
  */
+_arm2_xchg_1:	mov	r2, pc
+		orr	r2, r2, #I_BIT
+		teqp	r2, #0
+		ldrb	r2, [r1]
+		strb	r0, [r1]
+		mov	r0, r2
+		movs	pc, lr
+
 _arm3_xchg_1:	swpb	r0, r0, [r1]
 		movs	pc, lr
 
 /*
- * Function: arm3_xchg_4 (int new, volatile void *ptr)
- *
+ * Function: *_xchg_4 (int new, volatile void *ptr)
  * Params  : new	New value to store at...
  *	   : ptr	pointer to word-wide location
- *
  * Purpose : Performs an exchange operation
- *
  * Returns : Original word data at 'ptr'
  */
+_arm2_xchg_4:	mov	r2, pc
+		orr	r2, r2, #I_BIT
+		teqp	r2, #0
+		ldr	r2, [r1]
+		str	r0, [r1]
+		mov	r0, r2
+		movs	pc, lr
+
 _arm3_xchg_4:	swp	r0, r0, [r1]
 		movs	pc, lr
 
+_arm2_3_check_bugs:
+		bics	pc, lr, #0x04000000		@ Clear FIQ disable bit
 
 armvlsi_name:	.asciz	"ARM/VLSI"
 _arm2_name:	.asciz	"arm2"
@@ -436,57 +281,42 @@
  */
 		.globl	SYMBOL_NAME(arm2_processor_functions)
 SYMBOL_NAME(arm2_processor_functions):
-		.word	_arm2_switch_to			@  4
-		.word	_arm2_3_data_abort		@  8
-		.word	_arm2_3_check_bugs		@ 12
-		.word	_arm2_proc_init			@ 16
-		.word	_arm2_proc_fin			@ 20
-
-		.word	_arm2_remap_memc		@ 24
-		.word	_arm2_3_update_map		@ 28
-		.word	_arm2_3_update_cache		@ 32
-		.word	_arm2_xchg_1			@ 36
-		.word	SYMBOL_NAME(abort)		@ 40
-		.word	_arm2_xchg_4			@ 44
-
-		.globl	SYMBOL_NAME(arm250_processor_functions)
-SYMBOL_NAME(arm250_processor_functions):
-		.word	_arm2_switch_to			@  4
-		.word	_arm2_3_data_abort		@  8
-		.word	_arm2_3_check_bugs		@ 12
-		.word	_arm2_proc_init			@ 16
-		.word	_arm2_proc_fin			@ 20
-
-		.word	_arm2_remap_memc		@ 24
-		.word	_arm2_3_update_map		@ 28
-		.word	_arm2_3_update_cache		@ 32
-		.word	_arm3_xchg_1			@ 36
-		.word	SYMBOL_NAME(abort)		@ 40
-		.word	_arm3_xchg_4			@ 44
-
-		.globl	SYMBOL_NAME(arm3_processor_functions)
-SYMBOL_NAME(arm3_processor_functions):
-		.word	_arm3_switch_to			@  4
-		.word	_arm2_3_data_abort		@  8
-		.word	_arm2_3_check_bugs		@ 12
-		.word	_arm3_proc_init			@ 16
-		.word	_arm3_proc_fin			@ 20
-
-		.word	_arm3_remap_memc		@ 24
-		.word	_arm2_3_update_map		@ 28
-		.word	_arm2_3_update_cache		@ 32
-		.word	_arm3_xchg_1			@ 36
-		.word	SYMBOL_NAME(abort)		@ 40
-		.word	_arm3_xchg_4			@ 44
+		.word	_arm2_3_check_bugs
+		.word	_arm2_proc_init
+		.word	_arm2_proc_fin
+		.word	_arm2_set_pgd
+		.word	_arm2_xchg_1
+		.word	SYMBOL_NAME(abort)
+		.word	_arm2_xchg_4
 
 cpu_arm2_info:
 		.long	armvlsi_name
 		.long	_arm2_name
 
+		.globl	SYMBOL_NAME(arm250_processor_functions)
+SYMBOL_NAME(arm250_processor_functions):
+		.word	_arm2_3_check_bugs
+		.word	_arm2_proc_init
+		.word	_arm2_proc_fin
+		.word	_arm2_set_pgd
+		.word	_arm3_xchg_1
+		.word	SYMBOL_NAME(abort)
+		.word	_arm3_xchg_4
+
 cpu_arm250_info:
 		.long	armvlsi_name
 		.long	_arm250_name
 
+		.globl	SYMBOL_NAME(arm3_processor_functions)
+SYMBOL_NAME(arm3_processor_functions):
+		.word	_arm2_3_check_bugs
+		.word	_arm3_proc_init
+		.word	_arm3_proc_fin
+		.word	_arm3_set_pgd
+		.word	_arm3_xchg_1
+		.word	SYMBOL_NAME(abort)
+		.word	_arm3_xchg_4
+
 cpu_arm3_info:
 		.long	armvlsi_name
 		.long	_arm3_name
@@ -501,6 +331,8 @@
 
 		.long	0x41560200
 		.long	0xfffffff0
+		.long	0
+		mov	pc, lr
 		.long	arm2_arch_name
 		.long	arm2_elf_name
 		.long	0
@@ -509,6 +341,8 @@
 
 		.long	0x41560250
 		.long	0xfffffff0
+		.long	0
+		mov	pc, lr
 		.long	arm3_arch_name
 		.long	arm3_elf_name
 		.long	0
@@ -517,6 +351,8 @@
 
 		.long	0x41560300
 		.long	0xfffffff0
+		.long	0
+		mov	pc, lr
 		.long	arm3_arch_name
 		.long	arm3_elf_name
 		.long	0
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.3.22/linux/arch/arm/mm/proc-arm6,7.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/proc-arm6,7.S	Wed Oct 20 16:29:08 1999
@@ -9,6 +9,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/procinfo.h>
+#include <asm/errno.h>
 #include "../lib/constants.h"
 
 /*
@@ -70,6 +71,19 @@
 		mov	pc, lr
 
 /*
+ * Function: arm6_7_flush_tlb_page (unsigned long address, int flags)
+ *
+ * Params  : address	Address
+ *	   : flags	b0 = I-TLB as well
+ *
+ * Purpose : flush a TLB entry
+ */
+ENTRY(cpu_arm6_flush_tlb_page)
+ENTRY(cpu_arm7_flush_tlb_page)
+		mcr	p15, 0, r0, c6, c0, 0		@ flush TLB
+		mov	pc, lr
+
+/*
  * Function: arm6_7_data_abort ()
  *
  * Params  : r0 = address of aborted instruction
@@ -89,6 +103,16 @@
 		.align
 
 ENTRY(cpu_arm6_data_abort)
+Ldata_simple:
+		ldr	r4, [r0]			@ read instruction causing problem
+		mov	r2, r4, lsr #19			@ r2 b1 = L
+		and	r2, r2, #2			@ check read/write bit
+		mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+		and	r1, r1, #15
+		mov	pc, lr
+
+ENTRY(cpu_arm7_data_abort)
 		ldr	r4, [r0]			@ read instruction causing problem
 		mov	r2, r4, lsr #19			@ r2 b1 = L
 		and	r1, r4, #15 << 24
@@ -98,10 +122,10 @@
 		b	Ldata_unknown
 		b	Ldata_unknown
 		b	Ldata_unknown
-		b	Ldata_earlyldrpost		@ ldr	rd, [rn], #m
-		b	Ldata_simple			@ ldr	rd, [rn, #m]	@ RegVal
-		b	Ldata_earlyldrpost		@ ldr	rd, [rn], rm
-		b	Ldata_simple			@ ldr	rd, [rn, rm]
+		b	Ldata_lateldrpostconst		@ ldr	rd, [rn], #m
+		b	Ldata_lateldrpreconst		@ ldr	rd, [rn, #m]	@ RegVal
+		b	Ldata_lateldrpostreg		@ ldr	rd, [rn], rm
+		b	Ldata_lateldrprereg		@ ldr	rd, [rn, rm]
 		b	Ldata_ldmstm			@ ldm*a	rn, <rlist>
 		b	Ldata_ldmstm			@ ldm*b	rn, <rlist>
 		b	Ldata_unknown
@@ -119,29 +143,6 @@
 		bl	SYMBOL_NAME(panic)
 Lstop:		b	Lstop
 
-ENTRY(cpu_arm7_data_abort)
-		ldr	r4, [r0]			@ read instruction causing problem
-		mov	r2, r4, lsr #19			@ r2 b1 = L
-		and	r1, r4, #15 << 24
-		add	pc, pc, r1, lsr #22		@ Now branch to the relevent processing routine
-		movs	pc, lr
-		b	Ldata_unknown
-		b	Ldata_unknown
-		b	Ldata_unknown
-		b	Ldata_unknown
-		b	Ldata_lateldrpostconst		@ ldr	rd, [rn], #m
-		b	Ldata_lateldrpreconst		@ ldr	rd, [rn, #m]	@ RegVal
-		b	Ldata_lateldrpostreg		@ ldr	rd, [rn], rm
-		b	Ldata_lateldrprereg		@ ldr	rd, [rn, rm]
-		b	Ldata_ldmstm			@ ldm*a	rn, <rlist>
-		b	Ldata_ldmstm			@ ldm*b	rn, <rlist>
-		b	Ldata_unknown
-		b	Ldata_unknown
-		b	Ldata_simple			@ ldc	rd, [rn], #m	@ Same as ldr	rd, [rn], #m
-		b	Ldata_simple			@ ldc	rd, [rn, #m]
-		b	Ldata_unknown
-		b	Ldata_unknown
-
 Ldata_ldmstm:	tst	r4, #1 << 21			@ check writeback bit
 		beq	Ldata_simple
 
@@ -165,31 +166,16 @@
 		add	r7, r0, r7, lsl #2		@ Do correction (signed)
 		str	r7, [sp, r5, lsr #14]		@ Put register
 
-Ldata_simple:	and	r2, r2, #2			@ check read/write bit
-		mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-		and	r1, r1, #15
-		mov	pc, lr
-
-Ldata_earlyldrpost:
-		tst	r2, #4
-		and	r2, r2, #2			@ check read/write bit
-		orrne	r2, r2, #1			@ T bit
-		mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-		and	r1, r1, #15
-		mov	pc, lr
-
 Ldata_lateldrpostconst:
 		movs	r1, r4, lsl #20			@ Get offset
-		beq	Ldata_earlyldrpost		@ if offset is zero, no effect
+		beq	Ldata_simple			@ if offset is zero, no effect
 		and	r5, r4, #15 << 16		@ Get Rn
 		ldr	r0, [sp, r5, lsr #14]
 		tst	r4, #1 << 23			@ U bit
 		subne	r0, r0, r1, lsr #20
 		addeq	r0, r0, r1, lsr #20
 		str	r0, [sp, r5, lsr #14]		@ Put register
-		b	Ldata_earlyldrpost
+		b	Ldata_simple
 
 Ldata_lateldrpreconst:
 		tst	r4, #1 << 21			@ check writeback bit
@@ -252,7 +238,7 @@
 		subne	r0, r0, r1
 		addeq	r0, r0, r1
 		str	r0, [sp, r5, lsr #14]		@ Put register
-		b	Ldata_earlyldrpost
+		b	Ldata_simple
 
 Ldata_lateldrprereg:
 		tst	r4, #1 << 21			@ check writeback bit
@@ -319,10 +305,24 @@
 		mrs	ip, cpsr
 		bic	ip, ip, #F_BIT
 		msr	cpsr, ip
+		mov	pc, lr
+
 ENTRY(cpu_arm6_proc_init)
 ENTRY(cpu_arm7_proc_init)
+		mov	pc, lr
+
 ENTRY(cpu_arm6_proc_fin)
 ENTRY(cpu_arm7_proc_fin)
+		mrs	r0, cpsr
+		orr	r0, r0, #F_BIT | I_BIT
+		msr	cpsr, r0
+		mov	r0, #0x31			@ ....S..DP...M
+		mcr	p15, 0, r0, c1, c0, 0		@ disable caches
+		mov	pc, lr
+
+ENTRY(cpu_arm6_do_idle)
+ENTRY(cpu_arm7_do_idle)
+		mov	r0, #-EINVAL
 		mov	pc, lr
 
 /*
@@ -381,23 +381,22 @@
 ENTRY(cpu_arm7_set_pte)
 		str	r1, [r0], #-1024		@ linux version
 
+		eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
+
 		bic	r2, r1, #0xff0
 		bic	r2, r2, #3
 		orr	r2, r2, #HPTE_TYPE_SMALL
 
-		tst	r1, #LPTE_USER | LPTE_EXEC
+		tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
 		orrne	r2, r2, #HPTE_AP_READ
 
-		tst	r1, #LPTE_WRITE
-		tstne	r1, #LPTE_DIRTY
-		orrne	r2, r2, #HPTE_AP_WRITE
-
-		tst	r1, #LPTE_PRESENT
-		tstne	r1, #LPTE_YOUNG
-		moveq	r2, #0
+		tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+		orreq	r2, r2, #HPTE_AP_WRITE
+
+		tst	r1, #LPTE_PRESENT | LPTE_YOUNG	@ Present and Young
+		movne	r2, #0
 
 		str	r2, [r0]			@ hardware version
-		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
 		mov	pc, lr
 
 /*
@@ -407,13 +406,9 @@
  */
 ENTRY(cpu_arm6_reset)
 ENTRY(cpu_arm7_reset)
-		mrs	r1, cpsr
-		orr	r1, r1, #F_BIT|I_BIT
-		msr	cpsr, r1
 		mov	r0, #0
 		mcr	p15, 0, r0, c7, c0, 0		@ flush cache
 		mcr	p15, 0, r0, c5, c0, 0		@ flush TLB
-		mov	r1, #F_BIT | I_BIT | 3
 		mov	pc, lr
 
 cpu_armvlsi_name:
@@ -428,6 +423,26 @@
 
 		.section ".text.init", #alloc, #execinstr
 
+__arm6_setup:	mov	r0, #0
+		mcr	p15, 0, r0, c7, c0		@ flush caches on v3
+		mcr	p15, 0, r0, c5, c0		@ flush TLBs on v3
+		mcr	p15, 0, r4, c2, c0		@ load page table pointer
+		mov	r0, #0x1f			@ Domains 0, 1 = client
+		mcr	p15, 0, r0, c3, c0		@ load domain access register
+		mov	r0, #0x3d			@ ....S..DPWC.M
+		orr	r0, r0, #0x100
+		mov	pc, lr
+
+__arm7_setup:	mov	r0, #0
+		mcr	p15, 0, r0, c7, c0		@ flush caches on v3
+		mcr	p15, 0, r0, c5, c0		@ flush TLBs on v3
+		mcr	p15, 0, r4, c2, c0		@ load page table pointer
+		mov	r0, #0x1f			@ Domains 0, 1 = client
+		mcr	p15, 0, r0, c3, c0		@ load domain access register
+		mov	r0, #0x7d			@ ....S.LDPWC.M
+		orr	r0, r0, #0x100
+		mov	pc, lr
+
 /*
  * Purpose : Function pointers used to access above functions - all calls
  *	     come through these
@@ -452,6 +467,8 @@
 		.word	cpu_arm6_flush_icache_area
 		.word	cpu_arm6_cache_wback_area
 		.word	cpu_arm6_cache_purge_area
+		.word	cpu_arm6_flush_tlb_page
+		.word	cpu_arm7_do_idle
 		.size	arm6_processor_functions, . - arm6_processor_functions
 
 /*
@@ -478,6 +495,8 @@
 		.word	cpu_arm7_flush_icache_area
 		.word	cpu_arm7_cache_wback_area
 		.word	cpu_arm7_cache_purge_area
+		.word	cpu_arm7_flush_tlb_page
+		.word	cpu_arm7_do_idle
 		.size	arm7_processor_functions, . - arm7_processor_functions
 
 		.type	cpu_arm6_info, #object
@@ -519,9 +538,11 @@
 __arm6_proc_info:
 		.long	0x41560600
 		.long	0xfffffff0
+		.long	0x00000c12
+		b	__arm6_setup
 		.long	cpu_arch_name
 		.long	cpu_elf_name
-		.long	HWCAP_SWP
+		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm6_info
 		.long	arm6_processor_functions
 		.size	__arm6_proc_info, . - __arm6_proc_info
@@ -530,9 +551,11 @@
 __arm610_proc_info:
 		.long	0x41560610
 		.long	0xfffffff0
+		.long	0x00000c12
+		b	__arm6_setup
 		.long	cpu_arch_name
 		.long	cpu_elf_name
-		.long	HWCAP_SWP
+		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm610_info
 		.long	arm6_processor_functions
 		.size	__arm610_proc_info, . - __arm610_proc_info
@@ -541,9 +564,11 @@
 __arm7_proc_info:
 		.long	0x41007000
 		.long	0xffffff00
+		.long	0x00000c12
+		b	__arm7_setup
 		.long	cpu_arch_name
 		.long	cpu_elf_name
-		.long	HWCAP_SWP
+		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm7_info
 		.long	arm7_processor_functions
 		.size	__arm7_proc_info, . - __arm7_proc_info
@@ -552,9 +577,11 @@
 __arm710_proc_info:
 		.long	0x41007100
 		.long	0xfff8ff00
+		.long	0x00000c12
+		b	__arm7_setup
 		.long	cpu_arch_name
 		.long	cpu_elf_name
-		.long	HWCAP_SWP
+		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm710_info
 		.long	arm7_processor_functions
 		.size	__arm710_proc_info, . - __arm710_proc_info
diff -u --recursive --new-file v2.3.22/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.3.22/linux/arch/arm/mm/proc-sa110.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/arm/mm/proc-sa110.S	Wed Oct 20 16:29:08 1999
@@ -4,7 +4,7 @@
  * (C) 1997-1999 Russell King
  *
  * These are the low level assembler for performing cache and TLB
- * functions on the sa110.
+ * functions on the StrongARM-110 and StrongARM-1100
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
@@ -17,6 +17,27 @@
  */
 #define MAX_AREA_SIZE	32768
 
+		.macro flush_110_dcache	rd, ra, re
+		add	\re, \ra, #16384		@ only necessary for 16k
+1001:		ldr	\rd, [\ra], #32
+		teq	\re, \ra
+		bne	1001b
+		.endm
+
+		.macro flush_1100_dcache	rd, ra, re
+		add	\re, \ra, #8192			@ only necessary for 8k
+1001:		ldr	\rd, [\ra], #32
+		teq	\re, \ra
+		bne	1001b
+#ifdef FLUSH_BASE_MINICACHE
+		add	\ra, \ra, #FLUSH_BASE_MINICACHE - FLUSH_BASE
+		add	\re, \ra, #512			@ only 512 bytes
+1002:		ldr	\rd, [\ra], #32
+		teq	\re, \ra
+		bne	1002b
+#endif
+		.endm
+
 		.data
 Lclean_switch:	.long	0
 		.text
@@ -36,12 +57,27 @@
 		eor	r1, r1, #1
 		str	r1, [r3]
 		addne	ip, ip, #32768
-		add	r1, ip, #16384			@ only necessary for 16k
-1:		ldr	r3, [ip], #32
-		teq	r1, ip
-		bne	1b
+		flush_110_dcache	r3, ip, r1
+		mov	ip, #0
+		teq	r2, #0
+		mcrne	p15, 0, ip, c7, c5, 0		@ flush I cache
+		mcr	p15, 0, ip, c7, c10, 4		@ drain WB
+		mov	pc, lr
+
+		.align	5
+ENTRY(cpu_sa1100_flush_cache_all)			@ preserves r0
+		mov	r2, #1
+cpu_sa1100_flush_cache_all_r2:
+		ldr	r3, =Lclean_switch
+		ldr	ip, =FLUSH_BASE
+		ldr	r1, [r3]
+		ands	r1, r1, #1
+		eor	r1, r1, #1
+		str	r1, [r3]
+		addne	ip, ip, #32768
+		flush_1100_dcache	r3, ip, r1
 		mov	ip, #0
-		tst	r2, #1
+		teq	r2, #0
 		mcrne	p15, 0, ip, c7, c5, 0		@ flush I cache
 		mcr	p15, 0, ip, c7, c10, 4		@ drain WB
 		mov	pc, lr
@@ -66,11 +102,17 @@
 		add	r0, r0, #32
 		cmp	r0, r1
 		blt	1b
-		tst	r2, #1
+		teq	r2, #0
 		movne	r0, #0
 		mcrne	p15, 0, r0, c7, c5, 0		@ flush I cache
 		mov	pc, lr
 
+ENTRY(cpu_sa1100_flush_cache_area)
+		sub	r3, r1, r0
+		cmp	r3, #MAX_AREA_SIZE
+		bgt	cpu_sa1100_flush_cache_all_r2
+		b	1b
+
 /*
  * Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
  * Params  : address	Area start address
@@ -94,6 +136,13 @@
 		mcr	p15, 0, r2, c7, c10, 4		@ drain WB
 		mov	pc, lr
 
+ENTRY(cpu_sa1100_cache_wback_area)
+		sub	r3, r1, r0
+		cmp	r3, #MAX_AREA_SIZE
+		mov	r2, #0
+		bgt	cpu_sa1100_flush_cache_all_r2
+		bic	r0, r0, #31
+		b	1b
 /*
  * Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
  * Params  : address	Area start address
@@ -105,6 +154,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_cache_purge_area)
+ENTRY(cpu_sa1100_cache_purge_area)
 		tst	r0, #31
 		bic	r0, r0, #31
 		mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
@@ -123,6 +173,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_flush_cache_entry)
+ENTRY(cpu_sa1100_flush_cache_entry)
 		mov	r1, #0
 		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 		mcr	p15, 0, r1, c7, c10, 4		@ drain WB
@@ -136,6 +187,7 @@
  *	     for page table purposes.
  */
 ENTRY(cpu_sa110_clean_cache_area)
+ENTRY(cpu_sa1100_clean_cache_area)
 1:		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
 		add	r0, r0, #32
 		subs	r1, r1, #32
@@ -149,6 +201,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_flush_ram_page)
+ENTRY(cpu_sa1100_flush_ram_page)
 		mov	r1, #4096
 1:		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 		add	r0, r0, #32
@@ -170,6 +223,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_flush_tlb_all)
+ENTRY(cpu_sa1100_flush_tlb_all)
 		mov	r0, #0
 		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 		mcr	p15, 0, r0, c8, c7, 0		@ flush I & D tlbs
@@ -184,6 +238,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_flush_tlb_area)
+ENTRY(cpu_sa1100_flush_tlb_area)
 		mov	r3, #0
 		mcr	p15, 0, r3, c7, c10, 4		@ drain WB
 1:		cmp	r0, r1
@@ -193,12 +248,35 @@
 		mcrlt	p15, 0, r0, c8, c6, 1		@ flush D TLB entry
 		addlt	r0, r0, #4096
 		blt	1b
-		tst	r2, #1
+		teq	r2, #0
+		mcrne	p15, 0, r3, c8, c5, 0		@ flush I TLB
+		mov	pc, lr
+
+/*
+ * Function: sa110_flush_tlb_page (unsigned long address, int flags)
+ * Params  : address	Address to flush
+ *	   : flags	b0 = I-TLB as well
+ * Purpose : flush a TLB entry
+ */
+		.align	5
+ENTRY(cpu_sa110_flush_tlb_page)
+ENTRY(cpu_sa1100_flush_tlb_page)
+		mov	r3, #0
+		mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+		mcr	p15, 0, r0, c8, c6, 1		@ flush D TLB entry
+		teq	r1, #0
 		mcrne	p15, 0, r3, c8, c5, 0		@ flush I TLB
 		mov	pc, lr
 
+/*
+ * Function: sa110_flush_icache_area (unsigned long address, unsigned long size)
+ * Params  : address	Address of area to flush
+ *	   : size	Size of area to flush
+ * Purpose : flush an area from the Icache
+ */
 		.align	5
 ENTRY(cpu_sa110_flush_icache_area)
+ENTRY(cpu_sa1100_flush_icache_area)
 1:		mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
 		add	r0, r0, #32
 		subs	r1, r1, #32
@@ -218,6 +296,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_data_abort)
+ENTRY(cpu_sa1100_data_abort)
 		ldr	r2, [r0]			@ read instruction causing problem
 		mrc	p15, 0, r0, c6, c0, 0		@ get FAR
 		mov	r2, r2, lsr #19			@ b1 = L
@@ -237,16 +316,30 @@
 		.align	5
 ENTRY(cpu_sa110_set_pgd)
 		ldr	r3, =Lclean_switch
+		ldr	ip, =FLUSH_BASE
 		ldr	r2, [r3]
 		ands	r2, r2, #1
 		eor	r2, r2, #1
 		str	r2, [r3]
-		ldr	r2, =FLUSH_BASE
-		addne	r2, r2, #32768
-		add	r1, r2, #16384			@ only necessary for 16k
-1:		ldr	r3, [r2], #32
-		teq	r1, r2
-		bne	1b
+		addne	ip, ip, #32768
+		flush_110_dcache	r3, ip, r1
+		mov	r1, #0
+		mcr	p15, 0, r1, c7, c5, 0		@ flush I cache
+		mcr	p15, 0, r1, c7, c10, 4		@ drain WB
+		mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
+		mcr	p15, 0, r1, c8, c7, 0		@ flush TLBs
+		mov	pc, lr
+
+		.align	5
+ENTRY(cpu_sa1100_set_pgd)
+		ldr	r3, =Lclean_switch
+		ldr	ip, =FLUSH_BASE
+		ldr	r2, [r3]
+		ands	r2, r2, #1
+		eor	r2, r2, #1
+		str	r2, [r3]
+		addne	ip, ip, #32768
+		flush_1100_dcache	r3, ip, r1
 		mov	r1, #0
 		mcr	p15, 0, r1, c7, c5, 0		@ flush I cache
 		mcr	p15, 0, r1, c7, c10, 4		@ drain WB
@@ -262,9 +355,10 @@
  */
 		.align	5
 ENTRY(cpu_sa110_set_pmd)
+ENTRY(cpu_sa1100_set_pmd)
 		str	r1, [r0]
 		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
-		mcr	p15, 0, r0, c7, c10, 4		@ drain WB (TLB bypasses WB)
+		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 		mov	pc, lr
 
 /*
@@ -275,6 +369,7 @@
  */
 		.align	5
 ENTRY(cpu_sa110_set_pte)
+ENTRY(cpu_sa1100_set_pte)
 		str	r1, [r0], #-1024		@ linux version
 
 		eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
@@ -294,8 +389,8 @@
 
 		str	r2, [r0]			@ hardware version
 		mov	r0, r0
-		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
-		mcr	p15, 0, r0, c7, c10, 4		@ drain WB (TLB bypasses WB)
+		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 		mov	pc, lr
 
 /*
@@ -305,12 +400,39 @@
  * Notes   : This processor does not require these
  */
 ENTRY(cpu_sa110_check_bugs)
+ENTRY(cpu_sa1100_check_bugs)
 		mrs	ip, cpsr
 		bic	ip, ip, #F_BIT
 		msr	cpsr, ip
+		mov	pc, lr
 
 ENTRY(cpu_sa110_proc_init)
+ENTRY(cpu_sa1100_proc_init)
+		mov	r0, #0
+		mcr	p15, 0, r0, c15, c1, 2		@ Enable clock switching
+		mov	pc, lr
+
 ENTRY(cpu_sa110_proc_fin)
+ENTRY(cpu_sa1100_proc_fin)
+		mrs	r0, cpsr
+		orr	r0, r0, #F_BIT | I_BIT
+		msr	cpsr, r0
+		mov	r0, #0
+		mcr	p15, 0, r0, c15, c2, 2		@ Disable clock switching
+		mrc	p15, 0, r0, c1, c0, 0
+		bic	r0, r0, #0x1100			@ ...i...s........
+		bic	r0, r0, #0x000e			@ ............wca.
+		mcr	p15, 0, r0, c1, c0, 0		@ disable caches
+		mov	pc, lr
+
+		.align	5
+ENTRY(cpu_sa110_do_idle)
+ENTRY(cpu_sa1100_do_idle)
+		mov	r0, #0
+		mcr	p15, 0, r0, c15, c2, 2		@ Disable clock switching
+							@ load from uncacheable loc?
+		mcr	p15, 0, r0, c15, c8, 2		@ Wait for interrupt
+		mcr	p15, 0, r0, c15, c1, 2		@ Enable clock switching
 		mov	pc, lr
 
 /*
@@ -318,17 +440,13 @@
  * Notes   : This sets up everything for a reset
  */
 ENTRY(cpu_sa110_reset)
-		mrs	r1, cpsr
-		orr	r1, r1, #F_BIT | I_BIT
-		msr	cpsr, r1
+ENTRY(cpu_sa1100_reset)
 		stmfd	sp!, {r1, lr}
-		mov	r2, #1
 		bl	cpu_sa110_flush_cache_all
 		bl	cpu_sa110_flush_tlb_all
 		mcr	p15, 0, ip, c7, c7, 0		@ flush I,D caches
 		mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
-		bic	r0, r0, #0x1800
-		bic	r0, r0, #0x000f
+		bic	r0, r0, #1			@ ...............m
 		ldmfd	sp!, {r1, pc}
 /*
  * Purpose : Function pointers used to access above functions - all calls
@@ -338,10 +456,26 @@
 cpu_manu_name:	.asciz	"Intel"
 ENTRY(cpu_sa110_name)
 		.asciz	"sa110"
+ENTRY(cpu_sa1100_name)
+		.asciz	"sa1100"
 		.align
 
 		.section ".text.init", #alloc, #execinstr
 
+__sa110_setup:	mov	r0, #0
+		mcr	p15, 0, r0, c7, c7		@ flush I,D caches on v4
+		mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
+		mcr	p15, 0, r0, c8, c7		@ flush I,D TLBs on v4
+		mcr	p15, 0, r4, c2, c0		@ load page table pointer
+		mov	r0, #0x1f			@ Domains 0, 1 = client
+		mcr	p15, 0, r0, c3, c0		@ load domain access register
+		mrc	p15, 0, r0, c1, c0		@ get control register v4
+		bic	r0, r0, #0x0e00			@ ....??r.........
+		bic	r0, r0, #0x0002			@ ..............a.
+		orr	r0, r0, #0x003d			@ ..........DPWC.M
+		orr	r0, r0, #0x1100			@ ...I...S........
+		mov	pc, lr
+
 		.type	sa110_processor_functions, #object
 ENTRY(sa110_processor_functions)
 		.word	cpu_sa110_data_abort
@@ -362,7 +496,8 @@
 		.word	cpu_sa110_flush_icache_area
 		.word	cpu_sa110_cache_wback_area
 		.word	cpu_sa110_cache_purge_area
-
+		.word	cpu_sa110_flush_tlb_page
+		.word	cpu_sa110_do_idle
 		.size	sa110_processor_functions, . - sa110_processor_functions
 
 		.type	cpu_sa110_info, #object
@@ -371,6 +506,36 @@
 		.long	cpu_sa110_name
 		.size	cpu_sa110_info, . - cpu_sa110_info
 
+
+		.type	sa1100_processor_functions, #object
+ENTRY(sa1100_processor_functions)
+		.word	cpu_sa1100_data_abort
+		.word	cpu_sa1100_check_bugs
+		.word	cpu_sa1100_proc_init
+		.word	cpu_sa1100_proc_fin
+		.word	cpu_sa1100_flush_cache_all
+		.word	cpu_sa1100_flush_cache_area
+		.word	cpu_sa1100_flush_cache_entry
+		.word	cpu_sa1100_clean_cache_area
+		.word	cpu_sa1100_flush_ram_page
+		.word	cpu_sa1100_flush_tlb_all
+		.word	cpu_sa1100_flush_tlb_area
+		.word	cpu_sa1100_set_pgd
+		.word	cpu_sa1100_set_pmd
+		.word	cpu_sa1100_set_pte
+		.word	cpu_sa1100_reset
+		.word	cpu_sa1100_flush_icache_area
+		.word	cpu_sa1100_cache_wback_area
+		.word	cpu_sa1100_cache_purge_area
+		.word	cpu_sa1100_flush_tlb_page
+		.word	cpu_sa1100_do_idle
+		.size	sa1100_processor_functions, . - sa1100_processor_functions
+
+cpu_sa1100_info:
+		.long	cpu_manu_name
+		.long	cpu_sa1100_name
+		.size	cpu_sa1100_info, . - cpu_sa1100_info
+
 		.type	cpu_arch_name, #object
 cpu_arch_name:	.asciz	"armv4"
 		.size	cpu_arch_name, . - cpu_arch_name
@@ -385,9 +550,26 @@
 __sa110_proc_info:
 		.long	0x4401a100
 		.long	0xfffffff0
+		.long	0x00000c02
+		b	__sa110_setup
 		.long	cpu_arch_name
 		.long	cpu_elf_name
-		.long	HWCAP_SWP | HWCAP_HALF
+		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
 		.long	cpu_sa110_info
 		.long	sa110_processor_functions
 		.size	__sa110_proc_info, . - __sa110_proc_info
+
+		.type	__sa1100_proc_info,#object
+__sa1100_proc_info:
+		.long	0x4401a110
+		.long	0xfffffff0
+		.long	0x00000c02
+		b	__sa110_setup
+		.long	cpu_arch_name
+		.long	cpu_elf_name
+		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+		.long	cpu_sa1100_info
+		.long	sa1100_processor_functions
+		.size	__sa1100_proc_info, . - __sa1100_proc_info
+
+
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/ChangeLog linux/arch/arm/nwfpe/ChangeLog
--- v2.3.22/linux/arch/arm/nwfpe/ChangeLog	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/ChangeLog	Wed Oct 20 16:29:08 1999
@@ -1,10 +1,50 @@
-1998-11-23  Scott Bambrough  <scottb@corelcomputer.com>
+1999-08-19  Scott Bambrough  <scottb@netwinder.org>
+
+	* fpmodule.c - Changed version number to 0.95
+	* fpa11.h - modified FPA11, FPREG structures
+	* fpa11.c - Changes due to FPA11, FPREG structure alterations.
+	* fpa11_cpdo.c - Changes due to FPA11, FPREG structure alterations.
+	* fpa11_cpdt.c - Changes due to FPA11, FPREG structure alterations.
+	* fpa11_cprt.c - Changes due to FPA11, FPREG structure alterations.
+	* single_cpdo.c - Changes due to FPA11, FPREG structure alterations.
+	* double_cpdo.c - Changes due to FPA11, FPREG structure alterations.
+	* extended_cpdo.c - Changes due to FPA11, FPREG structure alterations.
+
+	* I discovered several bugs.  First and worst is that the kernel
+	  passes in a pointer to the FPE's state area.	This is defined
+	  as a struct user_fp (see user.h).  This pointer was cast to a
+	  FPA11*.  Unfortunately FPA11 and user_fp are of different sizes;
+	  user_fp is smaller.  This meant that the FPE scribbled on things
+	  below its area, which is bad, as the area is in the thread_struct
+	  embedded in the process task structure.  Thus we were scribbling
+	  over one of the most important structures in the entire OS.
+
+	* user_fp and FPA11 have now been harmonized.  Most of the changes
+	  in the above code were dereferencing problems due to moving the
+	  register type out of FPREG, and getting rid of the union variable
+	  fpvalue.
+
+	* Second I noticed resetFPA11 was not always being called for a
+	  task.  This should happen on the first floating point exception
+	  that occurs.	It is controlled by init_flag in FPA11.  The
+	  comment in the code beside init_flag state the kernel guarantees
+	  this to be zero.  Not so.  I found that the kernel recycles task
+	  structures, and that recycled ones may not have init_flag zeroed.
+	  I couldn't even find anything that guarantees it is zeroed when
+	  when the task structure is initially allocated.  In any case
+	  I now initialize the entire FPE state in the thread structure to
+	  zero when allocated and recycled.  See alloc_task_struct() and
+	  flush_thread() in arch/arm/process.c.  The change to
+	  alloc_task_struct() may not be necessary, but I left it in for
+	  completeness (better safe than sorry).
+
+1998-11-23  Scott Bambrough  <scottb@netwinder.org>
 
 	* README.FPE - fix typo in description of lfm/sfm instructions
 	* NOTES - Added file to describe known bugs/problems 
 	* fpmodule.c - Changed version number to 0.94
 
-1998-11-20  Scott Bambrough  <scottb@corelcomputer.com>
+1998-11-20  Scott Bambrough  <scottb@netwinder.org>
 
 	* README.FPE - fix description of URD, NRM instructions
 	* TODO - remove URD, NRM instructions from TODO list
@@ -12,7 +52,7 @@
 	* double_cpdo.c - implement URD, NRM
 	* extended_cpdo.c - implement URD, NRM
 
-1998-11-19  Scott Bambrough  <scottb@corelcomputer.com>
+1998-11-19  Scott Bambrough  <scottb@netwinder.org>
 
 	* ChangeLog - Added this file to track changes made.
 	* fpa11.c - added code to initialize register types to typeNone
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile
--- v2.3.22/linux/arch/arm/nwfpe/Makefile	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/Makefile	Wed Oct 20 16:29:08 1999
@@ -14,16 +14,15 @@
 NWFPE_OBJS += entry.o
 endif
 
-L_TARGET := math-emu.a
-
 ifeq ($(CONFIG_NWFPE),y)
-L_OBJS = $(NWFPE_OBJS)
+O_TARGET := math-emu.o
+O_OBJS = $(NWFPE_OBJS)
 else
   ifeq ($(CONFIG_NWFPE),m)
     M_OBJS = nwfpe.o
     MI_OBJS = $(NWFPE_OBJS)
   endif
-endif    
+endif
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/double_cpdo.c linux/arch/arm/nwfpe/double_cpdo.c
--- v2.3.22/linux/arch/arm/nwfpe/double_cpdo.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/double_cpdo.c	Wed Oct 20 16:29:08 1999
@@ -19,7 +19,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
@@ -54,14 +53,14 @@
    }
    else
    {  
-     switch (fpa11->fpreg[Fm].fType)
+     switch (fpa11->fType[Fm])
      {
         case typeSingle:
-          rFm = float32_to_float64(fpa11->fpreg[Fm].fValue.fSingle);
+          rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
         break;
 
         case typeDouble:
-          rFm = fpa11->fpreg[Fm].fValue.fDouble;
+          rFm = fpa11->fpreg[Fm].fDouble;
           break;
 
         case typeExtended:
@@ -80,14 +79,14 @@
    if (!MONADIC_INSTRUCTION(opcode))
    {
       Fn = getFn(opcode);
-      switch (fpa11->fpreg[Fn].fType)
+      switch (fpa11->fType[Fn])
       {
         case typeSingle:
-          rFn = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
+          rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
         break;
 
         case typeDouble:
-          rFn = fpa11->fpreg[Fn].fValue.fDouble;
+          rFn = fpa11->fpreg[Fn].fDouble;
         break;
         
         default: return 0;
@@ -100,62 +99,62 @@
    {
       /* dyadic opcodes */
       case ADF_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_add(rFn,rFm);
+         fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm);
       break;
 
       case MUF_CODE:
       case FML_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_mul(rFn,rFm);
+         fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm);
       break;
 
-   case SUF_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFn,rFm);
+      case SUF_CODE:
+         fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm);
       break;
 
       case RSF_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFm,rFn);
+         fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn);
       break;
 
       case DVF_CODE:
       case FDV_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFn,rFm);
+         fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm);
       break;
 
       case RDF_CODE:
       case FRD_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFm,rFn);
+         fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn);
       break;
 
 #if 0
       case POW_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFn,rFm);
+         fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm);
       break;
 
       case RPW_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFm,rFn);
+         fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn);
       break;
 #endif
 
       case RMF_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_rem(rFn,rFm);
+         fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm);
       break;
 
 #if 0
       case POL_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_pol(rFn,rFm);
+         fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm);
       break;
 #endif
 
       /* monadic opcodes */
       case MVF_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = rFm;
+         fpa11->fpreg[Fd].fDouble = rFm;
       break;
 
       case MNF_CODE:
       {
          unsigned int *p = (unsigned int*)&rFm;
          p[1] ^= 0x80000000;
-         fpa11->fpreg[Fd].fValue.fDouble = rFm;
+         fpa11->fpreg[Fd].fDouble = rFm;
       }
       break;
 
@@ -163,55 +162,55 @@
       {
          unsigned int *p = (unsigned int*)&rFm;
          p[1] &= 0x7fffffff;
-         fpa11->fpreg[Fd].fValue.fDouble = rFm;
+         fpa11->fpreg[Fd].fDouble = rFm;
       }
       break;
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = 
+         fpa11->fpreg[Fd].fDouble = 
              int32_to_float64(float64_to_int32(rFm));
       break;
 
       case SQT_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_sqrt(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm);
       break;
 
 #if 0
       case LOG_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_log(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_log(rFm);
       break;
 
       case LGN_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_ln(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_ln(rFm);
       break;
 
       case EXP_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_exp(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_exp(rFm);
       break;
 
       case SIN_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_sin(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_sin(rFm);
       break;
 
       case COS_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_cos(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_cos(rFm);
       break;
 
       case TAN_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_tan(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_tan(rFm);
       break;
 
       case ASN_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_arcsin(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm);
       break;
 
       case ACS_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_arccos(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_arccos(rFm);
       break;
 
       case ATN_CODE:
-         fpa11->fpreg[Fd].fValue.fDouble = float64_arctan(rFm);
+         fpa11->fpreg[Fd].fDouble = float64_arctan(rFm);
       break;
 #endif
 
@@ -224,7 +223,7 @@
       }
    }
 
-   if (0 != nRc) fpa11->fpreg[Fd].fType = typeDouble;
+   if (0 != nRc) fpa11->fType[Fd] = typeDouble;
    return nRc;
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/entry.S linux/arch/arm/nwfpe/entry.S
--- v2.3.22/linux/arch/arm/nwfpe/entry.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/entry.S	Wed Oct 20 16:29:08 1999
@@ -3,7 +3,7 @@
     (c) Corel Computer Corporation, 1998
     (c) Philip Blundell 1998-1999
 
-    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -85,14 +85,15 @@
         mov r10, lr			@ save the failure-return addresses
 
         ldr r5, [r4, #60]	 	@ get contents of PC;
-	ldr r0, [r5, #-4]		@ get actual instruction into r0
+	sub r8, r5, #4
+.Lx2:	ldrt r0, [r8], #0		@ get actual instruction into r0
 emulate:
 	bl EmulateAll			@ emulate the instruction
    	cmp r0, #0			@ was emulation successful
         moveq pc, r10			@ no, return failure
 
 next:
-__x1:	ldrt	r6, [r5], #4		@ get the next instruction and
+.Lx1:	ldrt r6, [r5], #4		@ get the next instruction and
 					@ increment PC
 
 	and   r2, r6, #0x0F000000	@ test for FP insns
@@ -114,13 +115,15 @@
         mov r0, r6			@ prepare for EmulateAll()
    	b emulate			@ if r0 != 0, goto EmulateAll
 
-	@ We need to be prepared for the instruction at __x1 to fault.
-	@ Emit the appropriate exception gunk to fix things up.
+	@ We need to be prepared for the instruction at .Lx1 or .Lx2
+	@ to fault.
 	.section .fixup,"ax"
 	.align
-__f1:	mov	pc, r9
+.Lfix:	mov	pc, r9
 	.previous
+
 	.section __ex_table,"a"
 	.align 3
-	.long	__x1, __f1
+	.long	.Lx2, .Lfix
+	.long	.Lx1, .Lfix
 	.previous
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S
--- v2.3.22/linux/arch/arm/nwfpe/entry26.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/entry26.S	Wed Oct 20 16:29:08 1999
@@ -3,7 +3,7 @@
     (c) Corel Computer Corporation, 1998
     (c) Philip Blundell 1998-1999
 
-    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/extended_cpdo.c linux/arch/arm/nwfpe/extended_cpdo.c
--- v2.3.22/linux/arch/arm/nwfpe/extended_cpdo.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/extended_cpdo.c	Wed Oct 20 16:29:08 1999
@@ -19,7 +19,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
@@ -52,18 +51,18 @@
    }
    else
    {  
-     switch (fpa11->fpreg[Fm].fType)
+     switch (fpa11->fType[Fm])
      {
         case typeSingle:
-          rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle);
+          rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
         break;
 
         case typeDouble:
-          rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble);
+          rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
         break;
         
         case typeExtended:
-          rFm = fpa11->fpreg[Fm].fValue.fExtended;
+          rFm = fpa11->fpreg[Fm].fExtended;
         break;
         
         default: return 0;
@@ -73,18 +72,18 @@
    if (!MONADIC_INSTRUCTION(opcode))
    {
       Fn = getFn(opcode);
-      switch (fpa11->fpreg[Fn].fType)
+      switch (fpa11->fType[Fn])
       {
         case typeSingle:
-          rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+          rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
         break;
 
         case typeDouble:
-          rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+          rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
         break;
         
         case typeExtended:
-          rFn = fpa11->fpreg[Fn].fValue.fExtended;
+          rFn = fpa11->fpreg[Fn].fExtended;
         break;
         
         default: return 0;
@@ -96,112 +95,112 @@
    {
       /* dyadic opcodes */
       case ADF_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_add(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm);
       break;
 
       case MUF_CODE:
       case FML_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_mul(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm);
       break;
 
       case SUF_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm);
       break;
 
       case RSF_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFm,rFn);
+         fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn);
       break;
 
       case DVF_CODE:
       case FDV_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm);
       break;
 
       case RDF_CODE:
       case FRD_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFm,rFn);
+         fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn);
       break;
 
 #if 0
       case POW_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm);
       break;
 
       case RPW_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFm,rFn);
+         fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn);
       break;
 #endif
 
       case RMF_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_rem(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm);
       break;
 
 #if 0
       case POL_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_pol(rFn,rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm);
       break;
 #endif
 
       /* monadic opcodes */
       case MVF_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = rFm;
+         fpa11->fpreg[Fd].fExtended = rFm;
       break;
 
       case MNF_CODE:
          rFm.high ^= 0x8000;
-         fpa11->fpreg[Fd].fValue.fExtended = rFm;
+         fpa11->fpreg[Fd].fExtended = rFm;
       break;
 
       case ABS_CODE:
          rFm.high &= 0x7fff;
-         fpa11->fpreg[Fd].fValue.fExtended = rFm;
+         fpa11->fpreg[Fd].fExtended = rFm;
       break;
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = 
+         fpa11->fpreg[Fd].fExtended = 
              int32_to_floatx80(floatx80_to_int32(rFm));
       break;
 
       case SQT_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sqrt(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm);
       break;
 
 #if 0
       case LOG_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_log(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_log(rFm);
       break;
 
       case LGN_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_ln(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm);
       break;
 
       case EXP_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_exp(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm);
       break;
 
       case SIN_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_sin(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm);
       break;
 
       case COS_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_cos(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm);
       break;
 
       case TAN_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_tan(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm);
       break;
 
       case ASN_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_arcsin(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm);
       break;
 
       case ACS_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_arccos(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm);
       break;
 
       case ATN_CODE:
-         fpa11->fpreg[Fd].fValue.fExtended = floatx80_arctan(rFm);
+         fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm);
       break;
 #endif
 
@@ -214,7 +213,7 @@
       }
    }
    
-   if (0 != nRc) fpa11->fpreg[Fd].fType = typeExtended;
+   if (0 != nRc) fpa11->fType[Fd] = typeExtended;
    return nRc;
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c
--- v2.3.22/linux/arch/arm/nwfpe/fpa11.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpa11.c	Wed Oct 20 16:29:08 1999
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
+#include <asm/system.h>
+
 #include "fpa11.h"
-#include "milieu.h"
 #include "fpopcode.h"
 
 #include "fpmodule.h"
@@ -39,17 +39,18 @@
 void resetFPA11(void)
 {
   int i;
-  /* initialize the registers */
+
+  /* initialize the register type array */
   for (i=0;i<=7;i++)
   {
-    fpa11->fpreg[i].fType = typeNone;
+    fpa11->fType[i] = typeNone;
   }
   
   /* FPSR: set system id to FP_EMULATOR, clear all other bits */
   fpa11->fpsr = FP_EMULATOR;
   
   /* FPCR: set SB, AB and DA bits, clear all others */
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
   fpa11->fpcr = MASK_RESET;
 #endif
 }
@@ -128,6 +129,9 @@
 unsigned int EmulateAll(unsigned int opcode)
 {
   unsigned int nRc = 0;
+  unsigned long flags;
+
+  save_flags(flags); sti();
 
   if (fpa11->initflag == 0)		/* good place for __builtin_expect */
   {
@@ -161,6 +165,8 @@
     /* Invalid instruction detected.  Return FALSE. */
     nRc = 0;
   }
+
+  restore_flags(flags);
 
   return(nRc);
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11.h linux/arch/arm/nwfpe/fpa11.h
--- v2.3.22/linux/arch/arm/nwfpe/fpa11.h	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpa11.h	Wed Oct 20 16:29:08 1999
@@ -31,25 +31,25 @@
 #define		typeDouble		0x02
 #define		typeExtended		0x03
 
-typedef struct tagFPREG {
-   unsigned int fType;
-   union {
-      float32  fSingle;
-      float64  fDouble;
-      floatx80 fExtended;
-   } fValue;
+typedef union tagFPREG {
+   float32  fSingle;
+   float64  fDouble;
+   floatx80 fExtended;
 } FPREG;
 
 /* FPA11 device model */
 typedef struct tagFPA11 {
+  FPREG fpreg[8];		/* 8 floating point registers */
+  FPSR fpsr;			/* floating point status register */
+  FPCR fpcr;			/* floating point control register */
+  unsigned char fType[8];	/* type of floating point value held in
+				   floating point registers.  One of none
+				   single, double or extended. */
   int initflag;			/* this is special.  The kernel guarantees
 				   to set it to 0 when a thread is launched,
 				   so we can use it to detect whether this
 				   instance of the emulator needs to be
 				   initialised. */
-  FPREG fpreg[8];		/* 8 floating point registers */
-  FPSR fpsr;			/* floating point status register */
-  FPCR fpcr;			/* floating point control register */
 } FPA11;
 
 extern void resetFPA11(void);
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11.inl linux/arch/arm/nwfpe/fpa11.inl
--- v2.3.22/linux/arch/arm/nwfpe/fpa11.inl	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/fpa11.inl	Wed Oct 20 16:29:08 1999
@@ -2,7 +2,7 @@
     NetWinder Floating Point Emulator
     (c) Corel Computer Corporation, 1998
 
-    Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdo.c linux/arch/arm/nwfpe/fpa11_cpdo.c
--- v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdo.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpa11_cpdo.c	Wed Oct 20 16:29:08 1999
@@ -19,7 +19,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
 #include "fpa11.h"
 #include "fpopcode.h"
 
@@ -48,14 +47,14 @@
    if (MONADIC_INSTRUCTION(opcode))
      nType = nDest;
    else
-     nType = fpa11->fpreg[getFn(opcode)].fType;
+     nType = fpa11->fType[getFn(opcode)];
    
    if (!CONSTANT_FM(opcode))
    {
      register unsigned int Fm = getFm(opcode);
-     if (nType < fpa11->fpreg[Fm].fType)
+     if (nType < fpa11->fType[Fm])
      {
-        nType = fpa11->fpreg[Fm].fType;
+        nType = fpa11->fType[Fm];
      }
    }
 
@@ -71,7 +70,7 @@
       destination register is the correct size.  If not force it
       to be. */
    Fd = getFd(opcode);
-   nType = fpa11->fpreg[Fd].fType;
+   nType = fpa11->fType[Fd];
    if ((0 != nRc) && (nDest != nType))
    {
      switch (nDest)
@@ -79,38 +78,38 @@
        case typeSingle:
        {
          if (typeDouble == nType)
-           fpa11->fpreg[Fd].fValue.fSingle = 
-              float64_to_float32(fpa11->fpreg[Fd].fValue.fDouble);
+           fpa11->fpreg[Fd].fSingle = 
+              float64_to_float32(fpa11->fpreg[Fd].fDouble);
          else
-           fpa11->fpreg[Fd].fValue.fSingle = 
-              floatx80_to_float32(fpa11->fpreg[Fd].fValue.fExtended);
+           fpa11->fpreg[Fd].fSingle = 
+              floatx80_to_float32(fpa11->fpreg[Fd].fExtended);
        }
        break;
           
        case typeDouble:
        {
          if (typeSingle == nType)
-           fpa11->fpreg[Fd].fValue.fDouble = 
-              float32_to_float64(fpa11->fpreg[Fd].fValue.fSingle);
+           fpa11->fpreg[Fd].fDouble = 
+              float32_to_float64(fpa11->fpreg[Fd].fSingle);
          else
-           fpa11->fpreg[Fd].fValue.fDouble = 
-              floatx80_to_float64(fpa11->fpreg[Fd].fValue.fExtended);
+           fpa11->fpreg[Fd].fDouble = 
+              floatx80_to_float64(fpa11->fpreg[Fd].fExtended);
        }
        break;
           
        case typeExtended:
        {
          if (typeSingle == nType)
-           fpa11->fpreg[Fd].fValue.fExtended = 
-              float32_to_floatx80(fpa11->fpreg[Fd].fValue.fSingle);
+           fpa11->fpreg[Fd].fExtended = 
+              float32_to_floatx80(fpa11->fpreg[Fd].fSingle);
          else
-           fpa11->fpreg[Fd].fValue.fExtended = 
-              float64_to_floatx80(fpa11->fpreg[Fd].fValue.fDouble);
+           fpa11->fpreg[Fd].fExtended = 
+              float64_to_floatx80(fpa11->fpreg[Fd].fDouble);
        }
        break;
      }
      
-     fpa11->fpreg[Fd].fType = nDest;
+     fpa11->fType[Fd] = nDest;
    }
    
    return nRc;
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdt.c linux/arch/arm/nwfpe/fpa11_cpdt.c
--- v2.3.22/linux/arch/arm/nwfpe/fpa11_cpdt.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpa11_cpdt.c	Wed Oct 20 16:29:08 1999
@@ -20,7 +20,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
@@ -32,16 +31,16 @@
 extern __inline__
 void loadSingle(const unsigned int Fn,const unsigned int *pMem)
 {
-   fpa11->fpreg[Fn].fType = typeSingle;
-   get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem);
+   fpa11->fType[Fn] = typeSingle;
+   get_user(fpa11->fpreg[Fn].fSingle, pMem);
 }
 
 extern __inline__
 void loadDouble(const unsigned int Fn,const unsigned int *pMem)
 {
    unsigned int *p;
-   p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble;
-   fpa11->fpreg[Fn].fType = typeDouble;
+   p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
+   fpa11->fType[Fn] = typeDouble;
    get_user(p[0], &pMem[1]);
    get_user(p[1], &pMem[0]); /* sign & exponent */
 }   
@@ -50,8 +49,8 @@
 void loadExtended(const unsigned int Fn,const unsigned int *pMem)
 {
    unsigned int *p;
-   p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended;
-   fpa11->fpreg[Fn].fType = typeExtended;
+   p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
+   fpa11->fType[Fn] = typeExtended;
    get_user(p[0], &pMem[0]);  /* sign & exponent */
    get_user(p[1], &pMem[2]);  /* ls bits */
    get_user(p[2], &pMem[1]);  /* ms bits */
@@ -63,11 +62,11 @@
    register unsigned int *p;
    unsigned long x;
 
-   p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
+   p = (unsigned int*)&(fpa11->fpreg[Fn]);
    get_user(x, &pMem[0]);
-   fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003;
+   fpa11->fType[Fn] = (x >> 14) & 0x00000003;
    
-   switch (fpa11->fpreg[Fn].fType)
+   switch (fpa11->fType[Fn])
    {
       case typeSingle:
       case typeDouble:
@@ -94,17 +93,17 @@
    float32 val;
    register unsigned int *p = (unsigned int*)&val;
    
-   switch (fpa11->fpreg[Fn].fType)
+   switch (fpa11->fType[Fn])
    {
       case typeDouble: 
-         val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble);
+         val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
       break;
 
       case typeExtended: 
-         val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended);
+         val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
       break;
 
-      default: val = fpa11->fpreg[Fn].fValue.fSingle;
+      default: val = fpa11->fpreg[Fn].fSingle;
    }
   
    put_user(p[0], pMem);
@@ -116,17 +115,17 @@
    float64 val;
    register unsigned int *p = (unsigned int*)&val;
 
-   switch (fpa11->fpreg[Fn].fType)
+   switch (fpa11->fType[Fn])
    {
       case typeSingle: 
-         val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
+         val = float32_to_float64(fpa11->fpreg[Fn].fSingle);
       break;
 
       case typeExtended:
-         val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended);
+         val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
       break;
 
-      default: val = fpa11->fpreg[Fn].fValue.fDouble;
+      default: val = fpa11->fpreg[Fn].fDouble;
    }
    put_user(p[1], &pMem[0]);	/* msw */
    put_user(p[0], &pMem[1]);	/* lsw */
@@ -138,17 +137,17 @@
    floatx80 val;
    register unsigned int *p = (unsigned int*)&val;
    
-   switch (fpa11->fpreg[Fn].fType)
+   switch (fpa11->fType[Fn])
    {
       case typeSingle: 
-         val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+         val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
       break;
 
       case typeDouble: 
-         val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+         val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
       break;
 
-      default: val = fpa11->fpreg[Fn].fValue.fExtended;
+      default: val = fpa11->fpreg[Fn].fExtended;
    }
    
    put_user(p[0], &pMem[0]); /* sign & exp */
@@ -161,8 +160,8 @@
 {
    register unsigned int nType, *p;
    
-   p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
-   nType = fpa11->fpreg[Fn].fType;
+   p = (unsigned int*)&(fpa11->fpreg[Fn]);
+   nType = fpa11->fType[Fn];
    
    switch (nType)
    {
@@ -187,12 +186,17 @@
 
 unsigned int PerformLDF(const unsigned int opcode)
 {
-   unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
-   
+   unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
+     write_back = WRITE_BACK(opcode);
+
    //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
 
    pBase = (unsigned int*)readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode)) pBase += 2;
+   if (REG_PC == getRn(opcode))
+   {
+     pBase += 2;
+     write_back = 0;
+   }
 
    pFinal = pBase;
    if (BIT_UP_SET(opcode))
@@ -210,19 +214,24 @@
       default: nRc = 0;
    }
    
-   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return nRc;
 }
 
 unsigned int PerformSTF(const unsigned int opcode)
 {
-   unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
+   unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
+     write_back = WRITE_BACK(opcode);
    
    //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
    SetRoundingMode(ROUND_TO_NEAREST);
    
    pBase = (unsigned int*)readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode)) pBase += 2;
+   if (REG_PC == getRn(opcode))
+   {
+     pBase += 2;
+     write_back = 0;
+   }
 
    pFinal = pBase;
    if (BIT_UP_SET(opcode))
@@ -240,15 +249,21 @@
       default: nRc = 0;
    }
    
-   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return nRc;
 }
 
 unsigned int PerformLFM(const unsigned int opcode)
 {
-   unsigned int i, Fd, *pBase, *pAddress, *pFinal;
+   unsigned int i, Fd, *pBase, *pAddress, *pFinal,
+     write_back = WRITE_BACK(opcode);
+
    pBase = (unsigned int*)readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode)) pBase += 2;
+   if (REG_PC == getRn(opcode))
+   {
+     pBase += 2;
+     write_back = 0;
+   }
 
    pFinal = pBase;
    if (BIT_UP_SET(opcode))
@@ -266,16 +281,21 @@
      if (Fd == 8) Fd = 0;
    }
 
-   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return 1;
 }
 
 unsigned int PerformSFM(const unsigned int opcode)
 {
-   unsigned int i, Fd, *pBase, *pAddress, *pFinal;
+   unsigned int i, Fd, *pBase, *pAddress, *pFinal,
+     write_back = WRITE_BACK(opcode);
    
    pBase = (unsigned int*)readRegister(getRn(opcode));
-   if (REG_PC == getRn(opcode)) pBase += 2;
+   if (REG_PC == getRn(opcode))
+   {
+     pBase += 2;
+     write_back = 0;
+   }
    
    pFinal = pBase;
    if (BIT_UP_SET(opcode))
@@ -293,7 +313,7 @@
      if (Fd == 8) Fd = 0;
    }
 
-   if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
+   if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return 1;
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpa11_cprt.c linux/arch/arm/nwfpe/fpa11_cprt.c
--- v2.3.22/linux/arch/arm/nwfpe/fpa11_cprt.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpa11_cprt.c	Wed Oct 20 16:29:08 1999
@@ -20,7 +20,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
 #include "milieu.h"
 #include "softfloat.h"
 #include "fpopcode.h"
@@ -65,37 +64,10 @@
     case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
     case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
 
-#if 0
-    /* ?? Not at all sure about the mode checks here.  Linux never
-       calls the emulator from a non-USR fault but we always run in SVC
-       mode.  Is there even any point trying to emulate the way FPA11
-       behaves in this respect?
-
-       No - and I quote: 'The FPCR may only be present in some
-       implementations: it is there to control the hardware in an
-       implementation-specific manner, ...  The user mode of the
-       ARM is not permitted to use this register, and the WFC and
-       RFC instructions will trap if tried from user mode.'
-       Therefore, we do not provide the RFC and WFC instructions.
-        (rmk, 3/05/1999)
-     */
-    case  WFC_CODE >> 20:
-    {
-       int mode = 0;
-       __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode));
-       nRc = (0x13 == mode) ? 1 : 0;	/* in SVC processor mode? */
-       if (nRc) writeFPCR(readRegister(getRd(opcode)));
-    }
-    break;
-    
-    case  RFC_CODE >> 20:
-    {
-       int mode = 0;
-       __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode));
-       nRc = (0x13 == mode) ? 1 : 0;	/* in SVC processor mode? */
-       if (nRc) writeRegister(getRd(opcode),readFPCR()); break;
-    }
-    break;
+#if 0    /* We currently have no use for the FPCR, so there's no point
+	    in emulating it. */
+    case  WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
+    case  RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
 #endif
 
     default: nRc = 0;
@@ -114,24 +86,24 @@
    {
       case ROUND_SINGLE:
       {
-        fpa11->fpreg[getFn(opcode)].fType = typeSingle;
-        fpa11->fpreg[getFn(opcode)].fValue.fSingle =
+        fpa11->fType[getFn(opcode)] = typeSingle;
+        fpa11->fpreg[getFn(opcode)].fSingle =
 	   int32_to_float32(readRegister(getRd(opcode)));
       }
       break;
 
       case ROUND_DOUBLE:
       {
-        fpa11->fpreg[getFn(opcode)].fType = typeDouble;
-        fpa11->fpreg[getFn(opcode)].fValue.fDouble =
+        fpa11->fType[getFn(opcode)] = typeDouble;
+        fpa11->fpreg[getFn(opcode)].fDouble =
             int32_to_float64(readRegister(getRd(opcode)));
       }
       break;
         
       case ROUND_EXTENDED:
       {
-        fpa11->fpreg[getFn(opcode)].fType = typeExtended;
-        fpa11->fpreg[getFn(opcode)].fValue.fExtended =
+        fpa11->fType[getFn(opcode)] = typeExtended;
+        fpa11->fpreg[getFn(opcode)].fExtended =
 	   int32_to_floatx80(readRegister(getRd(opcode)));
       }
       break;
@@ -149,26 +121,26 @@
    
    SetRoundingMode(opcode);
 
-   switch (fpa11->fpreg[Fn].fType)
+   switch (fpa11->fType[Fn])
    {
       case typeSingle:
       {
          writeRegister(getRd(opcode),
-	               float32_to_int32(fpa11->fpreg[Fn].fValue.fSingle));
+	               float32_to_int32(fpa11->fpreg[Fn].fSingle));
       }
       break;
 
       case typeDouble:
       {
          writeRegister(getRd(opcode),
-	               float64_to_int32(fpa11->fpreg[Fn].fValue.fDouble));
+	               float64_to_int32(fpa11->fpreg[Fn].fDouble));
       }
       break;
       	               
       case typeExtended:
       {
          writeRegister(getRd(opcode),
-	               floatx80_to_int32(fpa11->fpreg[Fn].fValue.fExtended));
+	               floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
       }
       break;
       
@@ -226,27 +198,27 @@
       ?? Might be some mileage in avoiding this conversion if possible.
       Eg, if both operands are 32-bit, detect this and do a 32-bit
       comparison (cheaper than an 80-bit one).  */
-   switch (fpa11->fpreg[Fn].fType)
+   switch (fpa11->fType[Fn])
    {
       case typeSingle: 
         //fp_printk("single.\n");
-	if (float32_is_nan(fpa11->fpreg[Fn].fValue.fSingle))
+	if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
 	   goto unordered;
-        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
+        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
       break;
 
       case typeDouble: 
         //fp_printk("double.\n");
-	if (float64_is_nan(fpa11->fpreg[Fn].fValue.fDouble))
+	if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
 	   goto unordered;
-        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
+        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
       break;
       
       case typeExtended: 
         //fp_printk("extended.\n");
-	if (floatx80_is_nan(fpa11->fpreg[Fn].fValue.fExtended))
+	if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
 	   goto unordered;
-        rFn = fpa11->fpreg[Fn].fValue.fExtended;
+        rFn = fpa11->fpreg[Fn].fExtended;
       break;
       
       default: return 0;
@@ -262,27 +234,27 @@
    else
    {
      //fp_printk("Fm = r%d which contains a ",Fm);
-      switch (fpa11->fpreg[Fm].fType)
+      switch (fpa11->fType[Fm])
       {
          case typeSingle: 
            //fp_printk("single.\n");
-	   if (float32_is_nan(fpa11->fpreg[Fm].fValue.fSingle))
+	   if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
 	      goto unordered;
-           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle);
+           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
          break;
 
          case typeDouble: 
            //fp_printk("double.\n");
-	   if (float64_is_nan(fpa11->fpreg[Fm].fValue.fDouble))
+	   if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
 	      goto unordered;
-           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble);
+           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
          break;
       
          case typeExtended: 
            //fp_printk("extended.\n");
-	   if (floatx80_is_nan(fpa11->fpreg[Fm].fValue.fExtended))
+	   if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
 	      goto unordered;
-           rFm = fpa11->fpreg[Fm].fValue.fExtended;
+           rFm = fpa11->fpreg[Fm].fExtended;
          break;
       
          default: return 0;
@@ -303,6 +275,7 @@
       the data sheet, observation of how the Acorn emulator actually
       behaves (and how programs expect it to) and guesswork.  */
    flags |= CC_OVERFLOW;
+   flags &= ~(CC_ZERO | CC_NEGATIVE);
 
    if (BIT_AC & readFPSR()) flags |= CC_CARRY;
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c
--- v2.3.22/linux/arch/arm/nwfpe/fpmodule.c	Fri Sep 10 23:57:27 1999
+++ linux/arch/arm/nwfpe/fpmodule.c	Wed Oct 20 16:29:08 1999
@@ -1,3 +1,4 @@
+
 /*
     NetWinder Floating Point Emulator
     (c) Rebel.com, 1998-1999
@@ -20,30 +21,16 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
-
-#ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
+#include <linux/config.h>
 
 /* XXX */
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <asm/pgtable.h>
 /* XXX */
 
 #include "softfloat.h"
@@ -62,7 +49,7 @@
 int fp_printk(const char *,...);
 void fp_send_sig(unsigned long sig, PTASK p, int priv);
 #if LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Scott Bambrough <scottb@netwinder.org>");
+MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
 MODULE_DESCRIPTION("NWFPE floating point emulator");
 #endif
 
@@ -73,57 +60,51 @@
 #endif
 
 /* kernel function prototypes required */
-void C_SYMBOL_NAME(fp_setup)(void);
+void fp_setup(void);
 
 /* external declarations for saved kernel symbols */
-extern unsigned int C_SYMBOL_NAME(kern_fp_enter);
+extern void (*kern_fp_enter)(void);
+
+/* Original value of fp_enter from kernel before patched by fpe_init. */ 
+static void (*orig_fp_enter)(void);
 
 /* forward declarations */
 extern void nwfpe_enter(void);
 
-/* Original value of fp_enter from kernel before patched by fpe_init. */ 
-static unsigned int orig_fp_enter;
-
 /* Address of user registers on the kernel stack. */
 unsigned int *userRegisters;
 
-void __init C_SYMBOL_NAME(fpe_version)(void)
+void __init fpe_version(void)
 {
   static const char szTitle[] = "<4>NetWinder Floating Point Emulator ";
-  static const char szVersion[] = "V0.94.1 ";
+  static const char szVersion[] = "V0.95 ";
   static const char szCopyright[] = "(c) 1998-1999 Rebel.com\n";
-  C_SYMBOL_NAME(fp_printk)(szTitle);
-  C_SYMBOL_NAME(fp_printk)(szVersion);
-  C_SYMBOL_NAME(fp_printk)(szCopyright);
+  fp_printk(szTitle);
+  fp_printk(szVersion);
+  fp_printk(szCopyright);
 }
 
 int __init fpe_init(void)
 {
-  /* Display title, version and copyright information. */
-  C_SYMBOL_NAME(fpe_version)();
-
-  /* Save pointer to the old FP handler and then patch ourselves in */
-  orig_fp_enter = C_SYMBOL_NAME(kern_fp_enter);
-  C_SYMBOL_NAME(kern_fp_enter) = (unsigned int)C_SYMBOL_NAME(nwfpe_enter);
+  if (sizeof(FPA11) > sizeof(union fp_state))
+    printk(KERN_ERR "nwfpe: bad structure size\n");
+  else {
+    /* Display title, version and copyright information. */
+    fpe_version();
+
+    /* Save pointer to the old FP handler and then patch ourselves in */
+    orig_fp_enter = kern_fp_enter;
+    kern_fp_enter = nwfpe_enter;
+  }
 
   return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-  return(fpe_init());
-}
-
-void cleanup_module(void)
+void __exit fpe_exit(void)
 {
   /* Restore the values we saved earlier. */
-  C_SYMBOL_NAME(kern_fp_enter) = orig_fp_enter;
+  kern_fp_enter = orig_fp_enter;
 }
-#endif
-
-#define _ARM_pc 60
-#define _ARM_cpsr 64
 
 /*
 ScottB:  November 4, 1998
@@ -135,7 +116,7 @@
 
 [1/1/99: Not quite true any more unfortunately.  There is Linux-specific
 code to access data in user space in some other source files at the 
-moment.  --philb]
+moment (grep for get_user / put_user calls).  --philb]
 
 float_exception_flags is a global variable in SoftFloat.
 
@@ -147,8 +128,9 @@
 
 void float_raise(signed char flags)
 {
-#if 0
-  printk(KERN_DEBUG "NWFPE: exception %08x at %08x from %08x\n", flags,
+#ifdef CONFIG_DEBUG_USER
+  printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n",
+	 current->comm, current->pid, flags,
 	 __builtin_return_address(0), userRegisters[15]);
 #endif
 
@@ -156,7 +138,7 @@
   if (readFPSR() & (flags << 16))
   {
     /* raise exception */
-    C_SYMBOL_NAME(fp_send_sig)(SIGFPE,C_SYMBOL_NAME(current),1);
+    fp_send_sig(SIGFPE, current, 1);
   }
   else
   {
@@ -164,3 +146,6 @@
     writeFPSR(flags);
   }
 }
+
+module_init(fpe_init);
+module_exit(fpe_exit);
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpmodule.inl linux/arch/arm/nwfpe/fpmodule.inl
--- v2.3.22/linux/arch/arm/nwfpe/fpmodule.inl	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/nwfpe/fpmodule.inl	Wed Oct 20 16:29:08 1999
@@ -1,23 +1,23 @@
 /*
    NetWinder Floating Point Emulator
-   (c) Corel Computer Corporation, 1998
+   (c) Rebel.com, 1998-1999
 
-   Direct questions, comments to Scott Bambrough <scottb@corelcomputer.com>
+    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
 
 /* Address of user registers on the kernel stack. */
 extern unsigned int *userRegisters;
@@ -25,64 +25,60 @@
 extern __inline__
 unsigned int readRegister(const unsigned int nReg)
 {
-	/* Note: The CPU thinks it has dealt with the current instruction.  As
-	   a result the program counter has been advanced to the next
-	   instruction, and points 4 bytes beyond the actual instruction
-	   that caused the invalid instruction trap to occur.  We adjust
-	   for this in this routine.  LDF/STF instructions with Rn = PC
-	   depend on the PC being correct, as they use PC+8 in their 
-	   address calculations. */
-	unsigned int val = userRegisters[nReg];
-
-	if (REG_PC == nReg)
-		val -= 4;
-
-	return val;
+  /* Note: The CPU thinks it has dealt with the current instruction.  As
+           a result the program counter has been advanced to the next
+           instruction, and points 4 bytes beyond the actual instruction
+           that caused the invalid instruction trap to occur.  We adjust
+           for this in this routine.  LDF/STF instructions with Rn = PC
+           depend on the PC being correct, as they use PC+8 in their 
+           address calculations. */
+  unsigned int val = userRegisters[nReg];
+  if (REG_PC == nReg) val -= 4;
+  return val;
 }
 
 extern __inline__
 void writeRegister(const unsigned int nReg, const unsigned int val)
 {
-	userRegisters[nReg] = val;
+  userRegisters[nReg] = val;
 }
 
 extern __inline__
 unsigned int readCPSR(void)
 {
-	return (readRegister(REG_CPSR));
+  return(readRegister(REG_CPSR));
 }
 
 extern __inline__
 void writeCPSR(const unsigned int val)
 {
-	writeRegister(REG_CPSR, val);
+  writeRegister(REG_CPSR,val);
 }
 
 extern __inline__
 unsigned int readConditionCodes(void)
 {
 #ifdef __FPEM_TEST__
-	return (0);
+   return(0);
 #else
-	return (readCPSR() & CC_MASK);
+   return(readCPSR() & CC_MASK);
 #endif
 }
 
 extern __inline__
 void writeConditionCodes(const unsigned int val)
 {
-	unsigned int rval;
-
-	/*
-	 * Operate directly on userRegisters since
-	 * the CPSR may be the PC register itself.
-	 */
-	rval = userRegisters[REG_CPSR] & ~CC_MASK;
-	userRegisters[REG_CPSR] = rval | (val & CC_MASK);
+  unsigned int rval;
+  /*
+   * Operate directly on userRegisters since
+   * the CPSR may be the PC register itself.
+   */
+  rval = userRegisters[REG_CPSR] & ~CC_MASK;
+  userRegisters[REG_CPSR] = rval | (val & CC_MASK);
 }
 
 extern __inline__
 unsigned int readMemoryInt(unsigned int *pMem)
 {
-	return *pMem;
+  return *pMem;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/fpopcode.c linux/arch/arm/nwfpe/fpopcode.c
--- v2.3.22/linux/arch/arm/nwfpe/fpopcode.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpopcode.c	Wed Oct 20 16:29:08 1999
@@ -19,7 +19,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpsr.h"
diff -u --recursive --new-file v2.3.22/linux/arch/arm/nwfpe/single_cpdo.c linux/arch/arm/nwfpe/single_cpdo.c
--- v2.3.22/linux/arch/arm/nwfpe/single_cpdo.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/single_cpdo.c	Wed Oct 20 16:29:08 1999
@@ -19,8 +19,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "config.h"
-#include "milieu.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpa11.h"
@@ -51,10 +49,10 @@
    }
    else
    {  
-     switch (fpa11->fpreg[Fm].fType)
+     switch (fpa11->fType[Fm])
      {
         case typeSingle:
-          rFm = fpa11->fpreg[Fm].fValue.fSingle;
+          rFm = fpa11->fpreg[Fm].fSingle;
         break;
         
         default: return 0;
@@ -64,10 +62,10 @@
    if (!MONADIC_INSTRUCTION(opcode))
    {
       Fn = getFn(opcode);
-      switch (fpa11->fpreg[Fn].fType)
+      switch (fpa11->fType[Fn])
       {
         case typeSingle:
-          rFn = fpa11->fpreg[Fn].fValue.fSingle;
+          rFn = fpa11->fpreg[Fn].fSingle;
         break;
 
         default: return 0;
@@ -79,112 +77,112 @@
    {
       /* dyadic opcodes */
       case ADF_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_add(rFn,rFm);
+         fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm);
       break;
 
       case MUF_CODE:
       case FML_CODE:
-        fpa11->fpreg[Fd].fValue.fSingle = float32_mul(rFn,rFm);
+        fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm);
       break;
 
       case SUF_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFn,rFm);
+         fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm);
       break;
 
       case RSF_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFm,rFn);
+         fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn);
       break;
 
       case DVF_CODE:
       case FDV_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFn,rFm);
+         fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm);
       break;
 
       case RDF_CODE:
       case FRD_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFm,rFn);
+         fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn);
       break;
 
 #if 0
       case POW_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFn,rFm);
+         fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm);
       break;
 
       case RPW_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFm,rFn);
+         fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn);
       break;
 #endif
 
       case RMF_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_rem(rFn,rFm);
+         fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm);
       break;
 
 #if 0
       case POL_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_pol(rFn,rFm);
+         fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm);
       break;
 #endif
 
       /* monadic opcodes */
       case MVF_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = rFm;
+         fpa11->fpreg[Fd].fSingle = rFm;
       break;
 
       case MNF_CODE:
          rFm ^= 0x80000000;
-         fpa11->fpreg[Fd].fValue.fSingle = rFm;
+         fpa11->fpreg[Fd].fSingle = rFm;
       break;
 
       case ABS_CODE:
          rFm &= 0x7fffffff;
-         fpa11->fpreg[Fd].fValue.fSingle = rFm;
+         fpa11->fpreg[Fd].fSingle = rFm;
       break;
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = 
+         fpa11->fpreg[Fd].fSingle = 
              int32_to_float32(float32_to_int32(rFm));
       break;
 
       case SQT_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_sqrt(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm);
       break;
 
 #if 0
       case LOG_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_log(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_log(rFm);
       break;
 
       case LGN_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_ln(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_ln(rFm);
       break;
 
       case EXP_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_exp(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_exp(rFm);
       break;
 
       case SIN_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_sin(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_sin(rFm);
       break;
 
       case COS_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_cos(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_cos(rFm);
       break;
 
       case TAN_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_tan(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_tan(rFm);
       break;
 
       case ASN_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_arcsin(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm);
       break;
 
       case ACS_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_arccos(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_arccos(rFm);
       break;
 
       case ATN_CODE:
-         fpa11->fpreg[Fd].fValue.fSingle = float32_arctan(rFm);
+         fpa11->fpreg[Fd].fSingle = float32_arctan(rFm);
       break;
 #endif
 
@@ -197,7 +195,7 @@
       }
    }
 
-   if (0 != nRc) fpa11->fpreg[Fd].fType = typeSingle;
+   if (0 != nRc) fpa11->fType[Fd] = typeSingle;
    return nRc;
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in
--- v2.3.22/linux/arch/arm/vmlinux-armo.lds.in	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/vmlinux-armo.lds.in	Wed Oct 20 16:29:08 1999
@@ -3,16 +3,36 @@
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 OUTPUT_ARCH(arm)
-ENTRY(_start)
+ENTRY(stext)
 SECTIONS
 {
   . = TEXTADDR;
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  __proc_info_begin = .;
+  .proc.info : { *(.proc.info) }
+  __proc_info_end = .;
+  .data.init : { *(.data.init) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+  . = ALIGN(32768);
+  __init_end = .;
+
+  .init.task : {
+	*(.init.task)
+  }
+
   _text = .;			/* Text and read-only data */
   .text : {
 	*(.text)
 	*(.fixup)
 	*(.gnu.warning)
-	} = 0x9090
+	}
   .text.lock : { *(.text.lock) }	/* out-of-line lock text */
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
@@ -26,26 +46,16 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
+  .got : { *(.got) }		/* Global offset table */
+
   _etext = .;			/* End of text section */
 
-  . = ALIGN(8192);
   .data : {			/* Data */
-	*(.init.task)
 	*(.data)
 	CONSTRUCTORS
 	}
 
   _edata = .;			/* End of data section */
-
-  . = ALIGN(32768);		/* Init code and data */
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  __proc_info_begin = .;
-  .proc.info : { *(.proc.info) }
-  __proc_info_end = .;
-  .data.init : { *(.data.init) }
-  . = ALIGN(32768);
-  __init_end = .;
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --recursive --new-file v2.3.22/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in
--- v2.3.22/linux/arch/arm/vmlinux-armv.lds.in	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/vmlinux-armv.lds.in	Wed Oct 20 16:29:08 1999
@@ -3,11 +3,10 @@
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 OUTPUT_ARCH(arm)
-ENTRY(_start)
+ENTRY(stext)
 SECTIONS
 {
   . = TEXTADDR;
-  _text = .;			/* Text and read-only data	*/
   .text : { }			/* Set text start address	*/
 
   __init_begin = .;		/* Init code and data		*/
@@ -38,6 +37,7 @@
   . = ALIGN(4096);
   __netwinder_end = .;
 
+  _text = .;			/* Text and read-only data	*/
   .text.real : {		/* Real text segment		*/
 	*(.text)
 	*(.fixup)
@@ -56,6 +56,8 @@
   __start___ksymtab = .;	/* Kernel symbol table		*/
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
+
+  .got : { *(.got) }		/* Global offset table		*/
 
   _etext = .;			/* End of text section		*/
 
diff -u --recursive --new-file v2.3.22/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.3.22/linux/arch/i386/Makefile	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/Makefile	Sat Oct 16 21:00:11 1999
@@ -84,9 +84,6 @@
 
 vmlinux: arch/i386/vmlinux.lds
 
-arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE
-	$(CPP) -C -P -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds
-
 FORCE: ;
 
 .PHONY: zImage bzImage compressed zlilo bzlilo zdisk bzdisk install \
@@ -119,7 +116,6 @@
 	@$(MAKEBOOT) clean
 
 archmrproper:
-	rm -f arch/i386/vmlinux.lds
 
 archdep:
 	@$(MAKEBOOT) dep
diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v2.3.22/linux/arch/i386/boot/Makefile	Mon Oct 11 15:38:14 1999
+++ linux/arch/i386/boot/Makefile	Tue Oct 19 17:30:18 1999
@@ -51,11 +51,11 @@
 bootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bbootsect: bbootsect.o bsetup
-	$(LD) -Ttext 0x0 -s -oformat binary $< -R bsetup.o -o $@
+bbootsect: bbootsect.o
+	$(LD) -Ttext 0x0 -s -oformat binary $< -o $@
 
 bbootsect.o: bbootsect.s
-	$(AS) -o $@ $<
+	$(AS) --defsym bootsect_kludge=0x220 -o $@ $<
 
 bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S
--- v2.3.22/linux/arch/i386/boot/bootsect.S	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/boot/bootsect.S	Tue Oct 19 17:30:18 1999
@@ -64,12 +64,12 @@
 	movw	%ax, %ds
 	movw	$INITSEG, %ax
 	movw	%ax, %es
-	movw	$128, %cx
+	movw	$256, %cx
 	subw	%si, %si
 	subw	%di, %di
 	cld
 	rep
-	movsl
+	movsw
 	ljmp	$INITSEG, $go
 
 # bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde).  We
@@ -105,11 +105,11 @@
 	movw	$0x78, %bx		# fs:bx is parameter table address
 	pushw	%ds
 	ldsw	%fs:(%bx), %si		# ds:si is source
-	movb	$3, %cl			# copy 12 bytes
+	movb	$6, %cl			# copy 12 bytes
 	cld
 	pushw	%di			# di = 0x4000-12.
 	rep
-	movsl
+	movsw
 	popw	%di
 	popw	%ds
 	movb	$36, 0x4(%di)		# patch sector count
@@ -118,7 +118,7 @@
 
 # Load the setup-sectors directly after the bootblock.
 # Note that 'es' is already set up.
-# Also, cx = 0 from rep movsl above.
+# Also, cx = 0 from rep movsw above.
 
 load_setup:
 	xorb	%ah, %ah		# reset FDC 
@@ -247,7 +247,7 @@
 	xorw	%bx, %bx		# bx is starting address within segment
 rp_read:
 #ifdef __BIG_KERNEL__
-	.word 0x1eff, 0x0220		# lcall *bootsect_kludge in setup.S
+	lcall	bootsect_kludge		# in setup.S
 #else
 	movw	%es, %ax
 	subw	$SYSSEG, %ax
diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.3.22/linux/arch/i386/boot/setup.S	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/boot/setup.S	Tue Oct 19 17:30:18 1999
@@ -209,14 +209,14 @@
 	addw	$SYSSEG, %bx
 	movw	%bx, %cs:start_sys_seg
 # Move rest of setup code/data to here
-	movw	$2048, %di			# four sectors loaded by LILO
+	movw	$4096, %di			# four sectors loaded by LILO
 	subw	%si, %si
 	movw	%cs, %ax			# aka SETUPSEG
 	movw	%ax, %es
 	movw	$SYSSEG, %ax
 	movw	%ax, %ds
 	rep
-	movsl
+	movsw
 	movw	%cs, %ax			# aka SETUPSEG
 	movw	%ax, %ds
 	cmpw	$SIG1, setup_sig1
@@ -532,9 +532,9 @@
 	addw	$0x100, %bx
 	subw	%di, %di
 	subw	%si, %si
-	movw 	$0x400, %cx
+	movw 	$0x800, %cx
 	rep
-	movsl
+	movsw
 	cmpw	%bp, %bx			# assume start_sys_seg > 0x200,
 						# so we will perhaps read one
 						# page more than needed, but
diff -u --recursive --new-file v2.3.22/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v2.3.22/linux/arch/i386/boot/video.S	Mon Oct 11 15:38:14 1999
+++ linux/arch/i386/boot/video.S	Tue Oct 19 17:30:18 1999
@@ -1152,7 +1152,7 @@
 	pushw	%es
 	movw	$0xc000, %bx
 	movw	%bx, %es
-	call	ax				# Call test routine
+	call	*%ax				# Call test routine
 	popw	%es
 	popw	%di
 	popw	%si
@@ -1741,7 +1741,7 @@
 	cmpb	%bh, %al
 	jne	isnot
 	
-	movb	$VIDEO_FIRST_V7>>8, $svga_prefix # Use special mode switching
+	movb	$VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
 	ret
 
 video7_md:
diff -u --recursive --new-file v2.3.22/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.22/linux/arch/i386/config.in	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/config.in	Tue Oct 19 10:22:20 1999
@@ -42,9 +42,17 @@
    define_bool CONFIG_X86_USE_3DNOW y
 fi
 
-choice 'Maximum Physical Memory' \
-	"1GB		CONFIG_1GB \
-	 2GB		CONFIG_2GB" 1GB
+choice 'High Memory Support' \
+	"off    CONFIG_NOHIGHMEM \
+	4GB    CONFIG_HIGHMEM4G \
+	64GB   CONFIG_HIGHMEM64G" off
+if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
+   define_bool CONFIG_HIGHMEM y
+fi
+if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
+   define_bool CONFIG_HIGHMEM y
+   define_bool CONFIG_X86_PAE y
+fi
 
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
@@ -63,7 +71,6 @@
 mainmenu_option next_comment
 comment 'General setup'
 
-bool 'BIGMEM support' CONFIG_BIGMEM
 bool 'Networking support' CONFIG_NET
 bool 'SGI Visual Workstation support' CONFIG_VISWS
 if [ "$CONFIG_VISWS" = "y" ]; then
diff -u --recursive --new-file v2.3.22/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.22/linux/arch/i386/defconfig	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/defconfig	Thu Oct 21 12:32:47 1999
@@ -24,8 +24,9 @@
 CONFIG_X86_POPAD_OK=y
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
-CONFIG_1GB=y
-# CONFIG_2GB is not set
+CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_MTRR is not set
 CONFIG_SMP=y
@@ -40,7 +41,6 @@
 #
 # General setup
 #
-# CONFIG_BIGMEM is not set
 CONFIG_NET=y
 # CONFIG_VISWS is not set
 CONFIG_X86_IO_APIC=y
@@ -54,10 +54,12 @@
 # CONFIG_MCA is not set
 
 #
-# PCMCIA/Cardbus support
+# PCMCIA/CardBus support
 #
 CONFIG_PCMCIA=y
 CONFIG_CARDBUS=y
+CONFIG_I82365=y
+# CONFIG_TCIC is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
@@ -111,7 +113,7 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_AEC6210 is not set
 CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_PIIX_TUNING is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_CPQ_DA is not set
 
@@ -284,11 +286,19 @@
 # CONFIG_WAN is not set
 
 #
-# PCMCIA network devices
+# PCMCIA network device support
 #
-CONFIG_PCMCIA_PCNET=y
+CONFIG_NET_PCMCIA=y
 # CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=y
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
 CONFIG_PCMCIA_RAYCS=y
+# CONFIG_PCMCIA_NETWAVE is not set
+# CONFIG_PCMCIA_WAVELAN is not set
 CONFIG_PCMCIA_NETCARD=y
 
 #
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.3.22/linux/arch/i386/kernel/head.S	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/head.S	Tue Oct 19 10:22:20 1999
@@ -367,11 +367,13 @@
 .org 0x1000
 ENTRY(swapper_pg_dir)
 	.long 0x00102007
-	.fill __USER_PGD_PTRS-1,4,0
-	/* default: 767 entries */
+	.long 0x00103007
+	.fill BOOT_USER_PGD_PTRS-2,4,0
+	/* default: 766 entries */
 	.long 0x00102007
-	/* default: 255 entries */
-	.fill __KERNEL_PGD_PTRS-1,4,0
+	.long 0x00103007
+	/* default: 254 entries */
+	.fill BOOT_KERNEL_PGD_PTRS-2,4,0
 
 /*
  * The page tables are initialized to only 4MB here - the final page
@@ -509,16 +511,156 @@
 	.long 0x3f0007,0x3f1007,0x3f2007,0x3f3007,0x3f4007,0x3f5007,0x3f6007,0x3f7007
 	.long 0x3f8007,0x3f9007,0x3fa007,0x3fb007,0x3fc007,0x3fd007,0x3fe007,0x3ff007
 
-.org 0x3000
-ENTRY(empty_bad_page)
-
+ENTRY(pg1)
+	.long 0x400007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007
+	.long 0x408007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007
+	.long 0x410007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007
+	.long 0x418007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007
+	.long 0x420007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007
+	.long 0x428007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007
+	.long 0x430007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007
+	.long 0x438007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007
+	.long 0x440007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007
+	.long 0x448007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007
+	.long 0x450007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007
+	.long 0x458007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007
+	.long 0x460007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007
+	.long 0x468007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007
+	.long 0x470007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007
+	.long 0x478007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007
+	.long 0x480007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007
+	.long 0x488007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007
+	.long 0x490007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007
+	.long 0x498007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007
+	.long 0x4a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007
+	.long 0x4a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007
+	.long 0x4b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007
+	.long 0x4b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007
+	.long 0x4c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007
+	.long 0x4c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007
+	.long 0x4d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007
+	.long 0x4d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007
+	.long 0x4e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007
+	.long 0x4e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007
+	.long 0x4f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007
+	.long 0x4f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007
+	.long 0x500007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007
+	.long 0x508007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007
+	.long 0x510007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007
+	.long 0x518007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007
+	.long 0x520007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007
+	.long 0x528007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007
+	.long 0x530007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007
+	.long 0x538007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007
+	.long 0x540007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007
+	.long 0x548007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007
+	.long 0x550007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007
+	.long 0x558007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007
+	.long 0x560007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007
+	.long 0x568007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007
+	.long 0x570007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007
+	.long 0x578007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007
+	.long 0x580007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007
+	.long 0x588007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007
+	.long 0x590007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007
+	.long 0x598007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007
+	.long 0x5a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007
+	.long 0x5a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007
+	.long 0x5b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007
+	.long 0x5b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007
+	.long 0x5c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007
+	.long 0x5c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007
+	.long 0x5d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007
+	.long 0x5d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007
+	.long 0x5e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007
+	.long 0x5e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007
+	.long 0x5f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007
+	.long 0x5f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007
+	.long 0x600007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007
+	.long 0x608007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007
+	.long 0x610007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007
+	.long 0x618007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007
+	.long 0x620007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007
+	.long 0x628007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007
+	.long 0x630007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007
+	.long 0x638007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007
+	.long 0x640007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007
+	.long 0x648007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007
+	.long 0x650007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007
+	.long 0x658007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007
+	.long 0x660007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007
+	.long 0x668007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007
+	.long 0x670007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007
+	.long 0x678007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007
+	.long 0x680007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007
+	.long 0x688007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007
+	.long 0x690007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007
+	.long 0x698007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007
+	.long 0x6a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007
+	.long 0x6a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007
+	.long 0x6b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007
+	.long 0x6b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007
+	.long 0x6c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007
+	.long 0x6c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007
+	.long 0x6d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007
+	.long 0x6d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007
+	.long 0x6e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007
+	.long 0x6e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007
+	.long 0x6f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007
+	.long 0x6f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007
+	.long 0x700007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007
+	.long 0x708007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007
+	.long 0x710007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007
+	.long 0x718007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007
+	.long 0x720007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007
+	.long 0x728007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007
+	.long 0x730007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007
+	.long 0x738007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007
+	.long 0x740007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007
+	.long 0x748007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007
+	.long 0x750007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007
+	.long 0x758007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007
+	.long 0x760007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007
+	.long 0x768007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007
+	.long 0x770007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007
+	.long 0x778007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007
+	.long 0x780007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007
+	.long 0x788007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007
+	.long 0x790007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007
+	.long 0x798007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007
+	.long 0x7a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007
+	.long 0x7a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007
+	.long 0x7b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007
+	.long 0x7b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007
+	.long 0x7c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007
+	.long 0x7c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007
+	.long 0x7d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007
+	.long 0x7d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007
+	.long 0x7e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007
+	.long 0x7e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007
+	.long 0x7f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007
+	.long 0x7f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007
 .org 0x4000
-ENTRY(empty_bad_page_table)
+ENTRY(empty_zero_page)
 
 .org 0x5000
-ENTRY(empty_zero_page)
+ENTRY(empty_bad_page)
 
 .org 0x6000
+ENTRY(empty_bad_pte_table)
+
+#if CONFIG_X86_PAE
+
+ .org 0x7000
+ ENTRY(empty_bad_pmd_table)
+
+ .org 0x8000
+
+#else
+
+ .org 0x7000
+
+#endif
 
 /*
  * This starts the data section. Note that the above is all
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.22/linux/arch/i386/kernel/irq.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/irq.c	Tue Oct 19 10:22:20 1999
@@ -20,6 +20,7 @@
  * Naturally it's not a 1:1 relation, but there are similarities.
  */
 
+#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.3.22/linux/arch/i386/kernel/pci-i386.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/pci-i386.c	Fri Oct 15 18:55:26 1999
@@ -177,7 +177,7 @@
  *	(4) Assign new addresses to resources which were either
  *	    not configured at all or misconfigured.  If explicitly
  *	    requested by the user, configure expansion ROM address
- *	    as well.  Finally enable the I/O and Memory bits.
+ *	    as well.
  */
 
 static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
@@ -252,21 +252,18 @@
 static void __init pcibios_assign_resources(void)
 {
 	struct pci_dev *dev;
-	u16 cmd, old_cmd;
 	int idx;
-	int fault = 0;
 	struct resource *r;
 
 	for(dev=pci_devices; dev; dev=dev->next) {
-		pci_read_config_word(dev, PCI_COMMAND, &cmd);
-		old_cmd = cmd;
 		for(idx=0; idx<6; idx++) {
 			r = &dev->resource[idx];
 			if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-			    ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+			    ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)) ||
+			    !dev->class || (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
 				/*
 				 *  Don't touch IDE controllers and I/O ports of video cards!
-				 *  Neither enable anything in their command registers.
+				 *  Also avoid classless devices and host bridges.
 				 */
 				continue;
 			if (!r->start && r->end) {
@@ -275,24 +272,9 @@
 				 *  the BIOS forgot to do so or because we have decided the old
 				 *  address was unusable for some reason.
 				 */
-				if (pcibios_assign_resource(dev, idx) < 0)
-					fault = 1;
-			}
-			if (r->flags & IORESOURCE_IO)
-				cmd |= PCI_COMMAND_IO;
-			if (r->flags & IORESOURCE_MEM)
-				cmd |= PCI_COMMAND_MEMORY;
-		}
-
-		if (cmd != old_cmd) {
-			if (fault)
-				printk("PCI: Not enabling device %s because of resource collisions\n", dev->slot_name);
-			else {
-				printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
-				pci_write_config_word(dev, PCI_COMMAND, cmd);
+				pcibios_assign_resource(dev, idx);
 			}
 		}
-
 		if (pci_probe & PCI_ASSIGN_ROMS) {
 			r = &dev->resource[PCI_ROM_RESOURCE];
 			r->end -= r->start;
@@ -309,4 +291,30 @@
 	pcibios_allocate_resources(0);
 	pcibios_allocate_resources(1);
 	pcibios_assign_resources();
+}
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h
--- v2.3.22/linux/arch/i386/kernel/pci-i386.h	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/pci-i386.h	Fri Oct 15 18:55:26 1999
@@ -18,12 +18,13 @@
 #define PCI_NO_SORT 0x100
 #define PCI_BIOS_SORT 0x200
 #define PCI_NO_CHECKS 0x400
-#define PCI_NO_PEER_FIXUP 0x800
+#define PCI_PEER_FIXUP 0x800
 #define PCI_ASSIGN_ROMS 0x1000
-#define PCI_NO_IRQ_SCAN 0x2000
+#define PCI_BIOS_IRQ_SCAN 0x2000
 
 extern unsigned int pci_probe;
 
 /* pci-i386.c */
 
 void pcibios_resource_survey(void);
+int pcibios_enable_resources(struct pci_dev *);
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.3.22/linux/arch/i386/kernel/pci-pc.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/kernel/pci-pc.c	Fri Oct 15 18:55:26 1999
@@ -688,7 +688,7 @@
 	struct irq_routing_table *rt;
 	int ret, map;
 
-	if (pci_probe & PCI_NO_IRQ_SCAN)
+	if (!(pci_probe & PCI_BIOS_IRQ_SCAN))
 		return NULL;
 	pcibios_irq_page = __get_free_page(GFP_KERNEL);
 	if (!pcibios_irq_page)
@@ -868,7 +868,30 @@
 		if (suba < subb)
 			pci_scan_bus(suba+1, pci_root->ops, NULL);	/* Bus B */
 	}
-	pci_probe |= PCI_NO_PEER_FIXUP;
+}
+
+static void __init pci_fixup_rcc(struct pci_dev *d)
+{
+	/*
+	 * RCC host bridges -- Find and scan all secondary buses.
+	 * Register 0x44 contains first, 0x45 last bus number routed there.
+	 */
+	u8 busno;
+	pci_read_config_byte(d, 0x44, &busno);
+	printk("PCI: RCC host bridge: secondary bus %02x\n", busno);
+	pci_scan_bus(busno, pci_root->ops, NULL);
+}
+
+static void __init pci_fixup_compaq(struct pci_dev *d)
+{
+	/*	
+	 * Compaq host bridges -- Find and scan all secondary buses.
+	 * This time registers 0xc8 and 0xc9.
+	 */
+	u8 busno;
+	pci_read_config_byte(d, 0xc8, &busno);
+	printk("PCI: Compaq host bridge: secondary bus %02x\n", busno);
+	pci_scan_bus(busno, pci_root->ops, NULL);
 }
 
 static void __init pci_fixup_umc_ide(struct pci_dev *d)
@@ -905,6 +928,9 @@
 
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_RCC,	PCI_DEVICE_ID_RCC_HE,		pci_fixup_rcc },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_RCC,	PCI_DEVICE_ID_RCC_LE,		pci_fixup_rcc },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_COMPAQ,	PCI_DEVICE_ID_COMPAQ_6010,	pci_fixup_compaq },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
 	{ 0 }
@@ -919,6 +945,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
+static struct irq_routing_table *pirq_table;
+
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
  */
@@ -974,7 +1002,6 @@
 		 */
 		if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL))
 			printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
-	pci_probe |= PCI_NO_PEER_FIXUP;
 }
 
 /*
@@ -982,7 +1009,7 @@
  *  table, but unfortunately we have to know the interrupt router chip.
  */
 
-static char * __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin)
+static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign)
 {
 	struct irq_info *q;
 	struct pci_dev *router;
@@ -1012,9 +1039,9 @@
 		return NULL;
 	}
 	DBG(" -> PIRQ %02x, mask %04x", pirq, mask);
-	if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+	if (!assign || (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
 		newirq = 0;
-	else for(newirq = 15; newirq && !(mask & (1 << newirq)); newirq--)
+	else for(newirq = 13; newirq && !(mask & (1 << newirq)); newirq--)
 		;
 	if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
 		DBG(" -> router not found\n");
@@ -1068,7 +1095,7 @@
 	struct pci_dev *dev;
 	u8 pin;
 
-	rtable = pcibios_find_irq_routing_table();
+	rtable = pirq_table = pcibios_find_irq_routing_table();
 #ifdef CONFIG_PCI_BIOS
 	if (!rtable && pci_bios_present)
 		rtable = pcibios_get_irq_routing_table();
@@ -1106,7 +1133,7 @@
 					dev->irq = irq;
 				}
 			}
-			rtable = NULL;	/* Avoid IRQ assignment below */
+			pirq_table = NULL;	/* Avoid automatic IRQ assignment */
 		}
 #endif
 		/*
@@ -1114,10 +1141,10 @@
 		 */
 		if (dev->irq >= NR_IRQS)
 			dev->irq = 0;
-		if (pin && !dev->irq && rtable && rtable->version) {
-			char *msg = pcibios_lookup_irq(dev, rtable, pin);
+		if (pin && !dev->irq && pirq_table) {
+			char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 0);
 			if (msg)
-				printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg);
+				printk("PCI: Found IRQ %d for device %s [%s]\n", dev->irq, dev->slot_name, msg);
 		}
 	}
 
@@ -1173,7 +1200,7 @@
 	pci_scan_bus(0, ops, NULL);
 
 	pcibios_fixup_irqs();
-	if (!(pci_probe & PCI_NO_PEER_FIXUP))
+	if (pci_probe & PCI_PEER_FIXUP)
 		pcibios_fixup_peer_bridges();
 	pcibios_resource_survey();
 
@@ -1199,8 +1226,8 @@
 	} else if (!strcmp(str, "nosort")) {
 		pci_probe |= PCI_NO_SORT;
 		return NULL;
-	} else if (!strcmp(str, "noirq")) {
-		pci_probe |= PCI_NO_IRQ_SCAN;
+	} else if (!strcmp(str, "biosirq")) {
+		pci_probe |= PCI_BIOS_IRQ_SCAN;
 		return NULL;
 	}
 #endif
@@ -1214,12 +1241,30 @@
 		return NULL;
 	}
 #endif
-	else if (!strcmp(str, "nopeer")) {
-		pci_probe |= PCI_NO_PEER_FIXUP;
+	else if (!strcmp(str, "peer")) {
+		pci_probe |= PCI_PEER_FIXUP;
 		return NULL;
 	} else if (!strcmp(str, "rom")) {
 		pci_probe |= PCI_ASSIGN_ROMS;
 		return NULL;
 	}
 	return str;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	int err;
+
+	if ((err = pcibios_enable_resources(dev)) < 0)
+		return err;
+	if (!dev->irq && pirq_table) {
+		u8 pin;
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+		if (pin) {
+			char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 1);
+			if (msg)
+				printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg);
+		}
+	}
+	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/pci-visws.c linux/arch/i386/kernel/pci-visws.c
--- v2.3.22/linux/arch/i386/kernel/pci-visws.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/pci-visws.c	Mon Oct 18 11:26:31 1999
@@ -14,6 +14,7 @@
 
 #include <asm/smp.h>
 #include <asm/lithium.h>
+#include <asm/io.h>
 
 #include "pci-i386.h"
 
@@ -128,4 +129,9 @@
 char * __init pcibios_setup(char *str)
 {
 	return str;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	return pcibios_enable_resources(dev);
 }
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.22/linux/arch/i386/kernel/setup.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/kernel/setup.c	Fri Oct 22 10:30:27 1999
@@ -54,7 +54,8 @@
 #ifdef CONFIG_BLK_DEV_RAM
 #include <linux/blk.h>
 #endif
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
 #include <asm/processor.h>
 #include <linux/console.h>
 #include <asm/uaccess.h>
@@ -401,12 +402,15 @@
 } /* add_memory_region */
 
 
-#define LOWMEMSIZE()	((*(unsigned short *)__va(0x413)) * 1024)
-
+/*
+ * Do NOT EVER look at the BIOS memory size location.
+ * It does not work on many machines.
+ */
+#define LOWMEMSIZE()	(0x9f000)
 
 void __init setup_memory_region(void)
 {
-#define E820_DEBUG	0
+#define E820_DEBUG	1
 #ifdef E820_DEBUG
 	int i;
 #endif
@@ -432,9 +436,8 @@
 		memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]);
 #ifdef E820_DEBUG
 		for (i=0; i < e820.nr_map; i++) {
-			printk("e820: %ld @ %08lx ",
-				(unsigned long)(e820.map[i].size),
-				(unsigned long)(e820.map[i].addr));
+			printk("e820: %08x @ %08x ", (int)e820.map[i].size,
+						(int)e820.map[i].addr);
 			switch (e820.map[i].type) {
 			case E820_RAM:	printk("(usable)\n");
 					break;
@@ -464,48 +467,11 @@
 } /* setup_memory_region */
 
 
-void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
+static inline void parse_mem_cmdline (char ** cmdline_p)
 {
-	unsigned long high_pfn, max_pfn;
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int i;
-	int usermem=0;
-
-#ifdef CONFIG_VISWS
-	visws_get_board_type_and_rev();
-#endif
-
- 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
- 	drive_info = DRIVE_INFO;
- 	screen_info = SCREEN_INFO;
-	apm_bios_info = APM_BIOS_INFO;
-	if( SYS_DESC_TABLE.length != 0 ) {
-		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
-		machine_id = SYS_DESC_TABLE.table[0];
-		machine_submodel_id = SYS_DESC_TABLE.table[1];
-		BIOS_revision = SYS_DESC_TABLE.table[2];
-	}
-	aux_device_present = AUX_DEVICE_INFO;
-
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-	setup_memory_region();
-
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
-	init_mm.start_code = (unsigned long) &_text;
-	init_mm.end_code = (unsigned long) &_etext;
-	init_mm.end_data = (unsigned long) &_edata;
-	init_mm.brk = (unsigned long) &_end;
-
-	code_resource.start = virt_to_bus(&_text);
-	code_resource.end = virt_to_bus(&_etext)-1;
-	data_resource.start = virt_to_bus(&_etext);
-	data_resource.end = virt_to_bus(&_edata)-1;
+	int usermem = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -519,8 +485,9 @@
 		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
 		 * <start> to <start>+<mem>, overriding the bios size.
 		 */
-		if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
-			if (to != command_line) to--;
+		if (c == ' ' && !memcmp(from, "mem=", 4)) {
+			if (to != command_line)
+				to--;
 			if (!memcmp(from+4, "nopentium", 9)) {
 				from += 9+4;
 				boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
@@ -542,7 +509,7 @@
 				}
 				mem_size = memparse(from+4, &from);
 				if (*from == '@')
-					start_at = memparse(from+1,&from);
+					start_at = memparse(from+1, &from);
 				else {
 					start_at = HIGH_MEMORY;
 					mem_size -= HIGH_MEMORY;
@@ -559,54 +526,166 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
+}
 
-	/* Find the highest page frame number we have available */
-	max_pfn = 0;
-	for (i=0; i < e820.nr_map; i++) {
-		/* RAM? */
-		if (e820.map[i].type == E820_RAM) {
-			unsigned long end_pfn = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT;
+void __init setup_arch(char **cmdline_p)
+{
+	unsigned long bootmap_size;
+	unsigned long start_pfn, max_pfn, max_low_pfn;
+	int i;
 
-			if (end_pfn > max_pfn)
-				max_pfn = end_pfn;
-		}
+#ifdef CONFIG_VISWS
+	visws_get_board_type_and_rev();
+#endif
+
+ 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+ 	drive_info = DRIVE_INFO;
+ 	screen_info = SCREEN_INFO;
+	apm_bios_info = APM_BIOS_INFO;
+	if( SYS_DESC_TABLE.length != 0 ) {
+		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
+		machine_id = SYS_DESC_TABLE.table[0];
+		machine_submodel_id = SYS_DESC_TABLE.table[1];
+		BIOS_revision = SYS_DESC_TABLE.table[2];
 	}
+	aux_device_present = AUX_DEVICE_INFO;
 
-/*
- * We can only allocate a limited amount of direct-mapped memory
- */
-#define VMALLOC_RESERVE	(128 << 20)	/* 128MB for vmalloc and initrd */
-#define MAXMEM		((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
-#define MAXMEM_PFN	(MAXMEM >> PAGE_SHIFT)
-
-	high_pfn = MAXMEM_PFN;
-	if (max_pfn < high_pfn)
-		high_pfn = max_pfn;
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+	setup_memory_region();
+
+	if (!MOUNT_ROOT_RDONLY)
+		root_mountflags &= ~MS_RDONLY;
+	init_mm.start_code = (unsigned long) &_text;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_end;
+
+	code_resource.start = virt_to_bus(&_text);
+	code_resource.end = virt_to_bus(&_etext)-1;
+	data_resource.start = virt_to_bus(&_etext);
+	data_resource.end = virt_to_bus(&_edata)-1;
+
+	parse_mem_cmdline(cmdline_p);
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
 
 /*
- * But the bigmem stuff may be able to use more of it
- * (but currently only up to about 4GB)
+ * 128MB for vmalloc and initrd
  */
-#ifdef CONFIG_BIGMEM
-	#define MAXBIGMEM	((unsigned long)(~(VMALLOC_RESERVE-1)))
-	#define MAXBIGMEM_PFN	(MAXBIGMEM >> PAGE_SHIFT)
-	if (max_pfn > MAX_PFN)
-		max_pfn = MAX_PFN;
-
-/* When debugging, make half of "normal" memory be BIGMEM memory instead */
-#ifdef BIGMEM_DEBUG
-	high_pfn >>= 1;
-#endif
+#define VMALLOC_RESERVE	(unsigned long)(128 << 20)
+#define MAXMEM		(unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)
+#define MAXMEM_PFN	PFN_DOWN(MAXMEM)
+
+	/*
+	 * partially used pages are not usable - thus
+	 * we are rounding upwards:
+	 */
+	start_pfn = PFN_UP(__pa(&_end));
 
-	bigmem_start = high_pfn << PAGE_SHIFT;
-	bigmem_end = max_pfn << PAGE_SHIFT;
-	printk(KERN_NOTICE "%ldMB BIGMEM available.\n", (bigmem_end-bigmem_start) >> 20);
+	/*
+	 * Find the highest page frame number we have available
+	 */
+	max_pfn = 0;
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long curr_pfn;
+		/* RAM? */
+		if (e820.map[i].type != E820_RAM)
+			continue;
+		curr_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
+		if (curr_pfn > max_pfn)
+			max_pfn = curr_pfn;
+	}
+
+	/*
+	 * Determine low and high memory ranges:
+	 */
+	max_low_pfn = max_pfn;
+	if (max_low_pfn > MAXMEM_PFN)
+		max_low_pfn = MAXMEM_PFN;
+
+#ifdef CONFIG_HIGHMEM
+	highstart_pfn = highend_pfn = max_pfn;
+	if (max_pfn > MAXMEM_PFN) {
+		highstart_pfn = MAXMEM_PFN;
+		highend_pfn = max_pfn;
+		printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+			pages_to_mb(highend_pfn - highstart_pfn));
+	}
 #endif
+	/*
+	 * Initialize the boot-time allocator (with low memory only):
+	 */
+	bootmap_size = init_bootmem(start_pfn, max_low_pfn);
+
+	/*
+	 * FIXME: what about high memory?
+	 */
+	ram_resources[1].end = PFN_PHYS(max_low_pfn);
+
+	/*
+	 * Register fully available low RAM pages with the bootmem allocator.
+	 */
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long curr_pfn, last_pfn, size;
+ 		/*
+		 * Reserve usable low memory
+		 */
+		if (e820.map[i].type != E820_RAM)
+			continue;
+		/*
+		 * We are rounding up the start address of usable memory:
+		 */
+		curr_pfn = PFN_UP(e820.map[i].addr);
+		if (curr_pfn >= max_low_pfn)
+			continue;
+		/*
+		 * ... and at the end of the usable range downwards:
+		 */
+		last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
 
-	ram_resources[1].end = (high_pfn << PAGE_SHIFT)-1;
+		if (last_pfn > max_low_pfn)
+			last_pfn = max_low_pfn;
 
-	*memory_start_p = (unsigned long) &_end;
-	*memory_end_p = PAGE_OFFSET + (high_pfn << PAGE_SHIFT);
+		/*
+		 * .. finally, did all the rounding and playing
+		 * around just make the area go away?
+		 */
+		if (last_pfn <= curr_pfn)
+			continue;
+
+		size = last_pfn - curr_pfn;
+		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
+	}
+	/*
+	 * Reserve the bootmem bitmap itself as well. We do this in two
+	 * steps (first step was init_bootmem()) because this catches
+	 * the (very unlikely) case of us accidentally initializing the
+	 * bootmem allocator with an invalid RAM area.
+	 */
+	reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
+			 bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
+
+	/*
+	 * reserve physical page 0 - it's a special BIOS page on many boxes,
+	 * enabling clean reboots, SMP operation, laptop functions.
+	 */
+	reserve_bootmem(0, PAGE_SIZE);
+
+#ifdef __SMP__
+	/*
+	 * But first pinch a few for the stack/trampoline stuff
+	 * FIXME: Don't need the extra page at 4K, but need to fix
+	 * trampoline before removing it. (see the GDT stuff)
+	 */
+	reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
+	smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
+#endif
 
 #ifdef __SMP__
 	/*
@@ -616,10 +695,11 @@
 #endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
+// FIXME needs to do the new bootmem alloc stuff
 	if (LOADER_TYPE) {
 		initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
 		initrd_end = initrd_start+INITRD_SIZE;
-		if (initrd_end > memory_end) {
+		if (initrd_end > (max_low_pfn << PAGE_SHIFT)) {
 			printk("initrd extends beyond end of memory "
 			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
 			    initrd_end,memory_end);
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.3.22/linux/arch/i386/kernel/smpboot.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/smpboot.c	Wed Oct 20 11:32:17 1999
@@ -39,6 +39,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
 #include <linux/irq.h>
+#include <linux/bootmem.h>
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
@@ -630,12 +631,15 @@
  * We are called very early to get the low memory for the
  * SMP bootup trampoline page.
  */
-unsigned long __init smp_alloc_memory(unsigned long mem_base)
+void __init smp_alloc_memory(void)
 {
-	if (virt_to_phys((void *)mem_base) >= 0x9F000)
+	trampoline_base = (void *) alloc_bootmem_low_pages(PAGE_SIZE);
+	/*
+	 * Has to be in very low memory so we can execute
+	 * real-mode AP code.
+	 */
+	if (__pa(trampoline_base) >= 0x9F000)
 		BUG();
-	trampoline_base = (void *)mem_base;
-	return mem_base + PAGE_SIZE;
 }
 
 /*
@@ -804,11 +808,10 @@
  	apic_write(APIC_DFR, value);
 }
 
-unsigned long __init init_smp_mappings(unsigned long memory_start)
+void __init init_smp_mappings(void)
 {
 	unsigned long apic_phys;
 
-	memory_start = PAGE_ALIGN(memory_start);
 	if (smp_found_config) {
 		apic_phys = mp_lapic_addr;
 	} else {
@@ -818,11 +821,10 @@
 		 * could use the real zero-page, but it's safer
 		 * this way if some buggy code writes to this page ...
 		 */
-		apic_phys = __pa(memory_start);
-		memset((void *)memory_start, 0, PAGE_SIZE);
-		memory_start += PAGE_SIZE;
+		apic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE));
+		memset((void *)apic_phys, 0, PAGE_SIZE);
 	}
-	set_fixmap(FIX_APIC_BASE,apic_phys);
+	set_fixmap(FIX_APIC_BASE, apic_phys);
 	dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
 
 #ifdef CONFIG_X86_IO_APIC
@@ -834,9 +836,8 @@
 			if (smp_found_config) {
 				ioapic_phys = mp_ioapics[i].mpc_apicaddr;
 			} else {
-				ioapic_phys = __pa(memory_start);
-				memset((void *)memory_start, 0, PAGE_SIZE);
-				memory_start += PAGE_SIZE;
+				ioapic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE));
+				memset((void *)ioapic_phys, 0, PAGE_SIZE);
 			}
 			set_fixmap(idx,ioapic_phys);
 			dprintk("mapped IOAPIC to %08lx (%08lx)\n",
@@ -845,8 +846,6 @@
 		}
 	}
 #endif
-
-	return memory_start;
 }
 
 /*
@@ -1112,6 +1111,12 @@
 	smp_callin();
 	while (!atomic_read(&smp_commenced))
 		/* nothing */ ;
+	/*
+	 * low-memory mappings have been cleared, flush them from
+	 * the local TLBs too.
+	 */
+	local_flush_tlb();
+
 	return cpu_idle();
 }
 
@@ -1153,7 +1158,6 @@
 static void __init do_boot_cpu(int i)
 {
 	unsigned long cfg;
-	pgd_t maincfg;
 	struct task_struct *idle;
 	unsigned long send_status, accept_status;
 	int timeout, num_starts, j;
@@ -1207,9 +1211,6 @@
 	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
 	dprintk("3.\n");
 
-	maincfg=swapper_pg_dir[0];
-	((unsigned long *)swapper_pg_dir)[0]=0x102007;
-
 	/*
 	 * Be paranoid about clearing APIC errors.
 	 */
@@ -1367,9 +1368,6 @@
 		cpucount--;
 	}
 
-	swapper_pg_dir[0]=maincfg;
-	local_flush_tlb();
-
 	/* mark "stuck" area as not stuck */
 	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
 }
@@ -1567,14 +1565,9 @@
 
 #ifndef CONFIG_VISWS
 	{
-		unsigned long cfg;
-
 		/*
 		 * Install writable page 0 entry to set BIOS data area.
 		 */
-		cfg = pg0[0];
-		/* writeable, present, addr 0 */
-		pg0[0] = _PAGE_RW | _PAGE_PRESENT | 0;
 		local_flush_tlb();
 
 		/*
@@ -1584,12 +1577,6 @@
 		CMOS_WRITE(0, 0xf);
 
 		*((volatile long *) phys_to_virt(0x467)) = 0;
-
-		/*
-		 * Restore old page 0 entry.
-		 */
-		pg0[0] = cfg;
-		local_flush_tlb();
 	}
 #endif
 
@@ -1646,5 +1633,7 @@
 	 */
 	if (cpu_has_tsc && cpucount)
 		synchronize_tsc_bp();
+
+	zap_low_mappings();
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.3.22/linux/arch/i386/kernel/traps.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/i386/kernel/traps.c	Fri Oct 22 11:35:01 1999
@@ -581,6 +581,7 @@
 
 #endif /* CONFIG_MATH_EMULATION */
 
+#ifndef CONFIG_M686
 void __init trap_init_f00f_bug(void)
 {
 	unsigned long page;
@@ -596,8 +597,8 @@
 	pgd = pgd_offset(&init_mm, page);
 	pmd = pmd_offset(pgd, page);
 	pte = pte_offset(pmd, page);
-	free_page(pte_page(*pte));
-	*pte = mk_pte(&idt_table, PAGE_KERNEL_RO);
+	__free_page(pte_page(*pte));
+	*pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO);
 	local_flush_tlb();
 
 	/*
@@ -608,6 +609,7 @@
 	idt = (struct desc_struct *)page;
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
 }
+#endif
 
 #define _set_gate(gate_addr,type,dpl,addr) \
 do { \
@@ -772,7 +774,7 @@
 #endif
 void __init trap_init(void)
 {
-	if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
+	if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
 		EISA_bus = 1;
 
 	set_trap_gate(0,&divide_error);
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c
--- v2.3.22/linux/arch/i386/kernel/visws_apic.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/visws_apic.c	Mon Oct 18 11:26:31 1999
@@ -37,7 +37,7 @@
 
 #include <asm/cobalt.h>
 
-#include "irq.h"
+#include <linux/irq.h>
 
 /*
  * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
diff -u --recursive --new-file v2.3.22/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.3.22/linux/arch/i386/kernel/vm86.c	Mon Jul 19 15:23:49 1999
+++ linux/arch/i386/kernel/vm86.c	Tue Oct 19 10:22:20 1999
@@ -102,7 +102,7 @@
 	if (pgd_none(*pgd))
 		return;
 	if (pgd_bad(*pgd)) {
-		printk("vm86: bad pgd entry [%p]:%08lx\n", pgd, pgd_val(*pgd));
+		pgd_ERROR(*pgd);
 		pgd_clear(pgd);
 		return;
 	}
@@ -110,7 +110,7 @@
 	if (pmd_none(*pmd))
 		return;
 	if (pmd_bad(*pmd)) {
-		printk("vm86: bad pmd entry [%p]:%08lx\n", pmd, pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		return;
 	}
diff -u --recursive --new-file v2.3.22/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.3.22/linux/arch/i386/lib/Makefile	Mon Oct 11 15:38:14 1999
+++ linux/arch/i386/lib/Makefile	Tue Oct 19 12:36:05 1999
@@ -7,7 +7,7 @@
 
 L_TARGET = lib.a
 L_OBJS  = checksum.o old-checksum.o delay.o \
-	usercopy.o getuser.o putuser.o
+	usercopy.o getuser.o putuser.o iodebug.o
 
 ifdef CONFIG_X86_USE_3DNOW
 L_OBJS += mmx.o
diff -u --recursive --new-file v2.3.22/linux/arch/i386/lib/iodebug.c linux/arch/i386/lib/iodebug.c
--- v2.3.22/linux/arch/i386/lib/iodebug.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/lib/iodebug.c	Tue Oct 19 12:26:53 1999
@@ -0,0 +1,19 @@
+#include <asm/io.h>
+
+void * __io_virt_debug(unsigned long x, const char *file, int line)
+{
+	if (x < PAGE_OFFSET) {
+		printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line);
+		return __va(x);
+	}
+	return (void *)x;
+}
+
+unsigned long __io_phys_debug(unsigned long x, const char *file, int line)
+{
+	if (x < PAGE_OFFSET) {
+		printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line);
+		return x;
+	}
+	return __pa(x);
+}
diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile
--- v2.3.22/linux/arch/i386/mm/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/mm/Makefile	Tue Oct 19 10:22:20 1999
@@ -10,8 +10,4 @@
 O_TARGET := mm.o
 O_OBJS	 := init.o fault.o ioremap.o extable.o
 
-ifeq ($(CONFIG_BIGMEM),y)
-O_OBJS += bigmem.o
-endif
-
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/bigmem.c linux/arch/i386/mm/bigmem.c
--- v2.3.22/linux/arch/i386/mm/bigmem.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/mm/bigmem.c	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-/*
- * BIGMEM IA32 code and variables.
- *
- * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
- *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de
- */
-
-#include <linux/mm.h>
-#include <linux/bigmem.h>
-
-unsigned long bigmem_start, bigmem_end;
-
-/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the
-   physical space so we can cache the place of the first one and move
-   around without checking the pgd every time. */
-pte_t *kmap_pte;
-pgprot_t kmap_prot;
-
-#define kmap_get_fixmap_pte(vaddr)					\
-	pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
-
-void __init kmap_init(void)
-{
-	unsigned long kmap_vstart;
-
-	/* cache the first kmap pte */
-	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
-	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
-
-	kmap_prot = PAGE_KERNEL;
-	if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
-		pgprot_val(kmap_prot) |= _PAGE_GLOBAL;
-}
diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.22/linux/arch/i386/mm/fault.c	Mon Aug  2 15:56:47 1999
+++ linux/arch/i386/mm/fault.c	Tue Oct 19 10:22:20 1999
@@ -76,6 +76,31 @@
 	return 0;
 }
 
+static inline void handle_wp_test (void)
+{
+	const unsigned long vaddr = PAGE_OFFSET;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	/*
+	 * make it read/writable temporarily, so that the fault
+	 * can be handled.
+	 */
+	pgd = swapper_pg_dir + __pgd_offset(vaddr);
+	pmd = pmd_offset(pgd, vaddr);
+	pte = pte_offset(pmd, vaddr);
+	*pte = mk_pte_phys(0, PAGE_KERNEL);
+	local_flush_tlb();
+
+	boot_cpu_data.wp_works_ok = 1;
+	/*
+	 * Beware: Black magic here. The printk is needed here to flush
+	 * CPU state on certain buggy processors.
+	 */
+	printk("Ok");
+}
+
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 extern unsigned long idt;
 
@@ -226,15 +251,8 @@
  * First we check if it was the bootup rw-test, though..
  */
 	if (boot_cpu_data.wp_works_ok < 0 &&
-	    address == PAGE_OFFSET && (error_code & 1)) {
-		boot_cpu_data.wp_works_ok = 1;
-		pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_KERNEL));
-		local_flush_tlb();
-		/*
-		 * Beware: Black magic here. The printk is needed here to flush
-		 * CPU state on certain buggy processors.
-		 */
-		printk("Ok");
+			address == PAGE_OFFSET && (error_code & 1)) {
+		handle_wp_test();
 		return;
 	}
 
diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.22/linux/arch/i386/mm/init.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/i386/mm/init.c	Wed Oct 20 11:32:17 1999
@@ -22,7 +22,9 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -32,22 +34,81 @@
 #include <asm/fixmap.h>
 #include <asm/e820.h>
 
-static unsigned long totalram = 0;
-static unsigned long totalbig = 0;
+unsigned long highstart_pfn, highend_pfn;
+static unsigned long totalram_pages = 0;
+static unsigned long totalhigh_pages = 0;
 
 extern void show_net_buffers(void);
-extern unsigned long init_smp_mappings(unsigned long);
 
-void __bad_pte_kernel(pmd_t *pmd)
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving an inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+
+/*
+ * These are allocated in head.S so that we get proper page alignment.
+ * If you change the size of these then change head.S as well.
+ */
+extern char empty_bad_page[PAGE_SIZE];
+#if CONFIG_X86_PAE
+extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD];
+#endif
+extern pte_t empty_bad_pte_table[PTRS_PER_PTE];
+
+/*
+ * We init them before every return and make them writable-shared.
+ * This guarantees we get out of the kernel in some more or less sane
+ * way.
+ */
+#if CONFIG_X86_PAE
+static pmd_t * get_bad_pmd_table(void)
 {
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+	pmd_t v;
+	int i;
+
+	pmd_val(v) = _PAGE_TABLE + __pa(empty_bad_pte_table);
+
+	for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++)
+		empty_bad_pmd_table[i] = v;
+
+	return empty_bad_pmd_table;
 }
+#endif
 
-void __bad_pte(pmd_t *pmd)
+static pte_t * get_bad_pte_table(void)
 {
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+	pte_t v;
+	int i;
+
+	v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
+
+	for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
+		empty_bad_pte_table[i] = v;
+
+	return empty_bad_pte_table;
+}
+
+
+
+void __handle_bad_pmd(pmd_t *pmd)
+{
+	pmd_ERROR(*pmd);
+	pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table());
+}
+
+void __handle_bad_pmd_kernel(pmd_t *pmd)
+{
+	pmd_ERROR(*pmd);
+	pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table());
 }
 
 pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
@@ -57,16 +118,16 @@
 	pte = (pte_t *) __get_free_page(GFP_KERNEL);
 	if (pmd_none(*pmd)) {
 		if (pte) {
-			clear_page((unsigned long)pte);
+			clear_page(pte);
 			pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
 			return pte + offset;
 		}
-		pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+		pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table());
 		return NULL;
 	}
 	free_page((unsigned long)pte);
 	if (pmd_bad(*pmd)) {
-		__bad_pte_kernel(pmd);
+		__handle_bad_pmd_kernel(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + offset;
@@ -79,19 +140,19 @@
 	pte = (unsigned long) __get_free_page(GFP_KERNEL);
 	if (pmd_none(*pmd)) {
 		if (pte) {
-			clear_page(pte);
+			clear_page((void *)pte);
 			pmd_val(*pmd) = _PAGE_TABLE + __pa(pte);
-			return (pte_t *)(pte + offset);
+			return (pte_t *)pte + offset;
 		}
-		pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+		pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table());
 		return NULL;
 	}
 	free_page(pte);
 	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
+		__handle_bad_pmd(pmd);
 		return NULL;
 	}
-	return (pte_t *) (pmd_page(*pmd) + offset);
+	return (pte_t *) pmd_page(*pmd) + offset;
 }
 
 int do_check_pgt_cache(int low, int high)
@@ -110,52 +171,36 @@
 	return freed;
 }
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving an inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-pte_t * __bad_pagetable(void)
+/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the
+   physical space so we can cache the place of the first one and move
+   around without checking the pgd every time. */
+
+#if CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+#define kmap_get_fixmap_pte(vaddr)					\
+	pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+
+void __init kmap_init(void)
 {
-	extern char empty_bad_page_table[PAGE_SIZE];
-	int d0, d1;
+	unsigned long kmap_vstart;
+
+	/* cache the first kmap pte */
+	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
 
-	__asm__ __volatile__("cld ; rep ; stosl"
-			     : "=&D" (d0), "=&c" (d1)
-			     : "a" (pte_val(BAD_PAGE)),
-			     "0" ((long) empty_bad_page_table),
-			     "1" (PAGE_SIZE/4)
-			     : "memory");
-	return (pte_t *) empty_bad_page_table;
-}
-
-pte_t __bad_page(void)
-{
-	extern char empty_bad_page[PAGE_SIZE];
-	int d0, d1;
-
-	__asm__ __volatile__("cld ; rep ; stosl"
-			     : "=&D" (d0), "=&c" (d1)
-			     : "a" (0),
-			     "0" ((long) empty_bad_page),
-			     "1" (PAGE_SIZE/4)
-			     : "memory");
-	return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED));
+	kmap_prot = PAGE_KERNEL;
+	if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+		pgprot_val(kmap_prot) |= _PAGE_GLOBAL;
 }
+#endif
 
 void show_mem(void)
 {
-	int i,free = 0,total = 0,reserved = 0;
+	int i,free = 0, total = 0, reserved = 0;
 	int shared = 0, cached = 0;
-	int bigmem = 0;
+	int highmem = 0;
 
 	printk("Mem-info:\n");
 	show_free_areas();
@@ -163,8 +208,8 @@
 	i = max_mapnr;
 	while (i-- > 0) {
 		total++;
-		if (PageBIGMEM(mem_map+i))
-			bigmem++;
+		if (PageHighMem(mem_map+i))
+			highmem++;
 		if (PageReserved(mem_map+i))
 			reserved++;
 		else if (PageSwapCache(mem_map+i))
@@ -174,59 +219,42 @@
 		else
 			shared += page_count(mem_map+i) - 1;
 	}
-	printk("%d pages of RAM\n",total);
-	printk("%d pages of BIGMEM\n",bigmem);
+	printk("%d pages of RAM\n", total);
+	printk("%d pages of HIGHMEM\n",highmem);
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
 }
 
-extern unsigned long free_area_init(unsigned long, unsigned long);
-
 /* References to section boundaries */
 
 extern char _text, _etext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
-/*
- * allocate page table(s) for compile-time fixed mappings
- */
-static unsigned long __init fixmap_init(unsigned long start_mem)
-{
-	pgd_t * pg_dir;
-	unsigned int idx;
-	unsigned long address;
-
-	start_mem = PAGE_ALIGN(start_mem);
-
-	for (idx=1; idx <= __end_of_fixed_addresses; idx += PTRS_PER_PTE)
-	{
-		address = __fix_to_virt(__end_of_fixed_addresses-idx);
-		pg_dir = swapper_pg_dir + (address >> PGDIR_SHIFT);
-		memset((void *)start_mem, 0, PAGE_SIZE);
-		pgd_val(*pg_dir) = _PAGE_TABLE | __pa(start_mem);
-		start_mem += PAGE_SIZE;
-	}
-
-	return start_mem;
-}
-
 static void set_pte_phys (unsigned long vaddr, unsigned long phys)
 {
 	pgprot_t prot;
-	pte_t * pte;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
 
-	pte = pte_offset(pmd_offset(pgd_offset_k(vaddr), vaddr), vaddr);
+	pgd = swapper_pg_dir + __pgd_offset(vaddr);
+	pmd = pmd_offset(pgd, vaddr);
+	pte = pte_offset(pmd, vaddr);
 	prot = PAGE_KERNEL;
 	if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
 		pgprot_val(prot) |= _PAGE_GLOBAL;
 	set_pte(pte, mk_pte_phys(phys, prot));
 
-	local_flush_tlb();
+	/*
+	 * It's enough to flush this one mapping.
+	 */
+	__flush_tlb_one(vaddr);
 }
 
 void set_fixmap (enum fixed_addresses idx, unsigned long phys)
@@ -240,6 +268,123 @@
 	set_pte_phys (address,phys);
 }
 
+static void __init pagetable_init(void)
+{
+	pgd_t *pgd, *pgd_base;
+	pmd_t *pmd;
+	pte_t *pte;
+	int i, j, k;
+	unsigned long vaddr;
+	unsigned long end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
+
+	pgd_base = swapper_pg_dir;
+
+	vaddr = PAGE_OFFSET;
+	i = __pgd_offset(vaddr);
+	pgd = pgd_base + i;
+
+	for (; (i < PTRS_PER_PGD) && (vaddr <= end); pgd++, i++) {
+		vaddr = i*PGDIR_SIZE;
+#if CONFIG_X86_PAE
+		pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+		memset((void*)pmd, 0, PAGE_SIZE);
+		pgd_val(*pgd) = __pa(pmd) + 0x1;
+#else
+		pmd = (pmd_t *)pgd;
+#endif
+		if (pmd != pmd_offset(pgd, 0))
+			BUG();
+		for (j = 0; (j < PTRS_PER_PMD) && (vaddr <= end); pmd++, j++) {
+			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
+			if (cpu_has_pse) {
+				unsigned long __pe;
+
+				set_in_cr4(X86_CR4_PSE);
+				boot_cpu_data.wp_works_ok = 1;
+				__pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr);
+				/* Make it "global" too if supported */
+				if (cpu_has_pge) {
+					set_in_cr4(X86_CR4_PGE);
+					__pe += _PAGE_GLOBAL;
+				}
+				pmd_val(*pmd) = __pe;
+				continue;
+			}
+
+			pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+			memset((void*)pte, 0, PAGE_SIZE);
+			pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
+
+			if (pte != pte_offset(pmd, 0))
+				BUG();
+
+			for (k = 0;
+				(k < PTRS_PER_PTE) && (vaddr <= end);
+					pte++, k++) {
+				vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
+				*pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
+			}
+		}
+	}
+
+	/*
+	 * Fixed mappings, only the page table structure has to be
+	 * created - mappings will be set by set_fixmap():
+	 */
+
+	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+	i = __pgd_offset(vaddr);
+	j = __pmd_offset(vaddr);
+	pgd = pgd_base + i;
+
+	for ( ; (i < PTRS_PER_PGD) && vaddr; pgd++, i++) {
+#if CONFIG_X86_PAE
+		if (pgd_none(*pgd)) {
+			pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+			memset((void*)pmd, 0, PAGE_SIZE);
+			pgd_val(*pgd) = __pa(pmd) + 0x1;
+			if (pmd != pmd_offset(pgd, vaddr))
+				BUG();
+		}
+		pmd = pmd_offset(pgd, vaddr);
+#else
+		pmd = (pmd_t *)pgd;
+#endif
+		for (; (j < PTRS_PER_PMD) && vaddr; pmd++, j++) {
+			if (pmd_none(*pmd)) {
+				pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+				memset((void*)pte, 0, PAGE_SIZE);
+				pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
+				if (pte != pte_offset(pmd, 0))
+					BUG();
+			}
+			vaddr += PMD_SIZE;
+		}
+		j = 0;
+	}
+
+#if CONFIG_X86_PAE
+	/*
+	 * Add low memory identity-mappings - SMP needs it when
+	 * starting up on an AP from real-mode. In the non-PAE
+	 * case we already have these mappings through head.S.
+	 * All user-space mappings are explicitly cleared after
+	 * SMP startup.
+	 */
+	pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
+#endif
+}
+
+void __init zap_low_mappings (void)
+{
+	int i;
+	/*
+	 * Zap initial low-memory mappings:
+	 */
+	for (i = 0; i < USER_PTRS_PER_PGD; i++)
+		pgd_clear(swapper_pg_dir + i);
+}
+
 /*
  * paging_init() sets up the page tables - note that the first 4MB are
  * already mapped by head.S.
@@ -247,89 +392,36 @@
  * This routines also unmaps the page at virtual kernel address 0, so
  * that we can trap those pesky NULL-reference errors in the kernel.
  */
-unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init paging_init(void)
 {
-	pgd_t * pg_dir;
-	pte_t * pg_table;
-	unsigned long tmp;
-	unsigned long address;
+	pagetable_init();
 
-/*
- * Physical page 0 is special; it's not touched by Linux since BIOS
- * and SMM (for laptops with [34]86/SL chips) may need it.  It is read
- * and write protected to detect null pointer references in the
- * kernel.
- * It may also hold the MP configuration table when we are booting SMP.
- */
-	start_mem = PAGE_ALIGN(start_mem);
-	address = PAGE_OFFSET;
-	pg_dir = swapper_pg_dir;
-	/* unmap the original low memory mappings */
-	pgd_val(pg_dir[0]) = 0;
-
-	/* Map whole memory from PAGE_OFFSET */
-	pg_dir += USER_PGD_PTRS;
-	while (address < end_mem) {
-		/*
-		 * If we're running on a Pentium CPU, we can use the 4MB
-		 * page tables. 
-		 *
-		 * The page tables we create span up to the next 4MB
-		 * virtual memory boundary, but that's OK as we won't
-		 * use that memory anyway.
-		 */
-		if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) {
-			unsigned long __pe;
-
-			set_in_cr4(X86_CR4_PSE);
-			boot_cpu_data.wp_works_ok = 1;
-			__pe = _KERNPG_TABLE + _PAGE_4M + __pa(address);
-			/* Make it "global" too if supported */
-			if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) {
-				set_in_cr4(X86_CR4_PGE);
-				__pe += _PAGE_GLOBAL;
-			}
-			pgd_val(*pg_dir) = __pe;
-			pg_dir++;
-			address += 4*1024*1024;
-			continue;
-		}
+	__asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir)));
 
-		/*
-		 * We're on a [34]86, use normal page tables.
-		 * pg_table is physical at this point
-		 */
-		pg_table = (pte_t *) (PAGE_MASK & pgd_val(*pg_dir));
-		if (!pg_table) {
-			pg_table = (pte_t *) __pa(start_mem);
-			start_mem += PAGE_SIZE;
-		}
+#if CONFIG_X86_PAE
+	/*
+	 * We will bail out later - printk doesnt work right now so
+	 * the user would just see a hanging kernel.
+	 */
+	if (cpu_has_pae)
+		set_in_cr4(X86_CR4_PAE);
+#endif
 
-		pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pg_table;
-		pg_dir++;
+	__flush_tlb();
 
-		/* now change pg_table to kernel virtual addresses */
-		pg_table = (pte_t *) __va(pg_table);
-		for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
-			pte_t pte = mk_pte(address, PAGE_KERNEL);
-			if (address >= end_mem)
-				pte_val(pte) = 0;
-			set_pte(pg_table, pte);
-			address += PAGE_SIZE;
-		}
-	}
-	start_mem = fixmap_init(start_mem);
 #ifdef __SMP__
-	start_mem = init_smp_mappings(start_mem);
+	init_smp_mappings();
 #endif
-	local_flush_tlb();
 
-#ifndef CONFIG_BIGMEM
-	return free_area_init(start_mem, end_mem);
-#else
+#ifdef CONFIG_HIGHMEM
 	kmap_init(); /* run after fixmap_init */
-	return free_area_init(start_mem, bigmem_end + PAGE_OFFSET);
 #endif
+#ifdef CONFIG_HIGHMEM
+	free_area_init(highend_pfn);
+#else
+	free_area_init(max_low_pfn);
+#endif
+	return;
 }
 
 /*
@@ -340,23 +432,38 @@
 
 void __init test_wp_bit(void)
 {
-	unsigned char tmp_reg;
-	unsigned long old = pg0[0];
+/*
+ * Ok, all PAE-capable CPUs are definitely handling the WP bit right.
+ */
+//#ifndef CONFIG_X86_PAE
+	const unsigned long vaddr = PAGE_OFFSET;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte, old_pte;
+	char tmp_reg;
 
 	printk("Checking if this processor honours the WP bit even in supervisor mode... ");
-	pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
+
+	pgd = swapper_pg_dir + __pgd_offset(vaddr);
+	pmd = pmd_offset(pgd, vaddr);
+	pte = pte_offset(pmd, vaddr);
+	old_pte = *pte;
+	*pte = mk_pte_phys(0, PAGE_READONLY);
 	local_flush_tlb();
+
 	__asm__ __volatile__(
 		"jmp 1f; 1:\n"
 		"movb %0,%1\n"
 		"movb %1,%0\n"
 		"jmp 1f; 1:\n"
-		:"=m" (*(char *) __va(0)),
+		:"=m" (*(char *) vaddr),
 		 "=q" (tmp_reg)
 		:/* no inputs */
 		:"memory");
-	pg0[0] = old;
+
+	*pte = old_pte;
 	local_flush_tlb();
+
 	if (boot_cpu_data.wp_works_ok < 0) {
 		boot_cpu_data.wp_works_ok = 0;
 		printk("No.\n");
@@ -365,136 +472,95 @@
 #endif
 	} else
 		printk(".\n");
+//#endif
 }
 
-static void __init mem_init_region(unsigned long pfn, unsigned long count, unsigned long start_mem_pfn)
+static inline int page_is_ram (unsigned long pagenr)
 {
-	printk("memory region: %luk @ %08lx000\n", count << 2, pfn);
+	int i;
 
-	do {
-		if (pfn >= max_mapnr)
-			break;
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long addr, size;
 
-		/* Avoid the kernel mapping between HIGH_MEMORY and "start_mem".. */
-		if (pfn < (HIGH_MEMORY >> PAGE_SHIFT) || pfn >= start_mem_pfn)
-			clear_bit(PG_reserved, &mem_map[pfn].flags);
-
-		pfn++;
-	} while (--count > 0);
+		if (e820.map[i].type != E820_RAM)	/* not usable memory */
+			continue;
+		addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+		size = e820.map[i].size >> PAGE_SHIFT;
+		if  ((pagenr >= addr) && (pagenr < addr+size))
+			return 1;
+	}
+	return 0;
 }
 
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+void __init mem_init(void)
 {
-	unsigned long start_low_mem = PAGE_SIZE;
 	int codepages = 0;
 	int reservedpages = 0;
 	int datapages = 0;
 	int initpages = 0;
-	unsigned long tmp;
-	int i, avail;
+#ifdef CONFIG_HIGHMEM
+	int tmp;
 
-	end_mem &= PAGE_MASK;
-#ifdef CONFIG_BIGMEM
-	bigmem_start = PAGE_ALIGN(bigmem_start);
-	bigmem_end &= PAGE_MASK;
-#endif
-	high_memory = (void *) end_mem;
-#ifndef CONFIG_BIGMEM
-	max_mapnr = num_physpages = MAP_NR(end_mem);
+	if (!mem_map)
+		BUG();
+	highmem_start_page = mem_map + highstart_pfn;
+	/* cache the highmem_mapnr */
+	highmem_mapnr = highstart_pfn;
+	max_mapnr = num_physpages = highend_pfn;
 #else
-	max_mapnr = num_physpages = PHYSMAP_NR(bigmem_end);
-	/* cache the bigmem_mapnr */
-	bigmem_mapnr = PHYSMAP_NR(bigmem_start);
+	max_mapnr = num_physpages = max_low_pfn;
 #endif
+	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
 	/* clear the zero-page */
 	memset(empty_zero_page, 0, PAGE_SIZE);
 
-	/* mark usable pages in the mem_map[] */
-	start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET;
+	/* this will put all low memory onto the freelists */
+	totalram_pages += free_all_bootmem();
 
-#ifdef __SMP__
-	/*
-	 * But first pinch a few for the stack/trampoline stuff
-	 *	FIXME: Don't need the extra page at 4K, but need to fix
-	 *	trampoline before removing it. (see the GDT stuff)
-	 *
-	 */
-	start_low_mem += PAGE_SIZE;				/* 32bit startup code */
-	start_low_mem = smp_alloc_memory(start_low_mem); 	/* AP processor stacks */
-#endif
-	start_mem = PAGE_ALIGN(start_mem);
-
-	/* walk the whitelist, unreserving good memory
-	 */
-	for (avail = i = 0; i < e820.nr_map; i++) {
-		unsigned long start_pfn, end_pfn;
-
-		if (e820.map[i].type != E820_RAM)	/* not usable memory */
-			continue;
-
-		start_pfn = (e820.map[i].addr + PAGE_SIZE - 1) >> PAGE_SHIFT;
-		end_pfn = (e820.map[i].addr + e820.map[i].size) >> PAGE_SHIFT;
-
-		/* We have a certain amount of low memory reserved */
-		if (start_pfn < MAP_NR(start_low_mem))
-			start_pfn = MAP_NR(start_low_mem);
+#ifdef CONFIG_HIGHMEM
+	for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
+		struct page *page = mem_map + tmp;
 
-		if (end_pfn <= start_pfn)
-			continue;
-
-		mem_init_region(start_pfn, end_pfn - start_pfn, MAP_NR(start_mem));
-	}
-
-	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
-		if (tmp >= MAX_DMA_ADDRESS)
-			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
-		if (PageReserved(mem_map+MAP_NR(tmp))) {
-			if (tmp >= (unsigned long) &_text && tmp < (unsigned long) &_edata) {
-				if (tmp < (unsigned long) &_etext)
-					codepages++;
-				else
-					datapages++;
-			} else if (tmp >= (unsigned long) &__init_begin
-				   && tmp < (unsigned long) &__init_end)
-				initpages++;
-			else if (tmp >= (unsigned long) &__bss_start
-				 && tmp < (unsigned long) start_mem)
-				datapages++;
-			else
-				reservedpages++;
+		if (!page_is_ram(tmp)) {
+			SetPageReserved(page);
 			continue;
 		}
-		set_page_count(mem_map+MAP_NR(tmp), 1);
-		totalram += PAGE_SIZE;
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
-#endif
-			free_page(tmp);
-	}
-#ifdef CONFIG_BIGMEM
-	for (tmp = bigmem_start; tmp < bigmem_end;  tmp += PAGE_SIZE) {
-		clear_bit(PG_reserved, &mem_map[PHYSMAP_NR(tmp)].flags);
-		set_bit(PG_BIGMEM, &mem_map[PHYSMAP_NR(tmp)].flags);
-		atomic_set(&mem_map[PHYSMAP_NR(tmp)].count, 1);
-		free_page(tmp + PAGE_OFFSET);
-		totalbig += PAGE_SIZE;
+		ClearPageReserved(page);
+		set_bit(PG_highmem, &page->flags);
+		atomic_set(&page->count, 1);
+		__free_page(page);
+		totalhigh_pages++;
 	}
-	totalram += totalbig;
+	totalram_pages += totalhigh_pages;
 #endif
-	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %dk bigmem)\n",
+	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
 		(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
 		max_mapnr << (PAGE_SHIFT-10),
 		codepages << (PAGE_SHIFT-10),
 		reservedpages << (PAGE_SHIFT-10),
 		datapages << (PAGE_SHIFT-10),
 		initpages << (PAGE_SHIFT-10),
-	        (int) (totalbig >> 10)
+		(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
 	       );
 
+#if CONFIG_X86_PAE
+	if (!cpu_has_pae)
+		panic("cannot execute a PAE-enabled kernel on a PAE-incapable CPU!");
+#endif
 	if (boot_cpu_data.wp_works_ok < 0)
 		test_wp_bit();
 
+	/*
+	 * Subtle. SMP is doing it's boot stuff late (because it has to
+	 * fork idle threads) - but it also needs low mappings for the
+	 * protected-mode entry to work. We zap these entries only after
+	 * the WP-bit has been tested.
+	 */
+#ifndef CONFIG_SMP
+	zap_low_mappings();
+#endif
+
 }
 
 void free_initmem(void)
@@ -503,21 +569,22 @@
 	
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		ClearPageReserved(mem_map + MAP_NR(addr));
 		set_page_count(mem_map+MAP_NR(addr), 1);
 		free_page(addr);
-		totalram += PAGE_SIZE;
+		totalram_pages++;
 	}
 	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
 {
-	val->totalram = totalram;
+	val->totalram = totalram_pages;
 	val->sharedram = 0;
-	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = atomic_read(&buffermem);
-	val->totalbig = totalbig;
-	val->freebig = nr_free_bigpages << PAGE_SHIFT;
+	val->freeram = nr_free_pages;
+	val->bufferram = atomic_read(&buffermem_pages);
+	val->totalhigh = totalhigh_pages;
+	val->freehigh = nr_free_highpages;
+	val->mem_unit = PAGE_SIZE;
 	return;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c
--- v2.3.22/linux/arch/i386/mm/ioremap.c	Sun Jul 25 13:45:25 1999
+++ linux/arch/i386/mm/ioremap.c	Tue Oct 19 10:22:20 1999
@@ -20,15 +20,19 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
 	do {
-		if (!pte_none(*pte))
+		if (!pte_none(*pte)) {
 			printk("remap_area_pte: page already exists\n");
+			BUG();
+		}
 		set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | 
 					_PAGE_DIRTY | _PAGE_ACCESSED | flags)));
 		address += PAGE_SIZE;
 		phys_addr += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -41,6 +45,8 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	phys_addr -= address;
+	if (address >= end)
+		BUG();
 	do {
 		pte_t * pte = pte_alloc_kernel(pmd, address);
 		if (!pte)
@@ -48,7 +54,7 @@
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 	return 0;
 }
 
@@ -61,8 +67,11 @@
 	phys_addr -= address;
 	dir = pgd_offset(&init_mm, address);
 	flush_cache_all();
-	while (address < end) {
-		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+	if (address >= end)
+		BUG();
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc_kernel(dir, address);
 		if (!pmd)
 			return -ENOMEM;
 		if (remap_area_pmd(pmd, address, end - address,
@@ -71,7 +80,7 @@
 		set_pgdir(address, *dir);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
 	flush_tlb_all();
 	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.3.22/linux/arch/i386/vmlinux.lds	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/vmlinux.lds	Sat Oct 16 21:00:59 1999
@@ -0,0 +1,75 @@
+/* ld script to make i386 Linux kernel
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0xC0000000 + 0x100000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.text)
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x9090
+  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  _etext = .;			/* End of text section */
+
+  .data : {			/* Data */
+	*(.data)
+	CONSTRUCTORS
+	}
+
+  _edata = .;			/* End of data section */
+
+  . = ALIGN(8192);		/* init_task */
+  .data.init_task : { *(.data.init_task) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	}
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -u --recursive --new-file v2.3.22/linux/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S
--- v2.3.22/linux/arch/i386/vmlinux.lds.S	Mon Aug  2 13:57:59 1999
+++ linux/arch/i386/vmlinux.lds.S	Wed Dec 31 16:00:00 1969
@@ -1,75 +0,0 @@
-/* ld script to make i386 Linux kernel
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
- */
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-SECTIONS
-{
-  . = PAGE_OFFSET_RAW + 0x100000;
-  _text = .;			/* Text and read-only data */
-  .text : {
-	*(.text)
-	*(.fixup)
-	*(.gnu.warning)
-	} = 0x9090
-  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
-  .rodata : { *(.rodata) }
-  .kstrtab : { *(.kstrtab) }
-
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___ksymtab = .;	/* Kernel symbol table */
-  __ksymtab : { *(__ksymtab) }
-  __stop___ksymtab = .;
-
-  _etext = .;			/* End of text section */
-
-  .data : {			/* Data */
-	*(.data)
-	CONSTRUCTORS
-	}
-
-  _edata = .;			/* End of data section */
-
-  . = ALIGN(8192);		/* init_task */
-  .data.init_task : { *(.data.init_task) }
-
-  . = ALIGN(4096);		/* Init code and data */
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
-  __initcall_end = .;
-  . = ALIGN(4096);
-  __init_end = .;
-
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
-  . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
-  _end = . ;
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-}
diff -u --recursive --new-file v2.3.22/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.3.22/linux/arch/m68k/mm/init.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mm/init.c	Sat Oct 16 10:50:48 1999
@@ -112,6 +112,7 @@
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
     printk("%ld pages in page table cache\n",pgtable_cache_size);
+    show_buffers();
 #ifdef CONFIG_NET
     show_net_buffers();
 #endif
diff -u --recursive --new-file v2.3.22/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.3.22/linux/arch/mips/mm/init.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/mips/mm/init.c	Sat Oct 16 10:50:48 1999
@@ -265,6 +265,7 @@
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
 	printk("%d free pages\n", free);
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.3.22/linux/arch/ppc/kernel/apus_setup.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/apus_setup.c	Wed Oct 20 22:13:20 1999
@@ -255,8 +255,7 @@
 
 /*********************************************************** SETUP */
 /* From arch/m68k/kernel/setup.c. */
-void __init apus_setup_arch(unsigned long * memory_start_p,
-				unsigned long * memory_end_p)
+void __init apus_setup_arch(void)
 {
 #ifdef CONFIG_APUS
 	extern char cmd_line[];
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.3.22/linux/arch/ppc/kernel/chrp_pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Mon Oct 18 11:14:22 1999
@@ -16,7 +16,6 @@
 #include <asm/hydra.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
-#include <asm/ide.h>
 #include <asm/machdep.h>
 
 #include "pci.h"
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.3.22/linux/arch/ppc/kernel/chrp_setup.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Wed Oct 20 22:13:20 1999
@@ -28,6 +28,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
 #include <linux/pci.h>
@@ -35,13 +36,12 @@
 #include <linux/version.h>
 #include <linux/adb.h>
 #include <linux/module.h>
+#include <linux/delay.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <linux/ide.h>
-#include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
 #include <asm/pci-bridge.h>
@@ -227,7 +227,7 @@
 
 
 void __init
-chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+chrp_setup_arch(void)
 {
 	extern char cmd_line[];
 	struct device_node *device;
@@ -278,7 +278,7 @@
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
-	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+	pmac_find_bridges();
 
 	/* Get the event scan rate for the rtas so we know how
 	 * often it expects a heartbeat. -- Cort
@@ -363,10 +363,7 @@
 			irq = *chrp_int_ack_special;
 		else
 			irq = i8259_irq( smp_processor_id() );
-                /*
-                 * Acknowledge as soon as possible to allow i8259
-                 * interrupt nesting                         */
-                openpic_eoi( smp_processor_id() );
+		openpic_eoi( smp_processor_id() );
         }
         if (irq == OPENPIC_VEC_SPURIOUS)
                 /*
@@ -374,6 +371,11 @@
                  * acknowledged
                  */
 		irq = -1;
+	/*
+	 * I would like to openpic_eoi here but there seem to be timing problems
+	 * between the openpic ack and the openpic eoi.
+	 *   -- Cort
+	 */
 	return irq;
 }
 
@@ -382,88 +384,14 @@
 	/*
 	 * If it's an i8259 irq then we've already done the
 	 * openpic irq.  So we just check to make sure the controller
-	 * is an openpic and if it is then eoi -- Cort
+	 * is an openpic and if it is then eoi
+	 *
+	 * We do it this way since our irq_desc[irq].ctl can change
+	 * with RTL and no longer be open_pic -- Cort
 	 */
-	if ( irq_desc[irq].ctl == &open_pic )
+	if ( irq >= open_pic.irq_offset)
 		openpic_eoi( smp_processor_id() );
 }
-
-#if 0
-void
-chrp_do_IRQ(struct pt_regs *regs,
-	    int            cpu,
-            int            isfake)
-{
-        int irq;
-        unsigned long bits = 0;
-        int openpic_eoi_done = 0;
-
-#ifdef __SMP__
-        {
-                unsigned int loops = 1000000;
-                while (test_bit(0, &global_irq_lock)) {
-                        if (smp_processor_id() == global_irq_holder) {
-                                printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
-                                xmon(0);
-#endif
-                                break;
-                        }
-                        if (loops-- == 0) {
-                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
-                                xmon(0);
-#endif
-                        }
-                }
-        }
-#endif /* __SMP__ */
-
-        irq = openpic_irq(0);
-        if (irq == IRQ_8259_CASCADE)
-        {
-                /*
-                 * This magic address generates a PCI IACK cycle.
-                 *
-                 * This should go in the above mask/ack code soon. -- Cort
-                 */
-		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                         */
-                openpic_eoi(0);
-                openpic_eoi_done = 1;
-        }
-        if (irq == OPENPIC_VEC_SPURIOUS)
-        {
-                /*
-                 * Spurious interrupts should never be
-                 * acknowledged
-                 */
-                ppc_spurious_interrupts++;
-                openpic_eoi_done = 1;
-		goto out;
-        }
-        bits = 1UL << irq;
-
-        if (irq < 0)
-        {
-                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-                       irq, regs->nip);
-                ppc_spurious_interrupts++;
-        }
-	else
-        {
-		ppc_irq_dispatch_handler( regs, irq );
-	}
-out:
-        if (!openpic_eoi_done)
-                openpic_eoi(0);
-}
-#endif
 
 void __init chrp_init_IRQ(void)
 {
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.22/linux/arch/ppc/kernel/gemini_setup.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/gemini_setup.c	Wed Oct 20 22:13:20 1999
@@ -134,7 +134,7 @@
 extern char cmd_line[];
 
 
-void __init gemini_setup_arch(unsigned long *memstart, unsigned long *memend)
+void __init gemini_setup_arch(void)
 {
 	unsigned int cpu;
 	extern char cmd_line[];
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.22/linux/arch/ppc/kernel/idle.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/idle.c	Wed Oct 20 22:13:20 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.67 1999/09/10 05:05:47 paulus Exp $
+ * $Id: idle.c,v 1.68 1999/10/15 18:16:03 cort Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -293,11 +293,8 @@
 		
 			/* set the POW bit in the MSR, and enable interrupts
 			 * so we wake up sometime! */
+			__sti(); /* this keeps rtl from getting confused -- Cort */
 			_nmask_and_or_msr(0, MSR_POW | MSR_EE);
-
-			/* Disable interrupts again so restore_flags will
-			 * work. */
-			_nmask_and_or_msr(MSR_EE, 0);
 		}
 		restore_flags(msr);
 	default:
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.22/linux/arch/ppc/kernel/irq.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/irq.c	Wed Oct 20 22:13:20 1999
@@ -296,15 +296,19 @@
 	irq = ppc_md.get_irq( regs );
 	if ( irq < 0 )
 	{
-                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-                       irq, regs->nip);
-                ppc_spurious_interrupts++;
-		return;
+		/* -2 means ignore, already handled */
+		if (irq != -2) {
+			printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+			       irq, regs->nip);
+			ppc_spurious_interrupts++;
+		}
+		goto out;
 	}
 	ppc_irq_dispatch_handler( regs, irq );
 	if ( ppc_md.post_irq )
 		ppc_md.post_irq( irq );
-	
+
+ out:	
         hardirq_exit( cpu );
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.3.22/linux/arch/ppc/kernel/m8xx_setup.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/m8xx_setup.c	Wed Oct 20 22:13:20 1999
@@ -33,6 +33,7 @@
 #include <linux/blk.h>
 #include <linux/ioport.h>
 #include <linux/ide.h>
+#include <linux/bootmem.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -83,13 +84,12 @@
 }
 
 void __init
-m8xx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+m8xx_setup_arch(void)
 {
 	int	cpm_page;
 	extern char cmd_line[];
 	
-	cpm_page = *memory_start_p;
-	*memory_start_p += PAGE_SIZE;
+	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
 	
 	printk("Boot arguments: %s\n", cmd_line);
 
@@ -108,6 +108,9 @@
 	rd_doload = 1;
 	rd_image_start = 0;
 #endif
+#if 0	/* XXX this may need to be updated for the new bootmem stuff,
+	   or possibly just deleted (see set_phys_avail() in init.c).
+	   - paulus. */
 	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
 	if ( initrd_start )
 	{
@@ -119,6 +122,7 @@
 			initrd_start = 0;
 		}
 	}
+#endif
 #endif
 }
 
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- v2.3.22/linux/arch/ppc/kernel/mbx_setup.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/mbx_setup.c	Wed Oct 20 22:13:20 1999
@@ -30,6 +30,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/ioport.h>
 
 #include <asm/mmu.h>
@@ -37,7 +38,6 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/ide.h>
 #include <asm/mbx.h>
 #include <asm/machdep.h>
 
@@ -76,13 +76,12 @@
 }
 
 void __init
-mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+mbx_setup_arch(void)
 {
 	int	cpm_page;
 	extern char cmd_line[];
 	
-	cpm_page = *memory_start_p;
-	*memory_start_p += PAGE_SIZE;
+	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
 	
 	sprintf(cmd_line,
 "%s root=/dev/nfs nfsroot=/sys/mbxroot",
@@ -104,6 +103,9 @@
 	rd_doload = 1;
 	rd_image_start = 0;
 #endif
+#if 0	/* XXX this may need to be updated for the new bootmem stuff,
+	   or possibly just deleted (see set_phys_avail() in init.c).
+	   - paulus. */
 	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
 	if ( initrd_start )
 	{
@@ -115,6 +117,7 @@
 			initrd_start = 0;
 		}
 	}
+#endif
 #endif
 
 #ifdef notdef
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.22/linux/arch/ppc/kernel/misc.S	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/kernel/misc.S	Wed Oct 20 22:13:20 1999
@@ -235,9 +235,9 @@
  * snoop from the data cache.
  * This is a no-op on the 601 which has a unified cache.
  *
- *	void flush_page_to_ram(void *page)
+ *	void __flush_page_to_ram(void *page)
  */
-_GLOBAL(flush_page_to_ram)
+_GLOBAL(__flush_page_to_ram)
 	mfspr	r5,PVR
 	rlwinm	r5,r5,16,16,31
 	cmpi	0,r5,1
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.22/linux/arch/ppc/kernel/pci.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/kernel/pci.c	Wed Oct 20 22:13:20 1999
@@ -146,3 +146,25 @@
 {
 	return 0;
 }
+
+/* the next two are stolen from the alpha port... */
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
+{
+        unsigned long where, size;
+        u32 reg;
+
+        where = PCI_BASE_ADDRESS_0 + (resource * 4);
+        size = res->end - res->start;
+        pci_read_config_dword(dev, where, &reg);
+        reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+        pci_write_config_dword(dev, where, reg);
+}
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+	/* XXX FIXME - update OF device tree node interrupt property */
+}
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.3.22/linux/arch/ppc/kernel/pmac_pci.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/pmac_pci.c	Wed Oct 20 22:13:20 1999
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/bootmem.h>
 
 #include <asm/init.h>
 #include <asm/io.h>
@@ -30,7 +31,7 @@
 struct bridge_data **bridges, *bridge_list;
 static int max_bus;
 
-static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+static void add_bridges(struct device_node *dev);
 
 /*
  * Magic constants for enabling cache coherency in the bandit/PSX bridge.
@@ -362,24 +363,22 @@
 	       bp->io_base);
 }
 
-unsigned long __init pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+void __init pmac_find_bridges(void)
 {
 	int bus;
 	struct bridge_data *bridge;
 
 	bridge_list = 0;
 	max_bus = 0;
-	add_bridges(find_devices("bandit"), &mem_start);
-	add_bridges(find_devices("chaos"), &mem_start);
-	add_bridges(find_devices("pci"), &mem_start);
-	bridges = (struct bridge_data **) mem_start;
-	mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+	add_bridges(find_devices("bandit"));
+	add_bridges(find_devices("chaos"));
+	add_bridges(find_devices("pci"));
+	bridges = (struct bridge_data **)
+		alloc_bootmem((max_bus + 1) * sizeof(struct bridge_data *));
 	memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
 	for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
 		for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
 			bridges[bus] = bridge;
-
-	return mem_start;
 }
 
 /*
@@ -387,7 +386,7 @@
  * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
  * if we have one or more bandit or chaos bridges, we don't have a MPC106.
  */
-static void __init add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+static void __init add_bridges(struct device_node *dev)
 {
 	int *bus_range;
 	int len;
@@ -413,8 +412,7 @@
 			printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
 			       bus_range[1]);
 		printk(" controlled by %s at %x\n", dev->name, addr->address);
-		bp = (struct bridge_data *) *mem_ptr;
-		*mem_ptr += sizeof(struct bridge_data);
+		bp = (struct bridge_data *) alloc_bootmem(sizeof(*bp));
 		if (strcmp(dev->name, "pci") != 0) {
 			bp->cfg_addr = (volatile unsigned int *)
 				ioremap(addr->address + 0x800000, 0x1000);
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.3.22/linux/arch/ppc/kernel/pmac_pic.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/pmac_pic.c	Wed Oct 20 22:13:20 1999
@@ -225,7 +225,7 @@
 			xmon(regs);
 #endif
 		smp_message_recv();
-		return -1;
+		return -2;	/* ignore, already handled */
         }
 
         {
@@ -374,7 +374,7 @@
 		}
 		
 		/* get addresses of second controller */
-		irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+		irqctrler = irqctrler->next;
 		if (irqctrler && irqctrler->n_addrs > 0) {
 			addr = (unsigned long) 
 				ioremap(irqctrler->addrs[0].address, 0x40);
@@ -382,6 +382,11 @@
 				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
 					(addr + (4 - i) * 0x10);
 		}
+	} else {
+		/* older powermacs have a GC (grand central) or ohare at
+		   f3000000, with interrupt control registers at f3000020. */
+		addr = (unsigned long) ioremap(0xf3000000, 0x40);
+		pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
 	}
 
 	/* disable all interrupts in all controllers */
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.22/linux/arch/ppc/kernel/pmac_setup.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/kernel/pmac_setup.c	Wed Oct 20 22:13:20 1999
@@ -39,6 +39,7 @@
 #include <linux/ioport.h>
 #include <linux/major.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 #include <linux/ide.h>
@@ -57,7 +58,6 @@
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
 #include <asm/feature.h>
-#include <asm/ide.h>
 #include <asm/machdep.h>
 #include <asm/keyboard.h>
 #include <asm/dma.h>
@@ -238,7 +238,7 @@
 static volatile u32 *sysctrl_regs;
 
 void __init
-pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)
+pmac_setup_arch(void)
 {
 	struct device_node *cpu;
 	int *fp;
@@ -269,7 +269,7 @@
 	__ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY));
 	ohare_init();
 
-	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+	pmac_find_bridges();
 	init_p2pbridge();
 
 	/* Checks "l2cr-value" property in the registry */
@@ -421,7 +421,7 @@
 #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
 extern int pmac_ide_count;
 extern struct device_node *pmac_ide_node[];
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89 };
+static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 };
 
 kdev_t __init find_ide_boot(void)
 {
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.22/linux/arch/ppc/kernel/ppc_ksyms.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Wed Oct 20 22:13:20 1999
@@ -60,7 +60,6 @@
 EXPORT_SYMBOL(syscall_trace);
 EXPORT_SYMBOL(transfer_to_handler);
 EXPORT_SYMBOL(do_IRQ);
-EXPORT_SYMBOL(init_task_union);
 EXPORT_SYMBOL(MachineCheckException);
 EXPORT_SYMBOL(AlignmentException);
 EXPORT_SYMBOL(ProgramCheckException);
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.3.22/linux/arch/ppc/kernel/prep_setup.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Wed Oct 20 22:13:20 1999
@@ -41,7 +41,6 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/ide.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
@@ -211,7 +210,7 @@
 }
 
 void __init
-prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)
+prep_setup_arch()
 {
 	extern char cmd_line[];
 	unsigned char reg;
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.22/linux/arch/ppc/kernel/setup.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/kernel/setup.c	Wed Oct 20 22:13:20 1999
@@ -11,12 +11,11 @@
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/blk.h>
+#include <linux/ide.h>
 
 #include <asm/init.h>
 #include <asm/residual.h>
 #include <asm/io.h>
-#include <linux/ide.h>
-#include <asm/ide.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
@@ -540,14 +539,12 @@
 	}
 }
 
-void __init setup_arch(char **cmdline_p,
-		       unsigned long * memory_start_p, unsigned long * memory_end_p)
+void __init setup_arch(char **cmdline_p)
 {
 	extern int panic_timeout;
 	extern char _etext[], _edata[];
 	extern char *klimit;
-	extern unsigned long find_available_memory(void);
-	extern unsigned long *end_of_DRAM;
+	extern void do_init_bootmem(void);
 
 #ifdef CONFIG_XMON
 	extern void xmon_map_scc(void);
@@ -556,22 +553,22 @@
 		xmon(0);
 #endif /* CONFIG_XMON */
 
-	/* reboot on panic */	
+	/* reboot on panic */
 	panic_timeout = 180;
 
 	init_mm.start_code = PAGE_OFFSET;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
-	init_mm.brk = (unsigned long) klimit;	
+	init_mm.brk = (unsigned long) klimit;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	strcpy(saved_command_line, cmd_line);
 	*cmdline_p = cmd_line;
 
-	*memory_start_p = find_available_memory();
-	*memory_end_p = (unsigned long) end_of_DRAM;
+	/* set up the bootmem stuff with available memory */
+	do_init_bootmem();
 
-	ppc_md.setup_arch(memory_start_p, memory_end_p);
+	ppc_md.setup_arch();
 	/* clear the progress line */
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 }
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/mbx_defconfig linux/arch/ppc/mbx_defconfig
--- v2.3.22/linux/arch/ppc/mbx_defconfig	Sat Jun 26 08:34:19 1999
+++ linux/arch/ppc/mbx_defconfig	Mon Oct 18 11:14:22 1999
@@ -74,7 +74,7 @@
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 CONFIG_BLK_DEV_SL82C105=y
 # CONFIG_IDE_CHIPSETS is not set
diff -u --recursive --new-file v2.3.22/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.22/linux/arch/ppc/mm/init.c	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/mm/init.c	Wed Oct 20 22:13:20 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.193 1999/10/11 18:50:35 geert Exp $
+ *  $Id: init.c,v 1.195 1999/10/15 16:39:39 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/openpic.h>
+#include <linux/bootmem.h>
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>		/* for initrd_* */
 #endif
@@ -59,6 +60,9 @@
 atomic_t next_mmu_context;
 unsigned long *end_of_DRAM;
 int mem_init_done;
+int init_bootmem_done;
+int boot_mapsize;
+unsigned long totalram_pages = 0;
 extern pgd_t swapper_pg_dir[];
 extern char _start[], _end[];
 extern char etext[], _stext[];
@@ -108,9 +112,9 @@
 };
 struct mem_pieces phys_mem;
 struct mem_pieces phys_avail;
-struct mem_pieces prom_mem;
 
 static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+static void set_phys_avail(void);
 void *find_mem_piece(unsigned, unsigned);
 static void print_mem_pieces(struct mem_pieces *);
 #if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
@@ -202,7 +206,7 @@
 			pte = (pte_t *) MMU_get_page();
 		else if ((pte = (pte_t *) get_zero_page_fast()) == NULL)
 			if ((pte = (pte_t *) __get_free_page(GFP_KERNEL)))
-				clear_page((unsigned long)pte);
+				clear_page(pte);
                 if (pte) {
                         pmd_val(*pmd) = (unsigned long)pte;
                         return pte + offset;
@@ -246,20 +250,20 @@
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-unsigned long empty_bad_page_table;
+pte_t *empty_bad_page_table;
 
 pte_t * __bad_pagetable(void)
 {
-	__clear_user((void *)empty_bad_page_table, PAGE_SIZE);
-	return (pte_t *) empty_bad_page_table;
+	clear_page(empty_bad_page_table);
+	return empty_bad_page_table;
 }
 
-unsigned long empty_bad_page;
+void *empty_bad_page;
 
 pte_t __bad_page(void)
 {
-	__clear_user((void *)empty_bad_page, PAGE_SIZE);
-	return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
+	clear_page(empty_bad_page);
+	return pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
 }
 
 void show_mem(void)
@@ -289,6 +293,7 @@
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
 	printk("%d pages in page table cache\n",(int)pgtable_cache_size);
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -345,7 +350,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = atomic_read(&buffermem);
+	val->bufferram = atomic_read(&buffermem_pages);
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
@@ -590,6 +595,37 @@
 #endif /* CONFIG_8xx */
 
 /*
+ * Set phys_avail to phys_mem less the kernel text/data/bss.
+ */
+static void __init set_phys_avail(void)
+{
+	unsigned long kstart, ksize;
+
+	/* we can't call the prom any more at this stage, so
+	   all of memory is available (after klimit) */
+	phys_avail = phys_mem;
+
+	/*
+	 * phys_avail records memory we can use.
+	 * Make sure the kernel text/data/bss is not in it.
+	 */
+	kstart = __pa(_stext);	/* should be 0 */
+	ksize = PAGE_ALIGN(klimit - _stext);
+	remove_mem_piece(&phys_avail, kstart, ksize, 0);
+	remove_mem_piece(&phys_avail, 0, 0x4000, 0);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) {
+		/*
+		 * Remove the initialized ramdisk from the available memory.
+		 */
+		remove_mem_piece(&phys_avail, __pa(initrd_start),
+				 initrd_end - initrd_start, 1);
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+}
+
+/*
  * Scan a region for a piece of a given size with the required alignment.
  */
 void __init *find_mem_piece(unsigned size, unsigned align)
@@ -681,7 +717,7 @@
 	printk("\n");
 }
 
-#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_PPC_ALL)
+#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
 /*
  * Add some memory to an array of pieces
  */
@@ -833,8 +869,8 @@
 {
 	int i;
 	unsigned long v, p, s, f;
-#ifndef CONFIG_8xx
 
+#ifndef CONFIG_8xx
 	if (!__map_without_bats) {
 		unsigned long tot, mem_base, bl, done;
 		unsigned long max_size = (256<<20);
@@ -869,24 +905,7 @@
 			       RAM_PAGE);
 		}
 	}
-	v = KERNELBASE;
-	for (i = 0; i < phys_mem.n_regions; ++i) {
-		p = phys_mem.regions[i].address;
-		for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
-			f = _PAGE_PRESENT | _PAGE_ACCESSED;
-			if ((char *) v < _stext || (char *) v >= etext)
-				f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
-			else
-				/* On the powerpc, no user access
-				   forces R/W kernel access */
-				f |= _PAGE_USER;
-			map_page(v, p, f);
-			v += PAGE_SIZE;
-			p += PAGE_SIZE;
-		}
-	}
-
-#else	/* CONFIG_8xx */
+#endif /* CONFIG_8xx */
 
 	for (i = 0; i < phys_mem.n_regions; ++i) {
 		v = (ulong)__va(phys_mem.regions[i].address);
@@ -896,37 +915,35 @@
                          * don't get ASID compares on kernel space.
                          */
 			f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
-
-                        /* I don't really need the rest of this code, but
-                         * I grabbed it because I think the line:
-                         *      f |= _PAGE_USER
-                         * is incorrect.  It needs to be set to bits we
-                         * don't define to cause a kernel read-only.  On
-                         * the MPC8xx, the PAGE_DIRTY takes care of that
-                         * for us (along with the RW software state).
-                         */
 			if ((char *) v < _stext || (char *) v >= etext)
 				f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+#ifndef CONFIG_8xx
+			else
+				/* On the powerpc (not 8xx), no user access
+				   forces R/W kernel access */
+				f |= _PAGE_USER;
+#endif /* CONFIG_8xx */
 			map_page(v, p, f);
 			v += PAGE_SIZE;
 			p += PAGE_SIZE;
 		}
-	}	    
-#endif /* CONFIG_8xx */
+	}
 }
 
-/* This can get called from ioremap, so don't make it an __init, OK? */
+/* In fact this is only called until mem_init is done. */
 static void __init *MMU_get_page(void)
 {
 	void *p;
 
 	if (mem_init_done) {
 		p = (void *) __get_free_page(GFP_KERNEL);
-		if (p == 0)
-			panic("couldn't get a page in MMU_get_page");
+	} else if (init_bootmem_done) {
+		p = alloc_bootmem_pages(PAGE_SIZE);
 	} else {
 		p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
 	}
+	if (p == 0)
+		panic("couldn't get a page in MMU_get_page");
 	__clear_user(p, PAGE_SIZE);
 	return p;
 }
@@ -1106,6 +1123,51 @@
 }
 
 /*
+ * Initialize the bootmem system and give it all the memory we
+ * have available.
+ */
+void __init do_init_bootmem(void)
+{
+	unsigned long start, size;
+	int i;
+
+	/*
+	 * Find an area to use for the bootmem bitmap.
+	 * We look for the first area which is at least
+	 * 128kB in length (128kB is enough for a bitmap
+	 * for 4GB of memory, using 4kB pages), plus 1 page
+	 * (in case the address isn't page-aligned).
+	 */
+	start = 0;
+	size = 0;
+	for (i = 0; i < phys_avail.n_regions; ++i) {
+		unsigned long a = phys_avail.regions[i].address;
+		unsigned long s = phys_avail.regions[i].size;
+		if (s <= size)
+			continue;
+		start = a;
+		size = s;
+		if (s >= 33 * PAGE_SIZE)
+			break;
+	}
+	start = PAGE_ALIGN(start);
+
+	boot_mapsize = init_bootmem(start >> PAGE_SHIFT,
+				    __pa(end_of_DRAM) >> PAGE_SHIFT);
+
+	/* remove the bootmem bitmap from the available memory */
+	remove_mem_piece(&phys_avail, start, start + boot_mapsize, 1);
+
+	/* add everything in phys_avail into the bootmem map */
+	for (i = 0; i < phys_avail.n_regions; ++i)
+		free_bootmem(phys_avail.regions[i].address,
+			     phys_avail.regions[i].size);
+
+	init_bootmem_done = 1;
+}
+
+#if 0
+/*
  * Find some memory for setup_arch to return.
  * We use the largest chunk of available memory as the area
  * that setup_arch returns, making sure that there are at
@@ -1143,97 +1205,56 @@
 	avail_start = (unsigned long) __va(a);
 	return avail_start;
 }
+#endif /* 0 */
 
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
  */
-unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init paging_init(void)
 {
-	extern unsigned long free_area_init(unsigned long, unsigned long);
 	/*
 	 * Grab some memory for bad_page and bad_pagetable to use.
 	 */
-	empty_bad_page = PAGE_ALIGN(start_mem);
-	empty_bad_page_table = empty_bad_page + PAGE_SIZE;
-	start_mem = empty_bad_page + 2 * PAGE_SIZE;
+	empty_bad_page = alloc_bootmem_pages(PAGE_SIZE);
+	empty_bad_page_table = alloc_bootmem_pages(PAGE_SIZE);
 
-	/* note: free_area_init uses its second argument
-	   to size the mem_map array. */
-	start_mem = free_area_init(start_mem, end_mem);
-	return start_mem;
+	free_area_init(max_low_pfn);
 }
 
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+void __init mem_init(void)
 {
 	unsigned long addr;
-	int i;
-	unsigned long a, lim;
 	int codepages = 0;
 	int datapages = 0;
 	int initpages = 0;
 	extern unsigned int rtas_data, rtas_size;
 
-	end_mem &= PAGE_MASK;
-	high_memory = (void *) end_mem;
-	max_mapnr = MAP_NR(high_memory);
-
-	/* mark usable pages in the mem_map[] */
-	start_mem = PAGE_ALIGN(start_mem);
-
+	max_mapnr = max_low_pfn;
+	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
-	remove_mem_piece(&phys_avail, __pa(avail_start),
-			 start_mem - avail_start, 1);
 
-	for (i = 0; i < phys_avail.n_regions; ++i) {
-		a = (unsigned long) __va(phys_avail.regions[i].address);
-		lim = (a + phys_avail.regions[i].size) & PAGE_MASK;
-		a = PAGE_ALIGN(a);
-		for (; a < lim; a += PAGE_SIZE)
-			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-	}
+	totalram_pages += free_all_bootmem();
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* if we are booted from BootX with an initial ramdisk,
 	   make sure the ramdisk pages aren't reserved. */
 	if (initrd_start) {
-		for (a = initrd_start; a < initrd_end; a += PAGE_SIZE)
-			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+		for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE)
+			clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 	
-	/* free the prom's memory - no-op on prep */
-	for (i = 0; i < prom_mem.n_regions; ++i) {
-		a = (unsigned long) __va(prom_mem.regions[i].address);
-		lim = (a + prom_mem.regions[i].size) & PAGE_MASK;
-		a = PAGE_ALIGN(a);
-		for (; a < lim; a += PAGE_SIZE)
-			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-	}
-
-	prom_trashed = 1;
-	
-	for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
-		if (PageReserved(mem_map + MAP_NR(addr))) {
-			if (addr < (ulong) etext)
-				codepages++;
-			else if (addr >= (unsigned long)&__init_begin
-				 && addr < (unsigned long)&__init_end)
-                                initpages++;
-                        else if (addr < (ulong) start_mem)
-				datapages++;
+	for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM;
+	     addr += PAGE_SIZE) {
+		if (!PageReserved(mem_map + MAP_NR(addr)))
 			continue;
-		}
-		set_page_count(mem_map + MAP_NR(addr), 1);
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (!initrd_start ||
-		    addr < (initrd_start & PAGE_MASK) || addr >= initrd_end)
-#endif /* CONFIG_BLK_DEV_INITRD */
-#ifndef CONFIG_8xx
-			if ( !rtas_data ||
-			     addr < (rtas_data & PAGE_MASK) ||
-			     addr >= (rtas_data+rtas_size))
-#endif /* CONFIG_8xx */
-				free_page(addr);
+		if (addr < (ulong) etext)
+			codepages++;
+		else if (addr >= (unsigned long)&__init_begin
+			 && addr < (unsigned long)&__init_end)
+			initpages++;
+		else if (addr < (ulong) klimit)
+			datapages++;
 	}
 
         printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
@@ -1241,7 +1262,7 @@
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10), 
 	       initpages << (PAGE_SHIFT-10),
-	       PAGE_OFFSET, end_mem);
+	       PAGE_OFFSET, (unsigned long) end_of_DRAM);
 	mem_init_done = 1;
 }
 
@@ -1257,11 +1278,9 @@
 unsigned long __init *pmac_find_end_of_memory(void)
 {
 	unsigned long a, total;
-	unsigned long kstart, ksize;
-	int i;
 	
 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (256<<20)
+#define RAM_LIMIT (768<<20)
 
 	memory_node = find_devices("memory");
 	if (memory_node == NULL) {
@@ -1309,32 +1328,8 @@
 		phys_mem.n_regions = 1;
 	}
 
-	if (boot_infos == 0) {
-		/* record which bits the prom is using */
-		get_mem_prop("available", &phys_avail);
-		prom_mem = phys_mem;
-		for (i = 0; i < phys_avail.n_regions; ++i)
-			remove_mem_piece(&prom_mem,
-					 phys_avail.regions[i].address,
-					 phys_avail.regions[i].size, 0);
-	} else {
-		/* booted from BootX - it's all available (after klimit) */
-		phys_avail = phys_mem;
-		prom_mem.n_regions = 0;
-	}
+	set_phys_avail();
 
-	/*
-	 * phys_avail records memory we can use now.
-	 * prom_mem records memory allocated by the prom that we
-	 * don't want to use now, but we'll reclaim later.
-	 * Make sure the kernel text/data/bss is in neither.
-	 */
-	kstart = __pa(_stext);	/* should be 0 */
-	ksize = PAGE_ALIGN(klimit - _stext);
-	remove_mem_piece(&phys_avail, kstart, ksize, 0);
-	remove_mem_piece(&prom_mem, kstart, ksize, 0);
-	remove_mem_piece(&phys_avail, 0, 0x4000, 0);
-	remove_mem_piece(&prom_mem, 0, 0x4000, 0);
 #undef RAM_LIMIT
 	return __va(total);
 }
@@ -1349,7 +1344,6 @@
  */
 unsigned long __init *prep_find_end_of_memory(void)
 {
-	unsigned long kstart, ksize;
 	unsigned long total;
 	total = res->TotalMemory;
 
@@ -1364,11 +1358,7 @@
 		printk("Ramsize default to be %ldM\n", total>>20);
 	}
 	append_mem_piece(&phys_mem, 0, total);
-	phys_avail = phys_mem;
-	kstart = __pa(_stext);	/* should be 0 */
-	ksize = PAGE_ALIGN(klimit - _stext);
-	remove_mem_piece(&phys_avail, kstart, ksize, 0);
-	remove_mem_piece(&phys_avail, 0, 0x4000, 0);
+	set_phys_avail();
 
 	return (__va(total));
 }
@@ -1378,7 +1368,7 @@
 #if defined(CONFIG_GEMINI)
 unsigned long __init *gemini_find_end_of_memory(void)
 {
-	unsigned long total, kstart, ksize, *ret;
+	unsigned long total, *ret;
 	unsigned char reg;
 
 	reg = readb(GEMINI_MEMCFG);
@@ -1390,10 +1380,7 @@
 	phys_mem.n_regions = 1;
 	
 	ret = __va(phys_mem.regions[0].size);
-	phys_avail = phys_mem;
-	kstart = __pa(_stext);
-	ksize = PAGE_ALIGN( _end - _stext );
-	remove_mem_piece( &phys_avail, kstart, ksize, 0 );
+	set_phys_avail();
 	return ret;
 }
 #endif /* defined(CONFIG_GEMINI) || defined(CONFIG_ALL_PPC) */
@@ -1429,15 +1416,8 @@
 	}
 
 	/* Now register the memory block. */
-	{
-		unsigned long kstart, ksize;
-
-		append_mem_piece(&phys_mem, memory[0].addr, memory[0].size);
-		phys_avail = phys_mem;
-		kstart = __pa(_stext);
-		ksize = PAGE_ALIGN(klimit - _stext);
-		remove_mem_piece(&phys_avail, kstart, ksize, 0);
-	}
+	append_mem_piece(&phys_mem, memory[0].addr, memory[0].size);
+	set_phys_avail();
 
 	/* Remove the memory chunks that are controlled by special
            Phase5 hardware. */
@@ -1586,7 +1566,6 @@
  */
 unsigned long __init *m8xx_find_end_of_memory(void)
 {
-	unsigned long kstart, ksize;
 	bd_t	*binfo;
 	unsigned long *ret;
 	extern unsigned char __res[];
@@ -1600,11 +1579,7 @@
 	ret = __va(phys_mem.regions[0].address+
 		   phys_mem.regions[0].size);
 
-	phys_avail = phys_mem;
-
-	kstart = __pa(_stext);	/* should be 0 */
-	ksize = PAGE_ALIGN(_end - _stext);
-	remove_mem_piece(&phys_avail, kstart, ksize, 0);
+	set_phys_avail();
 	return ret;
 }
 #endif /* ndef CONFIG_8xx */
diff -u --recursive --new-file v2.3.22/linux/arch/sh/Makefile linux/arch/sh/Makefile
--- v2.3.22/linux/arch/sh/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/Makefile	Mon Oct 18 11:16:12 1999
@@ -1,9 +1,11 @@
-# $Id$
+# $Id: Makefile,v 1.1 1999/09/18 16:55:51 gniibe Exp gniibe $
 #
 # 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  Kaz Kojima
+#
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
 # for "archclean" and "archdep" for cleaning up and making dependencies for
@@ -13,25 +15,35 @@
 #
 # Select the object file format to substitute into the linker script.
 #
-tool-prefix	= sh-gniibe-
-oformat		= elf
+tool-prefix	= sh-elf
+
+ifdef CONFIG_LITTLE_ENDIAN
+CFLAGS		+= -ml
+AFLAGS		+= -ml
+# LINKFLAGS	+= -EL
+LDFLAGS		:= -EL
+
+LD	=$(CROSS_COMPILE)ld $(LDFLAGS)
+
+endif
 
 ifdef CONFIG_CROSSCOMPILE
 CROSS_COMPILE  = $(tool-prefix)
 endif
 
-LINKFLAGS	= # -EL # -static #-N
 MODFLAGS	+=
 
 #
 #
-CFLAGS		+= -m3 # -ml
-LINKFLAGS	+=
-LDFLAGS		+= # -EL
 
-#
-#
-HOSTCC        = cc
+ifdef CONFIG_CPU_SH3
+CFLAGS		+= -m3
+AFLAGS		+= -m3
+endif
+ifdef CONFIG_CPU_SH4
+CFLAGS		+= -m4
+AFLAGS		+= -m4
+endif
 
 #
 # Choosing incompatible machines durings configuration will result in
@@ -52,14 +64,16 @@
 
 SUBDIRS := $(SUBDIRS) $(addprefix arch/sh/, kernel mm lib)
 CORE_FILES := arch/sh/kernel/kernel.o arch/sh/mm/mm.o $(CORE_FILES)
-LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a /home/niibe/lib/gcc-lib/sh-gniibe-elf/egcs-2.91.66/libgcc.a
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+LIBS := $(TOPDIR)/arch/sh/lib/lib.a $(LIBS) $(TOPDIR)/arch/sh/lib/lib.a \
+	$(LIBGCC)
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
 vmlinux: arch/sh/vmlinux.lds
 
 arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE
-	gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/linux/config.h -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
+	gcc -E -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds
 
 FORCE: ;
 
@@ -77,6 +91,7 @@
 #	$(MAKE) -C arch/$(ARCH)/tools clean
 
 archmrproper:
+	rm -f arch/sh/vmlinux.lds
 
 archdep:
 	@$(MAKEBOOT) dep
diff -u --recursive --new-file v2.3.22/linux/arch/sh/config.in linux/arch/sh/config.in
--- v2.3.22/linux/arch/sh/config.in	Mon Oct 11 15:38:14 1999
+++ linux/arch/sh/config.in	Mon Oct 18 11:16:13 1999
@@ -12,28 +12,24 @@
 mainmenu_option next_comment
 comment 'Processor type and features'
 choice 'Processor family' \
-	"SH3		CONFIG_CPU_SH3 \
-	 SH4		CONFIG_CPU_SH4" SH3
+   "SH-3	CONFIG_CPU_SH3 \
+    SH-4	CONFIG_CPU_SH4" SH-3
 bool 'Little Endian' CONFIG_LITTLE_ENDIAN
-hex 'Physical memory start address' CONFIG_MEMORY_START 0c000000
+hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+bool 'Use SH CPU internal real time clock' CONFIG_SH_CPU_RTC
 endmenu
 
 mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-   bool '  Set version information on all symbols for modules' CONFIG_MODVERSIONS
-   bool '  Kernel module loader' CONFIG_KMOD
+   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+   bool 'Kernel module loader' CONFIG_KMOD
 fi
 endmenu
 
-define_bool CONFIG_SERIAL n
-define_bool CONFIG_SH3SCI_SERIAL y
-define_bool CONFIG_SERIAL_CONSOLE y
-
 mainmenu_option next_comment
-comment 'Floppy, IDE, and other block devices'
-
+comment 'General setup'
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
@@ -41,6 +37,18 @@
 
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+endmenu
+
+mainmenu_option next_comment
+comment 'Character devices'
+define_bool CONFIG_SERIAL n
+define_bool CONFIG_SERIAL_CONSOLE y
+bool 'SuperH SCI support' CONFIG_SH_SCI_SERIAL
+bool 'SuperH SCIF support' CONFIG_SH_SCIF_SERIAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Floppy, IDE, and other block devices'
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
@@ -75,4 +83,5 @@
 comment 'Kernel hacking'
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'GDB Stub kernel debug' CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
 endmenu
diff -u --recursive --new-file v2.3.22/linux/arch/sh/defconfig linux/arch/sh/defconfig
--- v2.3.22/linux/arch/sh/defconfig	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/defconfig	Mon Oct 18 11:16:13 1999
@@ -10,48 +10,41 @@
 #
 # Processor type and features
 #
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-# CONFIG_LITTLE_ENDIAN is not set
-CONFIG_MEMORY_START=0c000000
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+CONFIG_LITTLE_ENDIAN=y
+CONFIG_MEMORY_START=08000000
 
 #
 # Loadable module support
 #
 # CONFIG_MODULES is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH3SCI_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
 
 #
-# Floppy, IDE, and other block devices
+# General setup
 #
 # CONFIG_NET is not set
-CONFIG_SYSVIPC=y
+# CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_SYSCTL is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
 
 #
-# Networking options
+# Character devices
 #
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
-# CONFIG_FILTER is not set
-# CONFIG_UNIX is not set
-# CONFIG_INET is not set
+# CONFIG_SERIAL is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SH_SCI_SERIAL is not set
+CONFIG_SH_SCIF_SERIAL=y
 
 #
-#  
+# Floppy, IDE, and other block devices
 #
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
 
 #
 # Unix 98 PTY support
@@ -66,8 +59,12 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_UDF_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -78,16 +75,15 @@
 # CONFIG_UFS_FS is not set
 
 #
-# Network File Systems
-#
-
-#
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMD_DISKLABEL is not set
-# CONFIG_SGI_DISKLABEL is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
@@ -99,3 +95,4 @@
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL_WITH_GDB_STUB=y
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile
--- v2.3.22/linux/arch/sh/kernel/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/Makefile	Mon Oct 18 11:16:13 1999
@@ -11,7 +11,7 @@
 
 O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o irq_onchip.o \
-            ptrace.o setup.o time.o sys_sh.o test-img.o semaphore.o
+            ptrace.o setup.o time.o sys_sh.o semaphore.o
 OX_OBJS  := sh_ksyms.o
 MX_OBJS  :=
 
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- v2.3.22/linux/arch/sh/kernel/entry.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/entry.S	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: entry.S,v 1.15 1999/10/17 01:32:52 gniibe Exp $
  *
  *  linux/arch/sh/entry.S
  *
@@ -12,6 +12,7 @@
 
 #include <linux/sys.h>
 #include <linux/linkage.h>
+#include <linux/config.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -28,18 +29,18 @@
  * Stack layout in 'ret_from_syscall':
  * 	ptrace needs to have all regs on the stack.
  *	if the order here is changed, it needs to be
- *	updated in process.c:copy_thread, signal.c:do_signal,
- *	ptrace.c and ptrace.h
+ *	updated in ptrace.c and ptrace.h
  *
- *	syscall #	
+ *	syscall #
+ *	ssr
+ *	r15 = stack pointer
  *	r0
  *      ...
- *	r15
+ *	r14
  *	gbr
  *	mach
  *	macl
  *	pr
- *	ssr
  *	spc
  *
  */
@@ -57,14 +58,23 @@
 
 ENOSYS = 38
 
-TRA    = 0xffffffd0
-EXPEVT = 0xffffffd4
-INTEVT = 0xffffffd8
+#if defined(__sh3__)
+TRA     = 0xffffffd0
+EXPEVT  = 0xffffffd4
+INTEVT  = 0xffffffd8
+MMU_TEA = 0xfffffffc		! TLB Exception Address Register
+#elif defined(__SH4__)
+TRA     = 0xff000020
+EXPEVT  = 0xff000024
+INTEVT  = 0xff000028
+MMU_TEA = 0xff00000c		! TLB Exception Address Register
+#endif
 
 /* Offsets to the stack */
 SYSCALL_NR =  0
-R0         =  4
-R15	   =  64
+SR	   =  4
+SP	   =  8
+R0         =  12
 
 #define k0	r0
 #define k1	r1
@@ -99,20 +109,19 @@
 ! Although this could be written in assembly language (and it'd be faster),
 ! this first version depends *much* on C implementation.
 !
-MMU_TEA = 0xfffffffc		! TLB Exception Address Register
 
-#define DO_FAULT(write) \
-	mov	#MMU_TEA,r0; \
-	mov.l	@r0,r6; \
-	/* STI */ \
-	mov.l	3f,r1; \
-	stc	sr,r0; \
-	and	r1,r0; \
-	ldc	r0,sr; \
-	/*    */ \
-	mov	r15,r4; \
-	mov.l	2f,r0; \
-	jmp	@r0; \
+#define DO_FAULT(write)			\
+	mov.l	4f,r0;			\
+	mov.l	@r0,r6; 		\
+	/* STI */ 			\
+	mov.l	3f,r1; 			\
+	stc	sr,r0; 			\
+	and	r1,r0; 			\
+	ldc	r0,sr; 			\
+	/*    */ 			\
+	mov	r15,r4; 		\
+	mov.l	2f,r0; 			\
+	jmp	@r0; 			\
 	 mov	#write,r5;
 
 	.balign	4
@@ -133,22 +142,65 @@
 	.balign 4
 2:	.long	SYMBOL_NAME(do_page_fault)
 3:	.long	0xefffffff	! BL=0
+4:	.long	MMU_TEA
 
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+	.balign	4
+	/* Unwind the stack and jmp to the debug entry */
+debug:
+	add	#4,r15		! skip syscall number
+	ldc.l	@r15+,ssr
+	mov.l	@r15+,r10	! original stack
+	mov.l	@r15+,r0
+	mov.l	@r15+,r1
+	mov.l	@r15+,r2
+	mov.l	@r15+,r3
+	mov.l	@r15+,r4
+	mov.l	@r15+,r5
+	mov.l	@r15+,r6
+	mov.l	@r15+,r7
+	stc	sr,r14
+	mov.l	8f,r9			! BL =1, RB=1
+	or	r9,r14
+	ldc	r14,sr			! here, change the register bank
+	mov	r10,k0
+	mov.l	@r15+,r8
+	mov.l	@r15+,r9
+	mov.l	@r15+,r10
+	mov.l	@r15+,r11
+	mov.l	@r15+,r12
+	mov.l	@r15+,r13
+	mov.l	@r15+,r14
+	ldc.l	@r15+,gbr
+	lds.l	@r15+,mach
+	lds.l	@r15+,macl
+	lds.l	@r15+,pr
+	ldc.l	@r15+,spc
+	mov	k0,r15
+	!
+	mov.l	9f,k0
+	jmp	@k0
+	 nop
+	.balign	4
+8:	.long	0x300000f0
+9:	.long	0xa0000100
+#endif
 
 	.balign	4
-error:	mov	#-1,r0
+error:	
 	! STI
 	mov.l	2f,r1
 	stc	sr,r0
 	and	r1,r0
 	ldc	r0,sr
 	!
-	mov.l	r0,@r15		! syscall nr = -1
 	mov.l	1f,r1
+	mov	#-1,r0
 	jmp	@r1
-	 nop
+	 mov.l	r0,@r15		! syscall nr = -1
 	.balign	4
 1:	.long	SYMBOL_NAME(do_exception_error)
+2:	.long	0xefffffff	! BL=0
 
 reschedule:
 	mova	SYMBOL_NAME(ret_from_syscall),r0
@@ -159,12 +211,13 @@
 1:	.long	SYMBOL_NAME(schedule)
 
 badsys:	mov	#-ENOSYS,r0
-	bra	SYMBOL_NAME(ret_from_syscall)
+	rts			! go to ret_from_syscall..
 	 mov.l	r0,@(R0,r15)
 
 signal_return:
 	! We can reach here from an interrupt handler,
 	! so, we need to unblock interrupt.
+	/*  STI */
 	mov.l	1f,r1
 	stc	sr,r0
 	and	r1,r0
@@ -185,15 +238,25 @@
 !
 ENTRY(ret_from_fork)
 	bra	SYMBOL_NAME(ret_from_syscall)
-	 add	#4,r15		! pop down bogus r0
+	 add	#4,r15		! pop down bogus r0 (see switch_to MACRO)
 
 !
 ! The immediate value of "trapa" indicates the number of arguments
 ! placed on the stack.
 !
+! Note that TRA register contains the value = Imm x 4.
+!
 system_call:
-	mov	#TRA,r2
+	mov.l	1f,r2
 	mov.l	@r2,r8
+	!
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+	mov	#0x20,r1
+	extu.b	r1,r1
+	shll2	r1
+	cmp/hs	r1,r8
+	bt	debug
+#endif
 	! STI
 	mov.l	2f,r1
 	stc	sr,r2
@@ -202,14 +265,15 @@
 	!
 	mov.l	__n_sys,r1
 	cmp/ge	r1,r0
-	bt	badsys
+	bt/s	badsys
+	 mov	r0,r2
 	!
 	stc	ksp,r1		!
 	mov.l	__tsk_flags,r0	!
 	add	r0,r1		!
 	mov.l	@r1,r0		! Is it trace?
 	tst	#PF_TRACESYS,r0
-	bt	6f
+	bt	5f
 	!                     Trace system call
 	mov	#-ENOSYS,r1
 	mov.l	r1,@(R0,r15)
@@ -217,32 +281,36 @@
 	jsr	@r1
 	 nop
 	mova	4f,r0
-	bra	7f
+	bra	6f
 	 lds	r0,pr
 	!
-6:	mova	1f,r0
+5:	mova	ret,r0		! normal case
 	lds	r0,pr
 	!			Build the stack frame if TRA > 0
-7:	cmp/pl	r8
+	!
+6:	mov	r2,r3
+	mov	r8,r2
+	cmp/pl	r8
 	bf	9f
-	shll2	r8		! x4
-	mov	#R15,r0
-	mov.l	@(r0,r15),r0	! get original stack
-8:	add	#-4,r8
-	mov.l	@(r0,r8),r1
+	mov.l	@(SP,r15),r0	! get original stack
+7:	add	#-4,r8
+8:	mov.l	@(r0,r8),r1	! May cause address error exception..
 	mov.l	r1,@-r15
 	cmp/pl	r8
-	bt	8b
+	bt	7b
 	!
-9:	mov.l	@(SYSCALL_NR,r15),r0
+9:	mov	r3,r0
 	shll2	r0		! x4
 	mov.l	__sct,r1
 	add	r1,r0
 	mov.l	@r0,r1
 	jmp	@r1
-	 nop
+	 mov	r2,r8
+
+	! In case of trace
 	.balign	4
-4:	mov.l	r0,@(R0,r15)	! save the return value
+4:	add	r8,r15		! pop off the arguments
+	mov.l	r0,@(R0,r15)	! save the return value
 	mov.l	3f,r1
 	mova	SYMBOL_NAME(ret_from_syscall),r0
 	jmp	@r1
@@ -250,11 +318,36 @@
 	.balign	4
 3:	.long	SYMBOL_NAME(syscall_trace)
 2:	.long	0xefffffff	! BL=0
-1:	mov.l	r0,@(R0,r15)	! save the return value
+1:	.long	TRA
+
+	.section	.fixup,"ax"
+fixup_syscall_argerr:
+	rts
+	 mov.l	1f,r0
+1:	.long	-22	! -EINVAL
+.previous
+
+	.section	__ex_table, "a"
+	.balign	4
+	.long	8b,fixup_syscall_argerr
+.previous
+
+
+ENTRY(ret_from_irq)
+	mov.l	@(SR,r15),r0	! get original stack
+	shll	r0
+	shll	r0		! kernel space?
+	bt	restore_all	! Yes, it's from kernel, go back soon
+	! XXX: Is it better to run through bottom half?
+	! In such a case, we should go "ret_from_syscall" instead
+	bra	ret_with_reschedule
+	 nop
+
+ret:	add	r8,r15		! pop off the arguments
+	mov.l	r0,@(R0,r15)	! save the return value
 	/* fall through */
 
 ENTRY(ret_from_syscall)
-ENTRY(ret_from_irq)
 	mov.l	__bh_mask,r0
 	mov.l	@r0,r1
 	mov.l	__bh_active,r0
@@ -276,9 +369,10 @@
 	tst	#0xff,r0
 	bf	signal_return
 	!
-	.balign	4
 restore_all:
 	add	#4,r15		! skip syscall number
+	ldc.l	@r15+,ssr
+	mov.l	@r15+,r10	! original stack
 	mov.l	@r15+,r0
 	mov.l	@r15+,r1
 	mov.l	@r15+,r2
@@ -291,6 +385,7 @@
 	mov.l	__blrb_flags,r9		! BL =1, RB=1
 	or	r9,r14
 	ldc	r14,sr			! here, change the register bank
+	mov	r10,k0
 	mov.l	@r15+,r8
 	mov.l	@r15+,r9
 	mov.l	@r15+,r10
@@ -298,12 +393,10 @@
 	mov.l	@r15+,r12
 	mov.l	@r15+,r13
 	mov.l	@r15+,r14
-	mov.l	@r15+,k0
 	ldc.l	@r15+,gbr
 	lds.l	@r15+,mach
 	lds.l	@r15+,macl
 	lds.l	@r15+,pr
-	ldc.l	@r15+,ssr
 	ldc.l	@r15+,spc
 	mov	k0,r15
 	rte
@@ -330,29 +423,32 @@
 !
 	.balign 	256,0,256
 general_exception:
-	mov	#EXPEVT,k2
+	mov.l	1f,k2
 	mov.l	2f,k3
 	bra	handle_exception
 	 mov.l	@k2,k2
 	.balign	4
 2:	.long	SYMBOL_NAME(ret_from_syscall)
+1:	.long	EXPEVT
 !
 !
 	.balign 	1024,0,1024
 tlb_miss:
-	mov	#EXPEVT,k2
+	mov.l	1f,k2
 	mov.l	3f,k3
 	bra	handle_exception
 	 mov.l	@k2,k2
 !
 	.balign 	512,0,512
 interrupt:
-	mov	#INTEVT,k2
+	mov.l	2f,k2
 	mov.l	4f,k3
 	bra	handle_exception
 	 mov.l	@k2,k2
 
 	.balign	4
+1:	.long	EXPEVT
+2:	.long	INTEVT
 3:	.long	SYMBOL_NAME(ret_from_syscall)
 4:	.long	SYMBOL_NAME(ret_from_irq)
 
@@ -362,15 +458,13 @@
 	! Using k0, k1 for scratch registers (r0_bank1, and r1_bank1),
 	! save all registers onto stack.
 	!
-	mov.l	2f,k1
 	stc	ssr,k0		! from kernel space?
 	shll	k0		! Check MD bit (bit30)
 	shll	k0
 	bt/s	1f		! it's from kernel to kernel transition
 	 mov	r15,k0		! save original stack to k0 anyway
 	mov	kernel_sp,r15	! change to kernel stack
-1:	stc.l	spc,@-r15	! save control registers
-	stc.l	ssr,@-r15
+1:	stc.l	spc,@-r15
 	sts.l	pr,@-r15
 	!
 	lds	k3,pr		! Set the return address to pr
@@ -378,9 +472,9 @@
 	sts.l	macl,@-r15
 	sts.l	mach,@-r15
 	stc.l	gbr,@-r15
-	mov.l	k0,@-r15	! save orignal stack, and general registers
 	mov.l	r14,@-r15
 	!
+	mov.l	2f,k1
 	stc	sr,r14		! back to normal register bank, and
 	and	k1,r14		! ..
 	ldc	r14,sr		! ...changed here.
@@ -399,6 +493,8 @@
 	mov.l	r2,@-r15
 	mov.l	r1,@-r15
 	mov.l	r0,@-r15
+	stc.l	r0_bank,@-r15	! save orignal stack
+	stc.l	ssr,@-r15
 	mov.l	r0,@-r15	! push r0 again (for syscall number)
 	! Then, dispatch to the handler, according to the excepiton code.
 	stc	k_ex_code,r1
@@ -413,10 +509,14 @@
 1:	.long	SYMBOL_NAME(exception_handling_table)
 2:	.long	0xdfffffff	! RB=0, BL=1
 
+none:
+	rts
+	 nop
+
 .data
 ENTRY(exception_handling_table)
-	.long	0
-	.long	0
+	.long	none /* XXX: Avoid spurious interrupt */
+	.long	error
 	.long	tlb_miss_load
 	.long	tlb_miss_store
 	.long	initial_page_write
@@ -424,13 +524,13 @@
 	.long	tlb_protection_violation_store
 	.long	error	! address_error_load        (filled by trap_init)
 	.long	error	! address_error_store       (filled by trap_init)
-	.long	0
-	.long	0
+	.long	error	! fpu_exception
+	.long	error
 	.long	system_call			! Unconditional Trap
 	.long	error	! reserved_instruction      (filled by trap_init)
 	.long	error	! illegal_slot_instruction  (filled by trap_init)
 ENTRY(nmi_slot)
-	.long	error				! Not implemented yet
+	.long	none				! Not implemented yet
 ENTRY(user_break_point_trap)
 	.long	error				! Not implemented yet
 ENTRY(interrupt_table)
@@ -450,7 +550,7 @@
 	.long	SYMBOL_NAME(do_IRQ)	! 1100
 	.long	SYMBOL_NAME(do_IRQ)	! 1101
 	.long	SYMBOL_NAME(do_IRQ)	! 1110
-	.long	0
+	.long	error
 	! Internal hardware
 	.long	SYMBOL_NAME(do_IRQ)	! TMU0 tuni0
 	.long	SYMBOL_NAME(do_IRQ)	! TMU1 tuni1
@@ -468,14 +568,24 @@
 	.long	SYMBOL_NAME(do_IRQ)	!      rovi
 	.long	SYMBOL_NAME(do_IRQ)
 	.long	SYMBOL_NAME(do_IRQ)
+	.long	SYMBOL_NAME(do_IRQ)	! Hitachi UDI
+	.long	SYMBOL_NAME(do_IRQ)	! GPIO
+	.long	SYMBOL_NAME(do_IRQ)	! DMAC dmte0
+	.long	SYMBOL_NAME(do_IRQ)	!      dmte1
+	.long	SYMBOL_NAME(do_IRQ)	!      dmte2
+	.long	SYMBOL_NAME(do_IRQ)	!      dmte3
+	.long	SYMBOL_NAME(do_IRQ)	!      dmae
 	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)
+	.long	SYMBOL_NAME(do_IRQ)	! SCIF eri
+	.long	SYMBOL_NAME(do_IRQ)	!      rxi
+	.long	SYMBOL_NAME(do_IRQ)	!      bri
+	.long	SYMBOL_NAME(do_IRQ)	!      txi
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error ! fpu
+	.long	error ! fpu
 
 ENTRY(sys_call_table)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
@@ -568,7 +678,7 @@
 	.long SYMBOL_NAME(sys_swapon)
 	.long SYMBOL_NAME(sys_reboot)
 	.long SYMBOL_NAME(old_readdir)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* old_mmap */	/* 90 */
+	.long SYMBOL_NAME(sys_mmap)		/* 90 */
 	.long SYMBOL_NAME(sys_munmap)
 	.long SYMBOL_NAME(sys_truncate)
 	.long SYMBOL_NAME(sys_ftruncate)
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S
--- v2.3.22/linux/arch/sh/kernel/head.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/head.S	Mon Oct 18 11:16:13 1999
@@ -1,8 +1,8 @@
-/* $Id$
+/* $Id: head.S,v 1.6 1999/10/05 12:34:16 gniibe Exp $
  *
  *  arch/sh/kernel/head.S
  *
- *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 1999  Niibe Yutaka & Kaz Kojima
  *
  * 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
@@ -10,60 +10,74 @@
  *
  * Head.S contains the SH exception handlers and startup code.
  */
-#include <linux/config.h>
-#include <linux/threads.h>
 #include <linux/linkage.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
 
-#ifdef CONFIG_CPU_SH3
-/* Following values are assumed to be as small as immediate. */
-#define CCR		0xffffffec	/* Address of Cache Control Register */
-#define CACHE_INIT	0x00000009	/* 8k-byte cache, flush, enable */
-#elif CONFIG_CPU_SH4
-/* Should fill here. */
-#endif
+	.section	.empty_zero_page, "aw"
+ENTRY(empty_zero_page)
+	.long	1		/* MOUNT_ROOT_RDONLY */
+	.long	0		/* RAMDISK_FLAGS */
+	.long	0x0200		/* ORIG_ROOT_DEV */
+	.long	1		/* LOADER_TYPE */
+	.long	0x88400000	/* INITRD_START */
+	.long	0x00400000	/* INITRD_SIZE */
+	.long	0x89000000	/* MEMORY_END */
+	.long	0
 
+	.text	
+	.balign 4096,0,4096
+/*
+ * Condition at the entry of _stext:
+ *
+ *   BSC has already been initialized.
+ *   INTC may or may not be initialized.
+ *   VBR may or may not be initialized.
+ *   MMU may or may not be initialized.
+ *   Cache may or may not be initialized.
+ *   Hardware (including on-chip modules) may or may not be initialized. 
+ *
+ *   The register R4&R5 holds the address of the parameter block, which has
+ *   command-line data, etc.
+ *
+ */
 ENTRY(_stext)
-	!			Switch to register bank 0
-	stc	sr,r1		!
-	mov.l	1f,r0		! RB=0, BL=1
-	and	r1,r0
-	ldc	r0,sr
-	!			Enable cache
-#ifdef CONFIG_CPU_SH3
-	mov	#CCR,r1
-	mov.l	@r1,r0
-	cmp/eq	#1,r0		! If it's enabled already, don't flush it
-	bt/s	8f
-	 mov	#CACHE_INIT,r0
-	mov.l	r0,@r1
-#elif CONFIG_CPU_SH4
-	! Should fill here.
+#if defined(__SH4__)
+	!			Initialize FPSCR	
+	/* GCC (as of 2.95.1) assumes FPU with double precision mode. */
+	mov.l	7f,r0
+	lds	r0,fpscr
 #endif
-8:
+	!			Initialize Status Register
+	mov.l	1f,r0		! MD=1, RB=0, BL=1
+	ldc	r0,sr
 	!
 	mov.l	2f,r0
 	mov	r0,r15		! Set initial r15 (stack pointer)
 	ldc	r0,r4_bank	!   and stack base
+	!
+	!			Enable cache
+	mov.l	6f,r0
+	jsr	@r0
+	 nop
 	!			Clear BSS area
 	mov.l	3f,r1
+	add	#4,r1
 	mov.l	4f,r2
 	mov	#0,r0
-9:	mov.l	r0,@r1
-	cmp/hs	r2,r1
-	bf/s	9b
-	 add	#4,r1
+9:	cmp/hs	r2,r1
+	bf/s	9b		! while (r1 < r2)
+	 mov.l	r0,@-r2
 	!			Start kernel
 	mov.l	5f,r0
 	jmp	@r0
 	 nop
 
 	.balign 4
-1:	.long 0xdfffffff		! RB=0, BL=1
-2:	.long SYMBOL_NAME(stack)
-3:	.long SYMBOL_NAME(__bss_start)
-4:	.long SYMBOL_NAME(_end)
-5:	.long SYMBOL_NAME(start_kernel)
-
-.data
+1:	.long	0x50000000		! MD=1, RB=0, BL=1
+2:	.long	SYMBOL_NAME(stack)
+3:	.long	SYMBOL_NAME(__bss_start)
+4:	.long	SYMBOL_NAME(_end)
+5:	.long	SYMBOL_NAME(start_kernel)
+6:	.long	SYMBOL_NAME(cache_init)
+#if defined(__SH4__)
+7:	.long   0x00080000
+#endif
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c
--- v2.3.22/linux/arch/sh/kernel/irq.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/irq.c	Mon Oct 18 11:16:13 1999
@@ -1,10 +1,11 @@
-/*
+/* $Id: irq.c,v 1.4 1999/10/11 13:12:14 gniibe Exp $
+ *
  * linux/arch/sh/kernel/irq.c
  *
  *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
  *
  *
- *  SuperH version:  Copyright (C) 1999  Niibe Yutaka
+ * SuperH version:  Copyright (C) 1999  Niibe Yutaka
  */
 
 /*
@@ -48,7 +49,7 @@
 /*
  * Controller mappings for all interrupt sources:
  */
-irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
 
 /*
  * Special irq handlers.
@@ -57,6 +58,37 @@
 void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 
 /*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
+ */
+	printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none	disable_none
+#define end_none	enable_none
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	startup_none,
+	shutdown_none,
+	enable_none,
+	disable_none,
+	ack_none,
+	end_none
+};
+
+/*
  * Generic, controller-independent functions:
  */
 
@@ -203,6 +235,8 @@
 	struct irqaction * action;
 	unsigned int status;
 
+	regs.syscall_nr = -1;	/* It's not system call */
+
 	/* Get IRQ number */
 	asm volatile("stc	r2_bank,%0\n\t"
 		     "shlr2	%0\n\t"
@@ -257,7 +291,7 @@
 	for (;;) {
 		handle_IRQ_event(irq, &regs, action);
 		spin_lock(&irq_controller_lock);
-		
+
 		if (!(desc->status & IRQ_PENDING))
 			break;
 		desc->status &= ~IRQ_PENDING;
@@ -265,7 +299,7 @@
 	}
 	desc->status &= ~IRQ_INPROGRESS;
 	if (!(desc->status & IRQ_DISABLED)){
-			irq_desc[irq].handler->end(irq);
+		irq_desc[irq].handler->end(irq);
 	}
 	spin_unlock(&irq_controller_lock);
 
@@ -334,16 +368,22 @@
 
 			/* Found it - now remove it from the list of entries */
 			*pp = action->next;
-			if (irq_desc[irq].action)
-				break;
-			irq_desc[irq].status |= IRQ_DISABLED;
-			irq_desc[irq].handler->shutdown(irq);
-			break;
+			if (!irq_desc[irq].action) {
+				irq_desc[irq].status |= IRQ_DISABLED;
+				irq_desc[irq].handler->shutdown(irq);
+			}
+			spin_unlock_irqrestore(&irq_controller_lock,flags);
+
+			/* Wait to make sure it's not being used on another CPU */
+			while (irq_desc[irq].status & IRQ_INPROGRESS)
+				barrier();
+			kfree(action);
+			return;
 		}
 		printk("Trying to free free IRQ%d\n",irq);
-		break;
+		spin_unlock_irqrestore(&irq_controller_lock,flags);
+		return;
 	}
-	spin_unlock_irqrestore(&irq_controller_lock,flags);
 }
 
 /*
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c
--- v2.3.22/linux/arch/sh/kernel/irq_onchip.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/kernel/irq_onchip.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: irq_onchip.c,v 1.3 1999/10/11 13:12:19 gniibe Exp $
+ *
  * linux/arch/sh/kernel/irq_onchip.c
  *
  * Copyright (C) 1999  Niibe Yutaka
@@ -31,32 +32,6 @@
 
 #include <linux/irq.h>
 
-
-/*
- * SH (non-)specific no controller code
- */
-
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq)
-{
-}
-
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define shutdown_none	disable_none
-#define end_none	enable_none
-
-struct hw_interrupt_type no_irq_type = {
-	"none",
-	startup_none,
-	shutdown_none,
-	enable_none,
-	disable_none,
-	ack_none,
-	end_none
-};
-
 struct ipr_data {
 	int offset;
 	int priority;
@@ -104,22 +79,25 @@
  * IPRC  15-12  11-8  7-4  3-0
  *
  */
+#if defined(__sh3__)
 #define INTC_IPR	0xfffffee2UL	/* Word access */
+#define INTC_SIZE	0x2
+#elif defined(__SH4__)
+#define INTC_IPR	0xffd00004UL	/* Word access */
+#define INTC_SIZE	0x4
+#endif
 
 void disable_onChip_irq(unsigned int irq)
 {
 	/* Set priority in IPR to 0 */
 	int offset = ipr_data[irq-TIMER_IRQ].offset;
-	unsigned long intc_ipr_address = INTC_IPR + offset/16;
+	unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE);
 	unsigned short mask = 0xffff ^ (0xf << (offset%16));
-	unsigned long __dummy;
+	unsigned long val;
 
-	asm volatile("mov.w	@%1,%0\n\t"
-		     "and	%2,%0\n\t"
-		     "mov.w	%0,@%1"
-		     : "=&z" (__dummy)
-		     : "r" (intc_ipr_address), "r" (mask)
-		     : "memory" );
+	val = ctrl_inw(intc_ipr_address);
+	val &= mask;
+	ctrl_outw(val, intc_ipr_address);
 }
 
 static void enable_onChip_irq(unsigned int irq)
@@ -127,16 +105,13 @@
 	/* Set priority in IPR back to original value */
 	int offset = ipr_data[irq-TIMER_IRQ].offset;
 	int priority = ipr_data[irq-TIMER_IRQ].priority;
-	unsigned long intc_ipr_address = INTC_IPR + offset/16;
+	unsigned long intc_ipr_address = INTC_IPR + (offset/16*INTC_SIZE);
 	unsigned short value = (priority << (offset%16));
-	unsigned long __dummy;
+	unsigned long val;
 
-	asm volatile("mov.w	@%1,%0\n\t"
-		     "or	%2,%0\n\t"
-		     "mov.w	%0,@%1"
-		     : "=&z" (__dummy)
-		     : "r" (intc_ipr_address), "r" (value)
-		     : "memory" );
+	val = ctrl_inw(intc_ipr_address);
+	val |= value;
+	ctrl_outw(val, intc_ipr_address);
 }
 
 void make_onChip_irq(unsigned int irq)
@@ -149,13 +124,11 @@
 static void mask_and_ack_onChip(unsigned int irq)
 {
 	disable_onChip_irq(irq);
-	sti();
 }
 
 static void end_onChip_irq(unsigned int irq)
 {
 	enable_onChip_irq(irq);
-	cli();
 }
 
 void __init init_IRQ(void)
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.3.22/linux/arch/sh/kernel/process.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/kernel/process.c	Mon Oct 18 11:16:13 1999
@@ -1,9 +1,10 @@
-/*
+/* $Id: process.c,v 1.7 1999/09/23 00:05:41 gniibe Exp $
+ *
  *  linux/arch/sh/kernel/process.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *
- *  SuperH version:  Copyright (C) 1999  Niibe Yutaka
+ *  SuperH version:  Copyright (C) 1999  Niibe Yutaka & Kaz Kojima
  */
 
 /*
@@ -41,6 +42,10 @@
 
 #include <linux/irq.h>
 
+#if defined(__SH4__)
+struct task_struct *last_task_used_math = NULL;
+#endif
+
 static int hlt_counter=0;
 
 #define HARD_IDLE_TIMEOUT (HZ / 3)
@@ -92,22 +97,21 @@
 void show_regs(struct pt_regs * regs)
 {
 	printk("\n");
-	printk("PC: [<%08lx>]", regs->pc);
-	printk(" SP: %08lx", regs->u_regs[UREG_SP]);
-	printk(" SR: %08lx\n", regs->sr);
-	printk("R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
-	       regs->u_regs[0],regs->u_regs[1],
-	       regs->u_regs[2],regs->u_regs[3]);
-	printk("R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
-	       regs->u_regs[4],regs->u_regs[5],
-	       regs->u_regs[6],regs->u_regs[7]);
-	printk("R8 : %08lx R9 : %08lx R10: %08lx R11: %08lx\n",
-	       regs->u_regs[8],regs->u_regs[9],
-	       regs->u_regs[10],regs->u_regs[11]);
-	printk("R12: %08lx R13: %08lx R14: %08lx\n",
-	       regs->u_regs[12],regs->u_regs[13],
-	       regs->u_regs[14]);
-	printk("MACH: %08lx MACL: %08lx GBR: %08lx PR: %08lx",
+	printk("PC  : %08lx SP  : %08lx SR  : %08lx TEA : %08lx\n",
+	       regs->pc, regs->sp, regs->sr, ctrl_inl(MMU_TEA));
+	printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
+	       regs->regs[0],regs->regs[1],
+	       regs->regs[2],regs->regs[3]);
+	printk("R4  : %08lx R5  : %08lx R6  : %08lx R7  : %08lx\n",
+	       regs->regs[4],regs->regs[5],
+	       regs->regs[6],regs->regs[7]);
+	printk("R8  : %08lx R9  : %08lx R10 : %08lx R11 : %08lx\n",
+	       regs->regs[8],regs->regs[9],
+	       regs->regs[10],regs->regs[11]);
+	printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
+	       regs->regs[12],regs->regs[13],
+	       regs->regs[14]);
+	printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
 	       regs->mach, regs->macl, regs->gbr, regs->pr);
 }
 
@@ -163,13 +167,35 @@
  */
 void exit_thread(void)
 {
+#if defined(__sh3__)
 	/* nothing to do ... */
+#elif defined(__SH4__)
+#if 0 /* for the time being... */
+	/* Forget lazy fpu state */
+	if (last_task_used_math == current) {
+		set_status_register (SR_FD, 0);
+		write_system_register (fpscr, FPSCR_PR);
+		last_task_used_math = NULL;
+	}
+#endif
+#endif
 }
 
 void flush_thread(void)
 {
+#if defined(__sh3__)
 	/* do nothing */
 	/* Possibly, set clear debug registers */
+#elif defined(__SH4__)
+#if 0 /* for the time being... */
+	/* Forget lazy fpu state */
+	if (last_task_used_math == current) {
+		set_status_register (SR_FD, 0);
+		write_system_register (fpscr, FPSCR_PR);
+		last_task_used_math = NULL;
+	}
+#endif
+#endif
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -180,6 +206,15 @@
 /* Fill in the fpu structure for a core dump.. */
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
 {
+#if defined(__SH4__)
+#if 0 /* for the time being... */
+	    /* We store the FPU info in the task->thread area.  */
+	    if (! (regs->sr & SR_FD)) {
+		    memcpy (r, &current->thread.fpu, sizeof (*r));
+		    return 1;
+	    }
+#endif
+#endif
 	return 0; /* Task didn't use the fpu at all. */
 }
 
@@ -191,14 +226,26 @@
 	struct pt_regs *childregs;
 
 	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1;
-
 	*childregs = *regs;
+
+#if defined(__SH4__)
+#if 0 /* for the time being... */
+	if (last_task_used_math == current) {
+		set_status_register (SR_FD, 0);
+		sh4_save_fp (p);
+	}
+	/* New tasks loose permission to use the fpu. This accelerates context
+	   switching for most programs since they don't use the fpu.  */
+	p->thread.sr = (read_control_register (sr) &~ SR_MD) | SR_FD;
+	childregs->sr |= SR_FD;
+#endif
+#endif
 	if (user_mode(regs)) {
-		childregs->u_regs[UREG_SP] = usp;
+		childregs->sp = usp;
 	} else {
-		childregs->u_regs[UREG_SP] = (unsigned long)p+2*PAGE_SIZE;
+		childregs->sp = (unsigned long)p+2*PAGE_SIZE;
 	}
-	childregs->u_regs[0] = 0; /* Set return value for child */
+	childregs->regs[0] = 0; /* Set return value for child */
 
 	p->thread.sp = (unsigned long) childregs;
 	p->thread.pc = (unsigned long) ret_from_fork;
@@ -215,18 +262,22 @@
 {
 /* changed the size calculations - should hopefully work better. lbt */
 	dump->magic = CMAGIC;
-	dump->start_code = 0;
-	dump->start_stack = regs->u_regs[UREG_SP] & ~(PAGE_SIZE - 1);
-	dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
-	dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
-	dump->u_dsize -= dump->u_tsize;
-	dump->u_ssize = 0;
+	dump->start_code = current->mm->start_code;
+	dump->start_data  = current->mm->start_data;
+	dump->start_stack = regs->sp & ~(PAGE_SIZE - 1);
+	dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
+	dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT;
+	dump->u_ssize = (current->mm->start_stack - dump->start_stack +
+			 PAGE_SIZE - 1) >> PAGE_SHIFT;
 	/* Debug registers will come here. */
 
-	if (dump->start_stack < TASK_SIZE)
-		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
-
 	dump->regs = *regs;
+
+#if 0 /* defined(__SH4__) */
+	/* FPU */
+	memcpy (&dump->regs[EF_SIZE/4], &current->thread.fpu,
+		sizeof (current->thread.fpu));
+#endif
 }
 
 /*
@@ -248,7 +299,7 @@
 			unsigned long r6, unsigned long r7,
 			struct pt_regs regs)
 {
-	return do_fork(SIGCHLD, regs.u_regs[UREG_SP], &regs);
+	return do_fork(SIGCHLD, regs.sp, &regs);
 }
 
 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
@@ -256,7 +307,7 @@
 			 struct pt_regs regs)
 {
 	if (!newsp)
-		newsp = regs.u_regs[UREG_SP];
+		newsp = regs.sp;
 	return do_fork(clone_flags, newsp, &regs);
 }
 
@@ -274,8 +325,7 @@
 			 unsigned long r6, unsigned long r7,
 			 struct pt_regs regs)
 {
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
-		       regs.u_regs[UREG_SP], &regs);
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, &regs);
 }
 
 /*
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- v2.3.22/linux/arch/sh/kernel/setup.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/setup.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: setup.c,v 1.4 1999/10/17 02:49:24 gniibe Exp $
+ *
  *  linux/arch/sh/kernel/setup.c
  *
  *  Copyright (C) 1999  Niibe Yutaka
@@ -29,6 +30,7 @@
 #endif
 #include <asm/processor.h>
 #include <linux/console.h>
+#include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -38,8 +40,7 @@
  * Machine setup..
  */
 
-struct sh_cpuinfo boot_cpu_data = { 0, 0, 0, 0, };
-extern int _text, _etext, _edata, _end, _stext, __bss_start;
+struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 0, 0, };
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
@@ -48,13 +49,31 @@
 #endif
 
 extern int root_mountflags;
+extern int _text, _etext, _edata, _end;
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM	((unsigned char *)empty_zero_page)
+
+#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000))
+#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004))
+#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008))
+#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c))
+#define INITRD_START (*(unsigned long *) (PARAM+0x010))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
+#define MEMORY_END (*(unsigned long *) (PARAM+0x018))
+/* ... */
+#define COMMAND_LINE ((char *) (PARAM+0x100))
+#define COMMAND_LINE_SIZE 256
+
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
 
-#define COMMAND_LINE_SIZE 1024
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
-extern unsigned char *root_fs_image;
-
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f },
 	{ "pic1", 0x20, 0x3f },
@@ -68,7 +87,6 @@
 
 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
 
-
 /* System RAM - interrupted by the 640kB-1M hole */
 #define code_resource (ram_resources[3])
 #define data_resource (ram_resources[4])
@@ -87,17 +105,26 @@
 	{ "Video ROM", 0xc0000, 0xc7fff }
 };
 
-
 void __init setup_arch(char **cmdline_p,
 		       unsigned long * memory_start_p,
 		       unsigned long * memory_end_p)
 {
-	*cmdline_p = command_line;
-	*memory_start_p = (unsigned long) &_end;
-	*memory_end_p = 0x8c400000; /* For my board. */
-	ram_resources[1].end = *memory_end_p-1;
+	unsigned long memory_start, memory_end;
+
+	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+	if (!MOUNT_ROOT_RDONLY)
+		root_mountflags &= ~MS_RDONLY;
 
-	init_mm.start_code = (unsigned long)&_stext;
+	memory_start = (unsigned long) &_end;
+	memory_end = MEMORY_END;
+
+	init_mm.start_code = (unsigned long)&_text;
 	init_mm.end_code = (unsigned long) &_etext;
 	init_mm.end_data = (unsigned long) &_edata;
 	init_mm.brk = (unsigned long) &_end;
@@ -107,51 +134,25 @@
 	data_resource.start = virt_to_bus(&_etext);
 	data_resource.end = virt_to_bus(&_edata)-1;
 
- 	ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
-
-	initrd_below_start_ok = 1;
-	initrd_start = (long)&root_fs_image;
-	initrd_end = (long)&__bss_start;
-	mount_initrd = 1;
-
-
-#if 0
-	/* Request the standard RAM and ROM resources - they eat up PCI memory space */
-	request_resource(&iomem_resource, ram_resources+0);
-	request_resource(&iomem_resource, ram_resources+1);
-	request_resource(&iomem_resource, ram_resources+2);
-	request_resource(ram_resources+1, &code_resource);
-	request_resource(ram_resources+1, &data_resource);
-#endif
-
-#if 0
-	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
-		request_resource(&ioport_resource, standard_io_resources+i);
-#endif
+	/* Save unparsed command line copy for /proc/cmdline */
+	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
-#if 0
-	rd_image_start = (long)root_fs_image;
-	rd_prompt = 0;
-	rd_doload = 1;
-#endif
+	memcpy(command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+	command_line[COMMAND_LINE_SIZE-1] = '\0';
 
-#if 0
- 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+	/* Not support "mem=XXX[kKmM]" command line option. */
+	*cmdline_p = command_line;
 
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
+	memory_end &= PAGE_MASK;
+	ram_resources[1].end = memory_end-1;
 
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
-#endif
+	*memory_start_p = memory_start;
+	*memory_end_p = memory_end;
 
 #ifdef CONFIG_BLK_DEV_INITRD
-#if 0
 	if (LOADER_TYPE) {
-		initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
+		initrd_start = INITRD_START ? INITRD_START : 0;
 		initrd_end = initrd_start+INITRD_SIZE;
 		if (initrd_end > memory_end) {
 			printk("initrd extends beyond end of memory "
@@ -162,6 +163,29 @@
 	}
 #endif
 
+#if 0
+	/*
+	 * Request the standard RAM and ROM resources -
+	 * they eat up PCI memory space
+	 */
+	request_resource(&iomem_resource, ram_resources+0);
+	request_resource(&iomem_resource, ram_resources+1);
+	request_resource(&iomem_resource, ram_resources+2);
+	request_resource(ram_resources+1, &code_resource);
+	request_resource(ram_resources+1, &data_resource);
+	probe_roms();
+
+	/* request I/O space for devices used on all i[345]86 PCs */
+	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+		request_resource(&ioport_resource, standard_io_resources+i);
+#endif
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
 #endif
 }
 
@@ -173,12 +197,12 @@
 {
 	char *p = buffer;
 
-#ifdef CONFIG_CPU_SH3
-	p += sprintf(p,"cpu family\t: SH3\n"
+#if defined(__sh3__)
+	p += sprintf(p,"cpu family\t: SH-3\n"
 		       "cache size\t: 8K-byte\n");
-#elif CONFIG_CPU_SH4
-	p += sprintf(p,"cpu family\t: SH4\n"
-		       "cache size\t: ??K-byte\n");
+#elif defined(__SH4__)
+	p += sprintf(p,"cpu family\t: SH-4\n"
+		       "cache size\t: 8K-byte/16K-byte\n");
 #endif
 	p += sprintf(p, "bogomips\t: %lu.%02lu\n\n",
 		     (loops_per_sec+2500)/500000,
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c
--- v2.3.22/linux/arch/sh/kernel/signal.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/signal.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: signal.c,v 1.10 1999/09/27 23:25:44 gniibe Exp $
+ *
  *  linux/arch/sh/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -9,8 +10,6 @@
  *
  */
 
-#include <linux/config.h>
-
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -24,6 +23,7 @@
 #include <linux/stddef.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
+#include <asm/pgtable.h>
 
 #define DEBUG_SIG 0
 
@@ -50,7 +50,7 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs.u_regs[0] = -EINTR;
+	regs.regs[0] = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -80,7 +80,7 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs.u_regs[0] = -EINTR;
+	regs.regs[0] = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -126,7 +126,7 @@
 		unsigned long r6, unsigned long r7,
 		struct pt_regs regs)
 {
-	return do_sigaltstack(uss, uoss, regs.u_regs[UREG_SP]);
+	return do_sigaltstack(uss, uoss, regs.sp);
 }
 
 
@@ -137,7 +137,7 @@
 struct sigframe
 {
 	struct sigcontext sc;
-	/* FPU should come here: SH-3 has no FPU */
+	/* FPU data should come here: SH-3 has no FPU */
 	unsigned long extramask[_NSIG_WORDS-1];
 	char retcode[4];
 };
@@ -158,22 +158,22 @@
 {
 	unsigned int err = 0;
 
-#define COPY(x)		err |= __get_user(regs->x, &sc->x)
-				COPY(u_regs[1]);
-	COPY(u_regs[2]);	COPY(u_regs[3]);
-	COPY(u_regs[4]);	COPY(u_regs[5]);
-	COPY(u_regs[6]);	COPY(u_regs[7]);
-	COPY(u_regs[8]);	COPY(u_regs[9]);
-	COPY(u_regs[10]);	COPY(u_regs[11]);
-	COPY(u_regs[12]);	COPY(u_regs[13]);
-	COPY(u_regs[14]);	COPY(u_regs[15]);
-	COPY(gbr);		COPY(mach);
-	COPY(macl);		COPY(pr);
-	COPY(sr);		COPY(pc);
+#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
+			COPY(regs[1]);
+	COPY(regs[2]);	COPY(regs[3]);
+	COPY(regs[4]);	COPY(regs[5]);
+	COPY(regs[6]);	COPY(regs[7]);
+	COPY(regs[8]);	COPY(regs[9]);
+	COPY(regs[10]);	COPY(regs[11]);
+	COPY(regs[12]);	COPY(regs[13]);
+	COPY(regs[14]);	COPY(sp);
+	COPY(gbr);	COPY(mach);
+	COPY(macl);	COPY(pr);
+	COPY(sr);	COPY(pc);
 #undef COPY
 
 	regs->syscall_nr = -1;		/* disable syscall checks */
-	err |= __get_user(*r0_p, &sc->u_regs[0]);
+	err |= __get_user(*r0_p, &sc->sc_regs[0]);
 
 	return err;
 }
@@ -182,7 +182,7 @@
 			     unsigned long r6, unsigned long r7,
 			     struct pt_regs regs)
 {
-	struct sigframe *frame = (struct sigframe *)regs.u_regs[UREG_SP];
+	struct sigframe *frame = (struct sigframe *)regs.sp;
 	sigset_t set;
 	int r0;
 
@@ -213,7 +213,7 @@
 				unsigned long r6, unsigned long r7,
 				struct pt_regs regs)
 {
-	struct rt_sigframe *frame = (struct rt_sigframe *)regs.u_regs[UREG_SP];
+	struct rt_sigframe *frame = (struct rt_sigframe *)regs.sp;
 	sigset_t set;
 	stack_t st;
 	int r0;
@@ -236,7 +236,7 @@
 		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
-	do_sigaltstack(&st, NULL, regs.u_regs[UREG_SP]);
+	do_sigaltstack(&st, NULL, regs.sp);
 
 	return r0;
 
@@ -255,18 +255,18 @@
 {
 	int err = 0;
 
-#define COPY(x)		err |= __put_user(regs->x, &sc->x)
-	COPY(u_regs[0]);	COPY(u_regs[1]);
-	COPY(u_regs[2]);	COPY(u_regs[3]);
-	COPY(u_regs[4]);	COPY(u_regs[5]);
-	COPY(u_regs[6]);	COPY(u_regs[7]);
-	COPY(u_regs[8]);	COPY(u_regs[9]);
-	COPY(u_regs[10]);	COPY(u_regs[11]);
-	COPY(u_regs[12]);	COPY(u_regs[13]);
-	COPY(u_regs[14]);	COPY(u_regs[15]);
-	COPY(gbr);		COPY(mach);
-	COPY(macl);		COPY(pr);
-	COPY(sr);		COPY(pc);
+#define COPY(x)		err |= __put_user(regs->x, &sc->sc_##x)
+	COPY(regs[0]);	COPY(regs[1]);
+	COPY(regs[2]);	COPY(regs[3]);
+	COPY(regs[4]);	COPY(regs[5]);
+	COPY(regs[6]);	COPY(regs[7]);
+	COPY(regs[8]);	COPY(regs[9]);
+	COPY(regs[10]);	COPY(regs[11]);
+	COPY(regs[12]);	COPY(regs[13]);
+	COPY(regs[14]);	COPY(sp);
+	COPY(gbr);	COPY(mach);
+	COPY(macl);	COPY(pr);
+	COPY(sr);	COPY(pc);
 #undef COPY
 
 	/* non-iBCS2 extensions.. */
@@ -294,7 +294,7 @@
 	int err = 0;
 	int signal;
 
-	frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame));
+	frame = get_sigframe(ka, regs->sp, sizeof(*frame));
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
@@ -318,8 +318,8 @@
 		regs->pr = (unsigned long) ka->sa.sa_restorer;
 	} else {
 		/* This is ; mov  #__NR_sigreturn,r0 ; trapa #0 */
-#ifdef CONFIG_LITTLE_ENDIAN
-		unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8);
+#ifdef __LITTLE_ENDIAN__
+		unsigned long code = 0xc300e000 | (__NR_sigreturn);
 #else
 		unsigned long code = 0xe000c300 | (__NR_sigreturn << 16);
 #endif
@@ -332,8 +332,8 @@
 		goto give_sigsegv;
 
 	/* Set up registers for signal handler */
-	regs->u_regs[UREG_SP] = (unsigned long) frame;
-	regs->u_regs[4] = signal; /* Arg for signal handler */
+	regs->sp = (unsigned long) frame;
+	regs->regs[4] = signal; /* Arg for signal handler */
 	regs->pc = (unsigned long) ka->sa.sa_handler;
 
 	set_fs(USER_DS);
@@ -343,6 +343,7 @@
 		current->comm, current->pid, frame, regs->pc, regs->pr);
 #endif
 
+	flush_icache_range(regs->pr, regs->pr+4);
 	return;
 
 give_sigsegv:
@@ -358,7 +359,7 @@
 	int err = 0;
 	int signal;
 
-	frame = get_sigframe(ka, regs->u_regs[UREG_SP], sizeof(*frame));
+	frame = get_sigframe(ka, regs->sp, sizeof(*frame));
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
@@ -376,9 +377,9 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
-	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_SP]),
-			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user((void *)current->sas_ss_sp,
+			  &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 	err |= setup_sigcontext(&frame->uc.uc_mcontext,
 			        regs, set->sig[0]);
@@ -390,8 +391,8 @@
 		regs->pr = (unsigned long) ka->sa.sa_restorer;
 	} else {
 		/* This is ; mov  #__NR_sigreturn,r0 ; trapa #0 */
-#ifdef CONFIG_LITTLE_ENDIAN
-		unsigned long code = 0x00c300e0 | (__NR_sigreturn << 8);
+#ifdef __LITTLE_ENDIAN__
+		unsigned long code = 0xc300e000 | (__NR_sigreturn);
 #else
 		unsigned long code = 0xe000c300 | (__NR_sigreturn << 16);
 #endif
@@ -404,8 +405,8 @@
 		goto give_sigsegv;
 
 	/* Set up registers for signal handler */
-	regs->u_regs[UREG_SP] = (unsigned long) frame;
-	regs->u_regs[4] = signal; /* Arg for signal handler */
+	regs->sp = (unsigned long) frame;
+	regs->regs[4] = signal; /* Arg for signal handler */
 	regs->pc = (unsigned long) ka->sa.sa_handler;
 
 	set_fs(USER_DS);
@@ -415,6 +416,7 @@
 		current->comm, current->pid, frame, regs->pc, regs->pr);
 #endif
 
+	flush_icache_range(regs->pr, regs->pr+4);
 	return;
 
 give_sigsegv:
@@ -434,19 +436,19 @@
 	/* Are we from a system call? */
 	if (regs->syscall_nr >= 0) {
 		/* If so, check system call restarting.. */
-		switch (regs->u_regs[0]) {
+		switch (regs->regs[0]) {
 			case -ERESTARTNOHAND:
-				regs->u_regs[0] = -EINTR;
+				regs->regs[0] = -EINTR;
 				break;
 
 			case -ERESTARTSYS:
 				if (!(ka->sa.sa_flags & SA_RESTART)) {
-					regs->u_regs[0] = -EINTR;
+					regs->regs[0] = -EINTR;
 					break;
 				}
 			/* fallthrough */
 			case -ERESTARTNOINTR:
-				regs->u_regs[0] = regs->syscall_nr;
+				regs->regs[0] = regs->syscall_nr;
 				regs->pc -= 2;
 		}
 	}
@@ -577,7 +579,6 @@
 				/* NOTREACHED */
 			}
 		}
-
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
@@ -586,10 +587,10 @@
 	/* Did we come from a system call? */
 	if (regs->syscall_nr >= 0) {
 		/* Restart the system call - no handlers present */
-		if (regs->u_regs[0] == -ERESTARTNOHAND ||
-		    regs->u_regs[0] == -ERESTARTSYS ||
-		    regs->u_regs[0] == -ERESTARTNOINTR) {
-			regs->u_regs[0] = regs->syscall_nr;
+		if (regs->regs[0] == -ERESTARTNOHAND ||
+		    regs->regs[0] == -ERESTARTSYS ||
+		    regs->regs[0] == -ERESTARTNOINTR) {
+			regs->regs[0] = regs->syscall_nr;
 			regs->pc -= 2;
 		}
 	}
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c
--- v2.3.22/linux/arch/sh/kernel/sys_sh.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/sys_sh.c	Mon Oct 18 11:16:13 1999
@@ -1,9 +1,11 @@
 /*
- * linux/arch/i386/kernel/sys_i386.c
+ * linux/arch/sh/kernel/sys_sh.c
  *
  * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/i386
+ * have a non-standard calling sequence on the Linux/SuperH
  * platform.
+ *
+ * Taken from i386 version.
  */
 
 #include <linux/errno.h>
@@ -41,66 +43,32 @@
 	return error;
 }
 
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
- */
-
-struct mmap_arg_struct {
-	unsigned long addr;
-	unsigned long len;
-	unsigned long prot;
-	unsigned long flags;
-	unsigned long fd;
-	unsigned long offset;
-};
-
-asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+asmlinkage unsigned long
+sys_mmap(int fd, unsigned long addr,
+	 unsigned long len, unsigned long prot,
+	 unsigned long flags, unsigned long off)
 {
 	int error = -EFAULT;
-	struct file * file = NULL;
-	struct mmap_arg_struct a;
-
-	if (copy_from_user(&a, arg, sizeof(a)))
-		return -EFAULT;
+	struct file *file = NULL;
 
 	down(&current->mm->mmap_sem);
 	lock_kernel();
-	if (!(a.flags & MAP_ANONYMOUS)) {
+	if (!(flags & MAP_ANONYMOUS)) {
 		error = -EBADF;
-		file = fget(a.fd);
+		file = fget(fd);
 		if (!file)
 			goto out;
 	}
-	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+	error = do_mmap(file, addr, len, prot, flags, off);
 	if (file)
 		fput(file);
 out:
 	unlock_kernel();
 	up(&current->mm->mmap_sem);
-	return error;
-}
-
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
-struct sel_arg_struct {
-	unsigned long n;
-	fd_set *inp, *outp, *exp;
-	struct timeval *tvp;
-};
-
-asmlinkage int old_select(struct sel_arg_struct *arg)
-{
-	struct sel_arg_struct a;
 
-	if (copy_from_user(&a, arg, sizeof(a)))
-		return -EFAULT;
-	/* sys_select() does the appropriate kernel locking */
-	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+	return error;
 }
 
 /*
@@ -198,9 +166,6 @@
 	return -EINVAL;
 }
 
-/*
- * Old cruft
- */
 asmlinkage int sys_uname(struct old_utsname * name)
 {
 	int err;
@@ -210,35 +175,6 @@
 	err=copy_to_user(name, &system_utsname, sizeof (*name));
 	up(&uts_sem);
 	return err?-EFAULT:0;
-}
-
-asmlinkage int sys_olduname(struct oldold_utsname * name)
-{
-	int error;
-
-	if (!name)
-		return -EFAULT;
-	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
-		return -EFAULT;
-  
-  	down(&uts_sem);
-	
-	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
-	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-	error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-	error |= __put_user(0,name->release+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-	error |= __put_user(0,name->version+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-	
-	up(&uts_sem);
-	
-	error = error ? -EFAULT : 0;
-
-	return error;
 }
 
 asmlinkage int sys_pause(void)
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/test-img.c linux/arch/sh/kernel/test-img.c
--- v2.3.22/linux/arch/sh/kernel/test-img.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/test-img.c	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-unsigned char root_fs_image[]
-__attribute__((__section__(".data.disk_image"))) 
-= {
-0x1f,0x8b,0x08,0x08,0x5d,0xd5,0xc7,0x37,0x00,0x03,0x72,0x2e,0x62,0x69,0x6e,0x00,
-0xed,0xdc,0x3f,0x6c,0x1b,0x55,0x1c,0xc0,0xf1,0xdf,0xf9,0xdc,0x04,0x27,0x69,0xb1,
-0x93,0x14,0x10,0x48,0x91,0xd3,0x02,0x4d,0x8a,0xb8,0xd4,0x21,0x8a,0x09,0x02,0x02,
-0xb5,0x4a,0xab,0x52,0x65,0x69,0x11,0x03,0x42,0xc2,0xb1,0x8f,0xc4,0x92,0xe3,0x03,
-0x9f,0x8d,0xca,0x14,0xd8,0x88,0x2a,0xa6,0x0e,0x88,0xa9,0x20,0xb1,0x87,0x8d,0xa5,
-0x5b,0x86,0xcc,0x90,0x78,0x77,0xd4,0x60,0x75,0xa9,0x40,0xe2,0xdf,0xd0,0x42,0x78,
-0x77,0xef,0x9c,0x38,0x24,0x72,0x49,0x20,0xc9,0x70,0xdf,0x8f,0xf2,0xf3,0xd9,0x77,
-0xbf,0xf3,0xbb,0x67,0xbf,0xdf,0xf9,0x4f,0xf4,0x2c,0x02,0x20,0xac,0xe2,0x2a,0x5e,
-0x53,0x61,0xaa,0x18,0x0e,0xd6,0x19,0xad,0x09,0x49,0x1d,0x5e,0x5e,0x7d,0x75,0x39,
-0xfd,0x6c,0x6d,0x39,0x6d,0x48,0xbf,0x5c,0xfd,0xc9,0xf0,0xf3,0x56,0xd5,0x3a,0x99,
-0xba,0xf7,0xd0,0x76,0x8a,0x53,0x5f,0xc4,0xdf,0xcd,0x24,0x56,0x6e,0x9e,0x59,0xb9,
-0x30,0x3e,0x73,0x3b,0xf7,0x3f,0x76,0x01,0xc0,0x3e,0x79,0x75,0x1f,0x55,0x71,0x4c,
-0x74,0xfd,0x47,0x8f,0xf6,0x70,0x00,0x1c,0xa2,0x8d,0x8d,0x49,0x6f,0xf1,0xc9,0x06,
-0x00,0x00,0x08,0x8d,0xe6,0xfb,0x00,0xef,0x73,0x7c,0x33,0x0e,0xf3,0xfd,0xc7,0xbd,
-0xd7,0xc5,0xff,0xd0,0x31,0x5a,0x5b,0x4e,0xf7,0x05,0xa1,0xb7,0x1c,0x93,0x48,0x4b,
-0x5e,0xe7,0x61,0x1e,0x14,0x80,0x50,0xf0,0xcf,0x3f,0xe7,0x76,0x3b,0xff,0x45,0xe4,
-0x89,0x96,0xbc,0x47,0x54,0xc4,0x54,0x74,0xa9,0xe8,0x56,0xd1,0xa3,0xe2,0xb8,0x8a,
-0x13,0x2a,0x1e,0x15,0xfd,0xfd,0x68,0x42,0x45,0xaf,0x8a,0xbe,0xbd,0xb6,0xaf,0xce,
-0x7f,0x7f,0xaa,0x76,0xef,0x07,0xd1,0x6c,0xbf,0xf5,0xfc,0xd7,0xbf,0xf7,0xae,0x6d,
-0x32,0xda,0x6c,0x6b,0xb6,0x7f,0x56,0x9d,0x77,0x4f,0x05,0xb1,0x5b,0xfb,0x27,0x0f,
-0xa8,0xfd,0x6f,0x06,0xf5,0xf2,0xfe,0x8e,0xfe,0xff,0x63,0xaf,0xff,0xf0,0xc5,0x54,
-0xdb,0xfe,0x7f,0x7a,0xeb,0xf2,0x15,0x53,0xe4,0xe6,0xaa,0x7e,0xed,0x19,0x0b,0xda,
-0xbf,0x75,0xd9,0xd8,0xd6,0xff,0xc7,0xf6,0xdf,0x7c,0xdb,0xf6,0x37,0xbe,0xd6,0x63,
-0x6a,0xe7,0xe3,0xbf,0x7d,0x2f,0xcb,0x1a,0x29,0x16,0x4a,0xd5,0xeb,0xe5,0x7d,0x7c,
-0x73,0xde,0xae,0x7d,0xaf,0x8f,0x3d,0x2a,0xc3,0xda,0xbc,0x1e,0x51,0x6d,0xe9,0x31,
-0xde,0xaf,0x8e,0xac,0xe8,0xb8,0x95,0xe7,0xde,0x77,0xaa,0xa5,0xbc,0x1e,0xf3,0x3d,
-0x62,0x4a,0xde,0xfe,0xc8,0x1f,0xfb,0x3d,0xea,0x49,0x71,0xa7,0x0b,0x25,0x6f,0xfc,
-0xdf,0x36,0x3b,0x65,0xdf,0x07,0x08,0xe0,0x48,0xe8,0xd7,0xb2,0xad,0xfa,0xff,0xd5,
-0xd4,0xf5,0x0f,0x20,0x24,0xf8,0xa7,0x1f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,
-0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,
-0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,0x10,0x5e,0xd4,0x3f,
-0x10,0x4a,0x7a,0x4e,0xcf,0xce,0xf9,0x3f,0xde,0xbc,0xb6,0xbb,0x66,0xa7,0xe4,0x9c,
-0x92,0xeb,0x14,0xed,0xa3,0x3d,0x48,0x00,0x07,0x42,0xcf,0xe3,0xdb,0x59,0xff,0xde,
-0x7c,0xd6,0xbb,0x66,0x54,0x0a,0xa5,0x42,0xe5,0x68,0x8f,0x10,0xc0,0x41,0x99,0xbf,
-0x70,0xe5,0x0d,0x23,0xd2,0x32,0x43,0x38,0x22,0x67,0xc5,0x9f,0x32,0x1c,0xff,0x4a,
-0x2d,0xc7,0xd4,0xd5,0x75,0x7f,0xfd,0x98,0x24,0xd5,0xb6,0x21,0x89,0xf9,0x53,0xe1,
-0x83,0x1d,0xe2,0x41,0x18,0xd3,0x3a,0xfc,0x9f,0x11,0x34,0x74,0x78,0xb7,0x07,0x83,
-0xd8,0xd4,0xe1,0x27,0x67,0xd6,0x8d,0x46,0x7c,0xa4,0x51,0x8f,0xd6,0x3a,0x4a,0xbf,
-0x2c,0xc9,0x7b,0xa7,0x3f,0x33,0x16,0xcc,0x5a,0xb4,0x61,0xd6,0xa3,0x4b,0xe2,0xdc,
-0x91,0xee,0xd2,0xef,0x22,0x89,0xa7,0x55,0xbc,0x38,0xd2,0x98,0xff,0xb9,0x1e,0xf1,
-0xb2,0xa6,0xcd,0xf3,0x89,0x85,0xce,0x75,0xa3,0xf6,0x78,0xe3,0xa4,0x97,0x27,0xb1,
-0xc5,0xbf,0x24,0x76,0x6a,0x68,0xa1,0x7b,0xa5,0x6f,0x4d,0x3e,0x34,0x52,0xe9,0x1b,
-0x0f,0xf2,0xa7,0x7f,0x34,0xea,0xcf,0x2c,0xc9,0xe2,0x1f,0x6b,0x6a,0xfb,0xf7,0x27,
-0xd6,0x0d,0xab,0xd7,0xbe,0xb3,0x26,0x03,0x89,0x86,0x0c,0xf4,0xd6,0x33,0x03,0x7d,
-0x4b,0xf2,0x43,0xd7,0xba,0x21,0xb1,0x5a,0xac,0x71,0xdc,0xbb,0x17,0x2f,0x4f,0xed,
-0x7b,0xe6,0xc6,0x83,0xc5,0xdf,0xbc,0xf5,0xaa,0xcd,0x97,0xe5,0x9d,0xcf,0xe7,0x55,
-0xbf,0x2a,0xf2,0xdd,0x93,0x1b,0xea,0xf6,0xb5,0x6b,0xb3,0x05,0x37,0xa9,0xfe,0xae,
-0x56,0x3f,0xb0,0xcb,0x97,0x06,0xbd,0xe9,0xda,0x32,0x39,0xd9,0x25,0xae,0x33,0x67,
-0x57,0x66,0x0b,0xa5,0x99,0x64,0xb5,0x54,0x75,0xab,0xd9,0xa2,0x65,0x59,0xde,0xc6,
-0x4b,0x76,0xb1,0xe8,0x24,0xdf,0x76,0xca,0xc5,0xbc,0x97,0x7c,0x31,0x93,0x79,0x29,
-0x39,0x74,0x71,0xea,0xad,0xe1,0xa4,0x3d,0x93,0x73,0x9f,0x1f,0xb5,0x26,0x52,0xd6,
-0xf8,0x78,0x32,0x35,0x31,0x31,0x71,0xee,0x85,0xd4,0x58,0x72,0xc8,0x5f,0x9d,0xb2,
-0x52,0xd6,0x68,0xb2,0x6c,0x17,0xed,0xac,0x6b,0x0f,0x8b,0x58,0xee,0xc7,0x73,0x95,
-0xec,0xb4,0x5a,0x56,0xca,0x7a,0x39,0xdb,0xbc,0x56,0xb1,0xaf,0x57,0xc4,0x2a,0x3b,
-0xf9,0x6c,0x25,0x2b,0x96,0xbe,0xcc,0x55,0x9c,0xb2,0xab,0x6e,0xe8,0xc5,0xb4,0xab,
-0x2e,0x72,0xce,0xdc,0x9c,0x5d,0xda,0xd3,0xe9,0xfb,0xa9,0xe0,0xf9,0xeb,0xf0,0xfb,
-0x2f,0xe2,0xc5,0xb7,0x2d,0xdb,0x9b,0x9f,0x14,0x07,0x83,0xbc,0x88,0x7e,0x9e,0x0c,
-0x15,0xf2,0xea,0x2e,0x79,0xc3,0x41,0x9e,0xa9,0xc7,0x81,0xd1,0x3a,0x16,0x64,0x6b,
-0x1c,0xc9,0xc8,0xd6,0xb8,0x69,0x9b,0x37,0xfe,0x2f,0xf3,0x5e,0x11,0xfd,0x93,0x0d,
-0x0f,0x6b,0xf7,0xbc,0x6c,0x9b,0x1e,0xef,0xe7,0xa5,0x77,0xc9,0x4b,0xe8,0xfb,0xda,
-0x5c,0xfd,0xa5,0xba,0x78,0x73,0x97,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x87,0xe8,0x6f,0x20,0x01,0xec,0xc5,0x00,0x00,0x01,0x00,
-};
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
--- v2.3.22/linux/arch/sh/kernel/time.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/kernel/time.c	Mon Oct 18 11:16:13 1999
@@ -1,12 +1,15 @@
-/*
+/* $Id: time.c,v 1.2 1999/10/11 13:12:02 gniibe Exp $
+ *
  *  linux/arch/sh/kernel/time.c
  *
- *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
  *
  *  Some code taken from i386 version.
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
  */
 
+#include <linux/config.h>
+
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -28,6 +31,11 @@
 #include <linux/timex.h>
 #include <linux/irq.h>
 
+#define TMU_TOCR_INIT	0x00
+#define TMU0_TCR_INIT	0x0020
+#define TMU_TSTR_INIT	1
+
+#if defined(__sh3__)
 #define TMU_TOCR	0xfffffe90	/* Byte access */
 #define TMU_TSTR	0xfffffe92	/* Byte access */
 
@@ -35,13 +43,63 @@
 #define TMU0_TCNT	0xfffffe98	/* Long access */
 #define TMU0_TCR	0xfffffe9c	/* Word access */
 
-#define TMU_TOCR_INIT	0x00
-#define TMU0_TCR_INIT	0x0020
-#define TMU_TSTR_INIT	1
-
-#define CLOCK_MHZ	(60/4)
 #define INTERVAL	37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? */
 
+/* SH-3 RTC */
+#define R64CNT  	0xfffffec0
+#define RSECCNT 	0xfffffec2
+#define RMINCNT 	0xfffffec4
+#define RHRCNT  	0xfffffec6
+#define RWKCNT  	0xfffffec8
+#define RDAYCNT 	0xfffffeca
+#define RMONCNT 	0xfffffecc
+#define RYRCNT  	0xfffffece
+#define RSECAR  	0xfffffed0
+#define RMINAR  	0xfffffed2
+#define RHRAR   	0xfffffed4
+#define RWKAR   	0xfffffed6
+#define RDAYAR  	0xfffffed8
+#define RMONAR  	0xfffffeda
+#define RCR1    	0xfffffedc
+#define RCR2    	0xfffffede
+
+#elif defined(__SH4__)
+#define TMU_TOCR	0xffd80000	/* Byte access */
+#define TMU_TSTR	0xffd80004	/* Byte access */
+
+#define TMU0_TCOR	0xffd80008	/* Long access */
+#define TMU0_TCNT	0xffd8000c	/* Long access */
+#define TMU0_TCR	0xffd80010	/* Word access */
+
+#define INTERVAL	83333
+
+/* SH-4 RTC */
+#define R64CNT  	0xffc80000
+#define RSECCNT 	0xffc80004
+#define RMINCNT 	0xffc80008
+#define RHRCNT  	0xffc8000c
+#define RWKCNT  	0xffc80010
+#define RDAYCNT 	0xffc80014
+#define RMONCNT 	0xffc80018
+#define RYRCNT  	0xffc8001c  /* 16bit */
+#define RSECAR  	0xffc80020
+#define RMINAR  	0xffc80024
+#define RHRAR   	0xffc80028
+#define RWKAR   	0xffc8002c
+#define RDAYAR  	0xffc80030
+#define RMONAR  	0xffc80034
+#define RCR1    	0xffc80038
+#define RCR2    	0xffc8003c
+#endif
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
 extern rwlock_t xtime_lock;
 #define TICK_SIZE tick
 
@@ -82,14 +140,48 @@
 	write_unlock_irq(&xtime_lock);
 }
 
-/*
- */
 static int set_rtc_time(unsigned long nowtime)
 {
-/* XXX  should be implemented XXXXXXXXXX */
-	int retval = -1;
+#ifdef CONFIG_SH_CPU_RTC
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+
+	ctrl_outb(2, RCR2);  /* reset pre-scaler & stop RTC */
+
+	cmos_minutes = ctrl_inb(RMINCNT);
+	BCD_TO_BIN(cmos_minutes);
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;	/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		BIN_TO_BCD(real_seconds);
+		BIN_TO_BCD(real_minutes);
+		ctrl_outb(real_seconds, RSECCNT);
+		ctrl_outb(real_minutes, RMINCNT);
+	} else {
+		printk(KERN_WARNING
+		       "set_rtc_time: can't update from %d to %d\n",
+		       cmos_minutes, real_minutes);
+		retval = -1;
+	}
+
+	ctrl_outb(2, RCR2);  /* start RTC */
 
 	return retval;
+#else
+	/* XXX should support other clock devices? */
+	return -1;
+#endif
 }
 
 /* last time the RTC clock got updated */
@@ -131,14 +223,12 @@
  */
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	unsigned long __dummy;
+	unsigned long timer_status;
 
 	/* Clear UNF bit */
-	asm volatile("mov.w	%1,%0\n\t"
-		     "and	%2,%0\n\t"
-		     "mov.w	%0,%1"
-		     : "=&z" (__dummy)
-		     : "m" (__m(TMU0_TCR)), "r" (~0x100));
+	timer_status = ctrl_inw(TMU0_TCR);
+	timer_status &= ~0x100;
+	ctrl_outw(timer_status, TMU0_TCR);
 
 	/*
 	 * Here we are in the timer irq handler. We just have irqs locally
@@ -187,16 +277,67 @@
 
 static unsigned long get_rtc_time(void)
 {
-/* XXX not implemented yet */
+#ifdef CONFIG_SH_CPU_RTC
+	unsigned int sec, min, hr, wk, day, mon, yr, yr100;
+
+ again:
+	ctrl_outb(1, RCR1);  /* clear CF bit */
+	do {
+		sec = ctrl_inb(RSECCNT);
+		min = ctrl_inb(RMINCNT);
+		hr  = ctrl_inb(RHRCNT);
+		wk  = ctrl_inb(RWKCNT);
+		day = ctrl_inb(RDAYCNT);
+		mon = ctrl_inb(RMONCNT);
+#if defined(__SH4__)
+		yr  = ctrl_inw(RYRCNT);
+		yr100 = (yr >> 8);
+		yr &= 0xff;
+#else
+		yr  = ctrl_inb(RYRCNT);
+		yr100 = (yr == 0x99) ? 0x19 : 0x20;
+#endif
+	} while ((ctrl_inb(RCR1) & 0x80) != 0);
+
+	BCD_TO_BIN(yr100);
+	BCD_TO_BIN(yr);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(hr);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(sec);
+
+	if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+	    hr > 23 || min > 59 || sec > 59) {
+		printk(KERN_ERR
+		       "SH RTC: invalid value, resetting to 1 Jan 2000\n");
+		ctrl_outb(2, RCR2);  /* reset, stop */
+		ctrl_outb(0, RSECCNT);
+		ctrl_outb(0, RMINCNT);
+		ctrl_outb(0, RHRCNT);
+		ctrl_outb(6, RWKCNT);
+		ctrl_outb(1, RDAYCNT);
+		ctrl_outb(1, RMONCNT);
+#if defined(__SH4__)
+		ctrl_outw(0x2000, RYRCNT);
+#else
+		ctrl_outb(0, RYRCNT);
+#endif
+		ctrl_outb(1, RCR2);  /* start */
+		goto again;
+	}
+
+	return mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+#else
+	/* XXX should support other clock devices? */
 	return 0;
+#endif
 }
 
 static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
 
 void __init time_init(void)
 {
-	unsigned long __dummy;
-
 	xtime.tv_sec = get_rtc_time();
 	xtime.tv_usec = 0;
 
@@ -204,19 +345,12 @@
 	setup_irq(TIMER_IRQ, &irq0);
 
 	/* Start TMU0 */
-	asm volatile("mov	%1,%0\n\t"
-		     "mov.b	%0,%2		! external clock input\n\t"
-		     "mov	%3,%0\n\t"
-		     "mov.w	%0,%4		! enable timer0 interrupt\n\t"
-		     "mov.l	%5,%6\n\t"
-		     "mov.l	%5,%7\n\t"
-		     "mov	%8,%0\n\t"
-		     "mov.b	%0,%9"
-		     : "=&z" (__dummy)
-		     : "i" (TMU_TOCR_INIT), "m" (__m(TMU_TOCR)),
-		       "i" (TMU0_TCR_INIT), "m" (__m(TMU0_TCR)),
-		       "r" (INTERVAL), "m" (__m(TMU0_TCOR)), "m" (__m(TMU0_TCNT)),
-		       "i" (TMU_TSTR_INIT), "m" (__m(TMU_TSTR)));
+	ctrl_outb(TMU_TOCR_INIT,TMU_TOCR);
+	ctrl_outw(TMU0_TCR_INIT,TMU0_TCR);
+	ctrl_outl(INTERVAL,TMU0_TCOR);
+	ctrl_outl(INTERVAL,TMU0_TCNT);
+	ctrl_outb(TMU_TSTR_INIT,TMU_TSTR);
+
 #if 0
 	/* Start RTC */
 	asm volatile("");
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- v2.3.22/linux/arch/sh/kernel/traps.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sh/kernel/traps.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: traps.c,v 1.3 1999/09/21 14:37:19 gniibe Exp $
+ *
  *  linux/arch/sh/traps.c
  *
  *  SuperH version: Copyright (C) 1999  Niibe Yutaka
@@ -56,10 +57,6 @@
 #define VMALLOC_OFFSET (8*1024*1024)
 #define MODULE_RANGE (8*1024*1024)
 
-static void show_registers(struct pt_regs *regs)
-{/* Not implemented yet. */
-}	
-
 spinlock_t die_lock;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -67,7 +64,7 @@
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	printk("%s: %04lx\n", str, err & 0xffff);
-	show_registers(regs);
+	show_regs(regs);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/Makefile linux/arch/sh/lib/Makefile
--- v2.3.22/linux/arch/sh/lib/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/Makefile	Mon Oct 18 11:16:13 1999
@@ -6,9 +6,7 @@
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
-# L_OBJS  = checksum.o old-checksum.o semaphore.o delay.o \
-# 	usercopy.o getuser.o putuser.o
-L_OBJS  = delay.o memcpy.o memset.o memmove.o csum_partial_copy.o \
-	  wordcopy.o checksum.o # usercopy.o getuser.o putuser.o
+L_OBJS  = delay.o memcpy.o memset.o memmove.o old-checksum.o \
+	  checksum.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/checksum.S linux/arch/sh/lib/checksum.S
--- v2.3.22/linux/arch/sh/lib/checksum.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/lib/checksum.S	Mon Oct 18 11:16:13 1999
@@ -0,0 +1,318 @@
+/* $Id: checksum.S,v 1.1 1999/09/18 16:56:53 gniibe Exp $
+ *
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		IP/TCP/UDP checksumming routines
+ *
+ * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
+ *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *		Tom May, <ftom@netcom.com>
+ *              Pentium Pro/II routines:
+ *              Alexander Kjeldaas <astor@guardian.no>
+ *              Finn Arne Gangstad <finnag@guardian.no>
+ *		Lots of code moved from tcp.c and ip.c; see those files
+ *		for more names.
+ *
+ * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ *			     handling.
+ *		Andi Kleen,  add zeroing on error
+ *                   converted to pure assembler
+ *
+ * SuperH version:  Copyright (C) 1999  Niibe Yutaka
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/errno.h>
+#include <linux/linkage.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*	
+ * unsigned int csum_partial(const unsigned char *buf, int len,
+ *                           unsigned int sum);
+ */
+
+.text
+ENTRY(csum_partial)
+	  /*
+	   * Experiments with Ethernet and SLIP connections show that buff
+	   * is aligned on either a 2-byte or 4-byte boundary.  We get at
+	   * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+	   * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+	   * alignment for the unrolled loop.
+	   */
+	mov	r5,r1
+	mov	r4,r0
+	tst	#2,r0		! Check alignment.
+	bt	2f		! Jump if alignment is ok.
+	!
+	add	#-2,r5		! Alignment uses up two bytes.
+	cmp/pz	r5		!
+	bt/s	1f		! Jump if we had at least two bytes.
+	 clrt
+	bra	6f
+	 add	#2,r5		! r5 was < 2.  Deal with it.
+1:
+	mov.w	@r4+,r0
+	extu.w	r0,r0
+	addc	r0,r6
+	bf	2f
+	add	#1,r6
+2:
+	mov	#-5,r0
+	shld	r0,r5
+	tst	r5,r5
+	bt/s	4f		! if it's =0, go to 4f
+	 clrt
+3:
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	mov.l	@r4+,r0
+	addc	r0,r6
+	movt	r0
+	dt	r5
+	bf/s	3b
+	 cmp/eq	#1,r0
+	mov	#0,r0
+	addc	r0,r6
+4:
+	mov	r1,r5
+	mov	#0x1c,r0
+	and	r0,r5
+	tst	r5,r5
+	bt/s	6f
+	 clrt
+	shlr2	r5
+5:
+	mov.l	@r4+,r0
+	addc	r0,r6
+	movt	r0
+	dt	r5
+	bf/s	5b
+	 cmp/eq	#1,r0
+	mov	#0,r0
+	addc	r0,r6
+6:
+	mov	r1,r5
+	mov	#3,r0
+	and	r0,r5
+	tst	r5,r5
+	bt	9f		! if it's =0 go to 9f
+	mov	#2,r1
+	cmp/hs  r1,r5
+	bf	7f
+	mov.w	@r4+,r0
+	extu.w	r0,r0
+	cmp/eq	r1,r5
+	bt/s	8f
+	 clrt
+	shll16	r0
+	addc	r0,r6
+7:
+	mov.b	@r4+,r0
+	extu.b	r0,r0
+8:
+	addc	r0,r6
+	mov	#0,r0
+	addc	r0,r6 
+9:
+	rts
+	 mov	r6,r0
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst, int len, 
+					int sum, int *src_err_ptr, int *dst_err_ptr)
+ */ 
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ *	  DST definitions? It's damn hard to trigger all cases.  I hope I got
+ *	  them all but there's no guarantee.
+ */
+
+#define SRC(y...)			\
+	9999: y;			\
+	.section __ex_table, "a";	\
+	.long 9999b, 6001f	;	\
+	.previous
+
+#define DST(y...)			\
+	9999: y;			\
+	.section __ex_table, "a";	\
+	.long 9999b, 6002f	;	\
+	.previous
+
+ENTRY(csum_partial_copy_generic)
+	mov.l	r5,@-r15
+	mov.l	r6,@-r15
+
+	mov	#2,r0
+	tst	r0,r5			! Check alignment. 
+	bt	2f			! Jump if alignment is ok.
+	add	#-2,r6			! Alignment uses up two bytes.
+	cmp/pz	r6			! Jump if we had at least two bytes.
+	bt/s	1f
+	 clrt
+	bra	4f
+	 add	#2,r6			! ecx was < 2.  Deal with it.
+SRC(1:	mov.w	@r4+,r0	)
+DST(	mov.w	r0,@r5	)
+	add	#2,r5
+	extu.w	r0,r0
+	addc	r0,r7
+	mov	#0,r0
+	addc	r0,r7
+2:
+	mov	r6,r2
+	mov	#-5,r0
+	shld	r0,r6
+	tst	r6,r6
+	bf/s	2f
+	 clrt
+SRC(1:	mov.l	@r4+,r0	)
+SRC(	mov.l	@r4+,r1	)
+	addc	r0,r7
+DST(	mov.l	r0,@r5	)
+	add	#4,r5
+	addc	r1,r7
+DST(	mov.l	r1,@r5	)
+	add	#4,r5
+
+SRC(	mov.l	@r4+,r0	)
+SRC(	mov.l	@r4+,r1	)
+	addc	r0,r7
+DST(	mov.l	r0,@r5	)
+	add	#4,r5
+	addc	r1,r7
+DST(	mov.l	r1,@r5	)
+	add	#4,r5
+
+SRC(	mov.l	@r4+,r0 	)
+SRC(	mov.l	@r4+,r1	)
+	addc	r0,r7
+DST(	mov.l	r0,@r5	)
+	add	#4,r5
+	addc	r1,r7
+DST(	mov.l	r1,@r5	)
+	add	#4,r5
+
+SRC(	mov.l	@r4+,r0	)
+SRC(	mov.l	@r4+,r1	)
+	addc	r0,r7
+DST(	mov.l	r0,@r5	)
+	add	#4,r5
+	addc	r1,r7
+DST(	mov.l	r1,@r5	)
+	add	#4,r5
+	movt	r0
+	dt	r6
+	bf/s	1b
+	 cmp/eq	#1,r0
+	mov	#0,r0
+	addc	r0,r7
+
+2:	mov	r2,r6
+	mov	#0x1c,r0
+	and	r0,r6
+	cmp/pl	r6
+	bf/s	4f
+	 clrt
+	shlr2	r6
+SRC(3:	mov.l	@r4+,r0	)
+	addc	r0,r7
+DST(	mov.l	r0,@r5	)
+	add	#4,r5
+	movt	r0
+	dt	r6
+	bf/s	3b
+	 cmp/eq	#1,r0
+	mov	#0,r0
+	addc	r0,r7
+4:	mov	r2,r6
+	mov	#3,r0
+	and	r0,r6
+	cmp/pl	r6
+	bf	7f
+	mov	#2,r1
+	cmp/hs	r1,r6
+	bf	5f
+SRC(	mov.w	@r4+,r0	)
+DST(	mov.w	r0,@r5	)
+	extu.w	r0,r0
+	add	#2,r5
+	cmp/eq	r1,r6
+	bt/s	6f
+	 clrt
+	shll16	r0
+	addc	r0,r7
+SRC(5:	mov.b	@r4+,r0	)
+DST(	mov.b	r0,@r5	)
+	extu.b	r0,r0
+6:	addc	r0,r7
+	mov	#0,r0
+	addc	r0,r7
+7:
+5000:
+
+# Exception handler:
+.section .fixup, "ax"							
+
+6001:
+	mov.l	@(8,r15),r0			! src_err_ptr
+	mov	#-EFAULT,r1
+	mov.l	r1,@r0
+
+	! zero the complete destination - computing the rest
+	! is too much work 
+	mov.l	@(4,r15),r5		! dst
+	mov.l	@r15,r6			! len
+	mov	#0,r7
+1:	mov.b	r7,@r5
+	dt	r6
+	bf/s	1b
+	 add	#1,r5
+	mov.l	8000f,r0
+	jmp	@r0
+	 nop
+	.balign 4
+8000:	.long	5000b
+
+6002:
+	mov.l	@(12,r15),r0			! dst_err_ptr
+	mov	#-EFAULT,r1
+	mov.l	r1,@r0
+	mov.l	8001f,r0
+	jmp	@r0
+	 nop
+	.balign 4
+8001:	.long	5000b
+
+.previous
+	add	#8,r15
+	rts
+	 mov	r7,r0
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/checksum.c linux/arch/sh/lib/checksum.c
--- v2.3.22/linux/arch/sh/lib/checksum.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/checksum.c	Wed Dec 31 16:00:00 1969
@@ -1,170 +0,0 @@
-/*
- * Taken from:
- * arch/alpha/lib/checksum.c
- *
- * This file contains network checksum routines that are better done
- * in an architecture-specific manner due to speed..
- */
- 
-#include <linux/string.h>
-
-#include <asm/byteorder.h>
-
-static inline unsigned short from64to16(unsigned long long x)
-{
-	/* add up 32-bit words for 33 bits */
-	x = (x & 0xffffffff) + (x >> 32);
-	/* add up 16-bit and 17-bit words for 17+c bits */
-	x = (x & 0xffff) + (x >> 16);
-	/* add up 16-bit and 2-bit for 16+c bit */
-	x = (x & 0xffff) + (x >> 16);
-	/* add up carry.. */
-	x = (x & 0xffff) + (x >> 16);
-	return x;
-}
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented.
- */
-unsigned short int csum_tcpudp_magic(unsigned long saddr,
-				   unsigned long daddr,
-				   unsigned short len,
-				   unsigned short proto,
-				   unsigned int sum)
-{
-	return ~from64to16(saddr + daddr + sum +
-		((unsigned long) ntohs(len) << 16) +
-		((unsigned long) proto << 8));
-}
-
-unsigned int csum_tcpudp_nofold(unsigned long saddr,
-				unsigned long daddr,
-				unsigned short len,
-				unsigned short proto,
-				unsigned int sum)
-{
-	unsigned long long result;
-
-	result = (saddr + daddr + sum +
-		  ((unsigned long) ntohs(len) << 16) +
-		  ((unsigned long) proto << 8));
-
-	/* Fold down to 32-bits so we don't loose in the typedef-less 
-	   network stack.  */
-	/* 64 to 33 */
-	result = (result & 0xffffffff) + (result >> 32);
-	/* 33 to 32 */
-	result = (result & 0xffffffff) + (result >> 32);
-	return result;
-}
-
-/*
- * Do a 64-bit checksum on an arbitrary memory area..
- *
- * This isn't a great routine, but it's not _horrible_ either. The
- * inner loop could be unrolled a bit further, and there are better
- * ways to do the carry, but this is reasonable.
- */
-static inline unsigned long do_csum(const unsigned char * buff, int len)
-{
-	int odd, count;
-	unsigned long long result = 0;
-
-	if (len <= 0)
-		goto out;
-	odd = 1 & (unsigned long) buff;
-	if (odd) {
-		result = *buff << 8;
-		len--;
-		buff++;
-	}
-	count = len >> 1;		/* nr of 16-bit words.. */
-	if (count) {
-		if (2 & (unsigned long) buff) {
-			result += *(unsigned short *) buff;
-			count--;
-			len -= 2;
-			buff += 2;
-		}
-		count >>= 1;		/* nr of 32-bit words.. */
-		if (count) {
-			if (4 & (unsigned long) buff) {
-				result += *(unsigned int *) buff;
-				count--;
-				len -= 4;
-				buff += 4;
-			}
-			count >>= 1;	/* nr of 64-bit words.. */
-			if (count) {
-				unsigned long carry = 0;
-				do {
-					unsigned long w = *(unsigned long *) buff;
-					count--;
-					buff += 8;
-					result += carry;
-					result += w;
-					carry = (w > result);
-				} while (count);
-				result += carry;
-				result = (result & 0xffffffff) + (result >> 32);
-			}
-			if (len & 4) {
-				result += *(unsigned int *) buff;
-				buff += 4;
-			}
-		}
-		if (len & 2) {
-			result += *(unsigned short *) buff;
-			buff += 2;
-		}
-	}
-	if (len & 1)
-		result += *buff;
-	result = from64to16(result);
-	if (odd)
-		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-out:
-	return result;
-}
-
-/*
- *	This is a version of ip_compute_csum() optimized for IP headers,
- *	which always checksum on 4 octet boundaries.
- */
-unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
-{
-	return ~do_csum(iph,ihl*4);
-}
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
-{
-	unsigned long long result = do_csum(buff, len);
-
-	/* add in old sum, and carry.. */
-	result += sum;
-	/* 32+c bits -> 32 bits */
-	result = (result & 0xffffffff) + (result >> 32);
-	return result;
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-unsigned short ip_compute_csum(unsigned char * buff, int len)
-{
-	return ~from64to16(do_csum(buff,len));
-}
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/csum_partial_copy.c linux/arch/sh/lib/csum_partial_copy.c
--- v2.3.22/linux/arch/sh/lib/csum_partial_copy.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/csum_partial_copy.c	Wed Dec 31 16:00:00 1969
@@ -1,75 +0,0 @@
-/*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
- *		MIPS specific IP/TCP/UDP checksumming routines
- *
- * Authors:	Ralf Baechle, <ralf@waldorf-gmbh.de>
- *		Lots of code moved from tcp.c and ip.c; see those files
- *		for more names.
- *
- *		This program is free software; you can redistribute it and/or
- *		modify it under the terms of the GNU General Public License
- *		as published by the Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- *
- * $Id: csum_partial_copy.c,v 1.2 1998/09/16 13:29:32 ralf Exp $
- */
-#include <net/checksum.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-#include <asm/string.h>
-#include <asm/uaccess.h>
-
-/*
- * copy while checksumming, otherwise like csum_partial
- */
-unsigned int csum_partial_copy(const char *src, char *dst, 
-                               int len, unsigned int sum)
-{
-	/*
-	 * It's 2:30 am and I don't feel like doing it real ...
-	 * This is lots slower than the real thing (tm)
-	 */
-	sum = csum_partial(src, len, sum);
-	memcpy(dst, src, len);
-
-	return sum;
-}
-
-/*
- * Copy from userspace and compute checksum.  If we catch an exception
- * then zero the rest of the buffer.
- */
-unsigned int csum_partial_copy_from_user (const char *src, char *dst,
-                                          int len, unsigned int sum,
-                                          int *err_ptr)
-{
-	int missing;
-
-	missing = copy_from_user(dst, src, len);
-	if (missing) {
-		memset(dst + len - missing, 0, missing);
-		*err_ptr = -EFAULT;
-	}
-		
-	return csum_partial(dst, len, sum);
-}
-
-/*
- * Copy to userspace and compute checksum.
- */
-unsigned int csum_partial_copy_to_user (const char *src, char *dst,
-                                        int len, unsigned int sum,
-                                        int *err_ptr)
-{
-	sum = csum_partial(src, len, sum);
-
-	if (copy_to_user(dst, src, len)) {
-		*err_ptr = -EFAULT;
-		return sum;
-	}
-
-	return sum;
-}
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/memcpy.S linux/arch/sh/lib/memcpy.S
--- v2.3.22/linux/arch/sh/lib/memcpy.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/memcpy.S	Mon Oct 18 11:16:13 1999
@@ -1,131 +1,227 @@
-! Taken from newlib-1.8.0
+/* $Id: memcpy.S,v 1.3 1999/09/28 11:32:48 gniibe Exp $
+ *
+ * "memcpy" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ */
 
-!
-! Fast SH memcpy
-!
-! by Toshiyasu Morita (tm@netcom.com)
-! hacked by J"orn Rernnecke (amylaar@cygnus.co.uk) ("o for o-umlaut)
-!
-! Entry: r4: destination pointer
-!        r5: source pointer
-!        r6: byte count
-!
-! Exit:  r0: destination pointer
-!        r1-r7: trashed
-!
-! Notes: Usually one wants to do small reads and write a longword, but
-!        unfortunately it is difficult in some cases to concatanate bytes
-!        into a longword on the SH, so this does a longword read and small
-!        writes.
-!
-! This implementation makes two assumptions about how it is called:
-!
-! 1.: If the byte count is nonzero, the address of the last byte to be
-!     copied is unsigned greater than the address of the first byte to
-!     be copied.  This could be easily swapped for a signed comparison,
-!     but the algorithm used needs some comparison.
-!
-! 2.: When there are two or three bytes in the last word of an 11-or-bore
-!     bytes memory chunk to b copied, the rest of the word can be read
-!     without size effects.
-!     This could be easily changed by increasing the minumum size of
-!     a fast memcpy and the amount subtracted from r7 before L_2l_loop be 2,
-!     however, this would cost a few extra cyles on average.
-!
+/*
+ * void *memcpy(void *dst, const void *src, size_t n);
+ * No overlap between the memory of DST and of SRC are assumed.
+ */
 
 #include <linux/linkage.h>
 ENTRY(memcpy)
-	! Big endian version copies with decreasing addresses.
-	mov	r4,r0
-	add	r6,r0
-	sub	r4,r5
-	mov	#11,r1
-	cmp/hs	r1,r6
-	bf/s	L_small
+	tst	r6,r6
+	bt/s	9f		! if n=0, do nothing
+	 mov	r4,r0
+	sub	r4,r5		! From here, r5 has the distance to r0
+	add	r6,r0		! From here, r0 points the end of copying point
+	mov	#12,r1
+	cmp/gt	r6,r1
+	bt/s	7f		! if it's too small, copy a byte at once
 	 add	#-1,r5
-	mov	r5,r3
-	add	r0,r3
-	shlr	r3
-	bt/s	L_even
-	 mov	r4,r7
-	mov.b	@(r0,r5),r2
-	add	#-1,r3
-	mov.b	r2,@-r0
-L_even:
-	tst	#1,r0
-	add	#-1,r5
-	bf/s	L_odddst
-	 add	#8,r7
-	tst	#2,r0
-	bt	L_al4dst
-	add	#-1,r3
-	mov.w	@(r0,r5),r1
-	mov.w	r1,@-r0
-L_al4dst:
-	shlr	r3
-	bt	L_al4both
-	mov.w	@(r0,r5),r1
-	swap.w	r1,r1
-	add	#4,r7
-	add	#-4,r5
-	.align	2
-L_2l_loop:
-	mov.l	@(r0,r5),r2
-	xtrct	r2,r1
-	mov.l	r1,@-r0
-	cmp/hs	r7,r0
-	mov.l	@(r0,r5),r1
-	xtrct	r1,r2
-	mov.l	r2,@-r0
-	bt	L_2l_loop
-	bra	L_cleanup
-	 add	#5,r5
+	add	#1,r5
+	!			From here, r6 is free
+	!
+	!      r4   -->  [ ...  ] DST             [ ...  ] SRC
+	!	         [ ...  ]                 [ ...  ]
+	!	           :                        :
+	!      r0   -->  [ ...  ]       r0+r5 --> [ ...  ]
+	!
+	!
+	mov	r5,r1
+	mov	#3,r2
+	and	r2,r1
+	shll2	r1
+	mov	r0,r3		! Save the value on R0 to R3
+	mova	jmptable,r0
+	add	r1,r0
+	mov.l	@r0,r1
+	jmp	@r1
+	 mov	r3,r0		! and back to R0
+	.balign	4
+jmptable:
+	.long	case0
+	.long	case1
+	.long	case2
+	.long	case3
 
-	nop ! avoid nop in executed code.
-L_al4both:
-	add	#-2,r5
-	.align	2
-L_al4both_loop:
-	mov.l	@(r0,r5),r1
-	cmp/hs	r7,r0
-	bt/s	L_al4both_loop
+	! copy a byte at once
+7:	mov	r4,r2
+	add	#1,r2
+8:
+	cmp/hi	r2,r0
+	mov.b	@(r0,r5),r1
+	bt/s	8b			! while (r0>r2)
+	 mov.b	r1,@-r0
+9:
+	rts
+	 nop
+
+case0:
+	!
+	!	GHIJ KLMN OPQR -->  GHIJ KLMN OPQR
+	!
+	! First, align to long word boundary
+	mov	r0,r3
+	and	r2,r3
+	tst	r3,r3
+	bt/s	2f
+	 add	#-4,r5
+	add	#3,r5
+1:	dt	r3
+	mov.b	@(r0,r5),r1
+	bf/s	1b
+	 mov.b	r1,@-r0
+	!
+	add	#-3,r5
+2:	! Second, copy a long word at once
+	mov	r4,r2
+	add	#7,r2
+3:	mov.l	@(r0,r5),r1
+	cmp/hi	r2,r0
+	bt/s	3b
 	 mov.l	r1,@-r0
-	bra	L_cleanup
+	!
+	! Third, copy a byte at once, if necessary
+	cmp/eq	r4,r0
+	bt/s	9b
 	 add	#3,r5
+	bra	8b
+	 add	#-6,r2
 
-	nop ! avoid nop in executed code.
-L_odddst:
-	shlr	r3
-	bt	L_al4src
-	mov.w	@(r0,r5),r1
-	mov.b	r1,@-r0
-	shlr8	r1
-	mov.b	r1,@-r0
-L_al4src:
-	add	#-2,r5
-	.align	2
-L_odd_loop:
-	mov.l	@(r0,r5),r2
-	cmp/hs	r7,r0
-	mov.b	r2,@-r0
-	shlr8	r2
-	mov.w	r2,@-r0
-	shlr16	r2
-	mov.b	r2,@-r0
-	bt	L_odd_loop
-
-	add	#3,r5
-L_cleanup:
-L_small:
+case1:
+	!
+	!	GHIJ KLMN OPQR -->  ...G HIJK LMNO PQR.
+	!
+	! First, align to long word boundary
+	mov	r0,r3
+	and	r2,r3
+	tst	r3,r3
+	bt/s	2f
+	 add	#-1,r5
+1:	dt	r3
+	mov.b	@(r0,r5),r1
+	bf/s	1b
+	 mov.b	r1,@-r0
+	!
+2:	! Second, read a long word and write a long word at once
+	mov.l	@(r0,r5),r1
+	add	#-4,r5
+	mov	r4,r2
+	add	#7,r2
+	!
+#ifdef __LITTLE_ENDIAN__
+3:	mov	r1,r3		! RQPO
+	shll16	r3
+	shll8	r3		! Oxxx
+	mov.l	@(r0,r5),r1	! NMLK
+	mov	r1,r6
+	shlr8	r6		! xNML
+	or	r6,r3		! ONML
+	cmp/hi	r2,r0
+	bt/s	3b
+	 mov.l	r3,@-r0
+#else
+3:	mov	r1,r3		! OPQR
+	shlr16	r3
+	shlr8	r3		! xxxO
+	mov.l	@(r0,r5),r1	! KLMN
+	mov	r1,r6
+	shll8	r6		! LMNx
+	or	r6,r3		! LMNO
+	cmp/hi	r2,r0
+	bt/s	3b
+	 mov.l	r3,@-r0
+#endif
+	!
+	! Third, copy a byte at once, if necessary
 	cmp/eq	r4,r0
-	bt	L_ready
-	add	#1,r4
-	.align	2
-L_cleanup_loop:
-	mov.b	@(r0,r5),r2
+	bt/s	9b
+	 add	#4,r5
+	bra	8b
+	 add	#-6,r2
+
+case2:
+	!
+	!	GHIJ KLMN OPQR -->  ..GH IJKL MNOP QR..
+	!
+	! First, align to word boundary
+	tst	#1,r0
+	bt/s	2f
+	 add	#-1,r5
+	mov.b	@(r0,r5),r1
+	mov.b	r1,@-r0
+	!
+2:	! Second, read a word and write a word at once
+	add	#-1,r5
+	mov	r4,r2
+	add	#3,r2
+	!
+3:	mov.w	@(r0,r5),r1
+	cmp/hi	r2,r0
+	bt/s	3b
+	 mov.w	r1,@-r0
+	!
+	! Third, copy a byte at once, if necessary
 	cmp/eq	r4,r0
-	mov.b	r2,@-r0
-	bf	L_cleanup_loop
-L_ready:
+	bt/s	9b
+	 add	#1,r5
+	mov.b	@(r0,r5),r1
 	rts
-	 nop
+	 mov.b	r1,@-r0
+
+case3:
+	!
+	!	GHIJ KLMN OPQR -->  .GHI JKLM NOPQ R...
+	!
+	! First, align to long word boundary
+	mov	r0,r3
+	and	r2,r3
+	tst	r3,r3
+	bt/s	2f
+	 add	#-1,r5
+1:	dt	r3
+	mov.b	@(r0,r5),r1
+	bf/s	1b
+	 mov.b	r1,@-r0
+	!
+2:	! Second, read a long word and write a long word at once
+	add	#-2,r5
+	mov.l	@(r0,r5),r1
+	add	#-4,r5
+	mov	r4,r2
+	add	#7,r2
+	!
+#ifdef __LITTLE_ENDIAN__
+3:	mov	r1,r3		! RQPO
+	shll8	r3		! QPOx
+	mov.l	@(r0,r5),r1	! NMLK
+	mov	r1,r6
+	shlr16	r6
+	shlr8	r6		! xxxN
+	or	r6,r3		! QPON
+	cmp/hi	r2,r0
+	bt/s	3b
+	 mov.l	r3,@-r0
+#else
+3:	mov	r1,r3		! OPQR
+	shlr8	r3		! xOPQ
+	mov.l	@(r0,r5),r1	! KLMN
+	mov	r1,r6
+	shll16	r6
+	shll8	r6		! Nxxx
+	or	r6,r3		! NOPQ
+	cmp/hi	r2,r0
+	bt/s	3b
+	 mov.l	r3,@-r0
+#endif
+	!
+	! Third, copy a byte at once, if necessary
+	cmp/eq	r4,r0
+	bt/s	9b
+	 add	#6,r5
+	bra	8b
+	 add	#-6,r2
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/memmove.S linux/arch/sh/lib/memmove.S
--- v2.3.22/linux/arch/sh/lib/memmove.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/memmove.S	Mon Oct 18 11:16:13 1999
@@ -1,422 +1,254 @@
+/* $Id: memmove.S,v 1.2 1999/09/21 12:55:49 gniibe Exp $
+ *
+ * "memmove" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ */
+
+/*
+ * void *memmove(void *dst, const void *src, size_t n);
+ * The memory areas may overlap.
+ */
+
 #include <linux/linkage.h>
 ENTRY(memmove)
-	mov.l	r8,@-r15
-	mov.l	r9,@-r15
-	mov.l	r14,@-r15
-	sts.l	pr,@-r15
-	add	#-28,r15
-	mov	r15,r14
-	mov.l	r4,@r14
-	mov.l	r5,@(4,r14)
-	mov.l	r6,@(8,r14)
-	mov.l	@r14,r1
-	mov.l	r1,@(12,r14)
-	mov.l	@(4,r14),r1
-	mov.l	r1,@(16,r14)
-	mov.l	@(12,r14),r1
-	mov.l	@(16,r14),r2
-	sub	r2,r1
-	mov.l	@(8,r14),r2
-	cmp/hs	r2,r1
-	bt	.L54
-	bra	.L2
-	nop
-.L54:
-	mov.l	@(8,r14),r1
-	mov	#15,r2
-	cmp/gt	r2,r1
-	bt	.LF100
-	bra	.L52
-	nop
-.LF100:
-	mov.l	@(12,r14),r2
-	neg	r2,r1
-	mov	#3,r2
-	and	r1,r2
-	mov.l	@(8,r14),r1
-	mov	r1,r9
-	sub	r2,r9
-	mov	r9,r2
-	mov.l	r2,@(8,r14)
-.L4:
-	mov.l	@(12,r14),r2
-	neg	r2,r1
-	mov	#3,r2
-	and	r1,r2
-	mov.l	r2,@(20,r14)
-.L7:
-	mov.l	@(20,r14),r1
-	cmp/pl	r1
-	bt	.L9
-	bra	.L6
-	nop
-	.align 2
-.L9:
-	mov	r14,r2
-	mov	r14,r1
-	add	#24,r1
-	mov.l	@(16,r14),r2
-	mov.b	@r2,r3
-	mov.b	r3,@r1
-	mov.l	@(16,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(20,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(12,r14),r1
-	mov	r14,r2
-	mov	r14,r3
-	add	#24,r3
-	mov.b	@r3,r2
-	mov.b	r2,@r1
-	mov.l	@(12,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(12,r14)
-	bra	.L7
-	nop
-	.align 2
-.L8:
-.L6:
-	bra	.L5
-	nop
-	.align 2
-.L10:
-	bra	.L4
-	nop
-	.align 2
-.L5:
-	nop
-.L11:
-	mov.l	@(16,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	tst	r2,r2
-	bf	.L14
-	mov	r15,r2
-	mov.l	@(12,r14),r1
-	mov.l	@(16,r14),r2
-	mov.l	@(8,r14),r7
-	mov	r7,r3
-	shlr2	r3
-	mov	r1,r4
-	mov	r2,r5
-	mov	r3,r6
-	mov.l	.L46,r8
-	jsr	@r8
-	nop
-	bra	.L15
-	nop
-	.align 2
-.L14:
-	mov	r15,r2
-	mov.l	@(12,r14),r1
-	mov.l	@(16,r14),r2
-	mov.l	@(8,r14),r7
-	mov	r7,r3
-	shlr2	r3
-	mov	r1,r4
-	mov	r2,r5
-	mov	r3,r6
-	mov.l	.L47,r8
-	jsr	@r8
-	nop
-.L15:
-	mov.l	@(8,r14),r1
-	mov	#-4,r2
-	and	r2,r1
-	mov.l	@(16,r14),r2
-	add	r2,r1
-	mov.l	r1,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	#-4,r2
-	and	r2,r1
-	mov.l	@(12,r14),r2
-	add	r2,r1
-	mov.l	r1,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	mov.l	r2,@(8,r14)
-.L13:
-.L52:
-	bra	.L3
-	nop
-	.align 2
-.L16:
-	bra	.L11
-	nop
-	.align 2
-.L12:
-.L3:
-	nop
-.L17:
-	mov.l	@(8,r14),r1
-	mov.l	r1,@(20,r14)
-.L20:
-	mov.l	@(20,r14),r1
-	cmp/pl	r1
-	bt	.L22
-	bra	.L19
-	nop
-	.align 2
-.L22:
-	mov	r14,r2
-	mov	r14,r1
-	add	#24,r1
-	mov.l	@(16,r14),r2
-	mov.b	@r2,r3
-	mov.b	r3,@r1
-	mov.l	@(16,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(20,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(12,r14),r1
-	mov	r14,r2
-	mov	r14,r3
-	add	#24,r3
-	mov.b	@r3,r2
-	mov.b	r2,@r1
-	mov.l	@(12,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(12,r14)
-	bra	.L20
-	nop
-	.align 2
-.L21:
-.L19:
-	bra	.L18
-	nop
-	.align 2
-.L23:
-	bra	.L17
-	nop
-	.align 2
-.L18:
-	bra	.L24
-	nop
-	.align 2
-.L2:
-	mov.l	@(16,r14),r1
-	mov.l	@(8,r14),r2
-	add	r2,r1
-	mov.l	r1,@(16,r14)
-	mov.l	@(12,r14),r1
-	mov.l	@(8,r14),r2
-	add	r2,r1
-	mov.l	r1,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	#15,r2
-	cmp/gt	r2,r1
-	bt	.LF101
-	bra	.L53
-	nop
-.LF101:
-	mov.l	@(12,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	mov.l	@(8,r14),r1
-	mov	r1,r9
-	sub	r2,r9
-	mov	r9,r2
-	mov.l	r2,@(8,r14)
-.L26:
-	mov.l	@(12,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	mov.l	r2,@(20,r14)
-.L29:
-	mov.l	@(20,r14),r1
-	cmp/pl	r1
-	bt	.L31
-	bra	.L28
-	nop
-	.align 2
-.L31:
-	mov.l	@(16,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(16,r14)
-	mov	r14,r2
-	mov	r14,r1
-	add	#24,r1
-	mov.l	@(16,r14),r2
-	mov.b	@r2,r3
-	mov.b	r3,@r1
-	mov.l	@(12,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(20,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(12,r14),r1
-	mov	r14,r2
-	mov	r14,r3
-	add	#24,r3
-	mov.b	@r3,r2
-	mov.b	r2,@r1
-	bra	.L29
-	nop
-	.align 2
-.L30:
-.L28:
-	bra	.L27
-	nop
-	.align 2
-.L32:
-	bra	.L26
-	nop
-	.align 2
-.L27:
-	nop
-.L33:
-	mov.l	@(16,r14),r1
+	! if dest > src, call memcpy (it copies in decreasing order)
+	cmp/hi	r5,r4
+	bf	1f
+	mov.l	2f,r0
+	jmp	@r0
+	 nop
+	.balign 4
+2:	.long	SYMBOL_NAME(memcpy)
+1:
+	sub	r5,r4		! From here, r4 has the distance to r0
+	tst	r6,r6
+	bt/s	9f		! if n=0, do nothing
+	 mov	r5,r0
+	add	r6,r5
+	mov	#12,r1
+	cmp/gt	r6,r1
+	bt/s	8f		! if it's too small, copy a byte at once
+	 add	#-1,r4
+	add	#1,r4
+	!
+	!                [ ...  ] DST             [ ...  ] SRC
+	!	         [ ...  ]                 [ ...  ]
+	!	           :                        :
+	!      r0+r4-->  [ ...  ]       r0    --> [ ...  ]
+	!	           :                        :
+	!	         [ ...  ]                 [ ...  ]
+	!			        r5    -->
+	!
+	mov	r4,r1
 	mov	#3,r2
-	and	r1,r2
-	tst	r2,r2
-	bf	.L36
-	mov	r15,r2
-	mov.l	@(12,r14),r1
-	mov.l	@(16,r14),r2
-	mov.l	@(8,r14),r7
-	mov	r7,r3
-	shlr2	r3
-	mov	r1,r4
-	mov	r2,r5
-	mov	r3,r6
-	mov.l	.L48,r8
-	jsr	@r8
-	nop
-	bra	.L37
-	nop
-	.align 2
-.L36:
-	mov	r15,r2
-	mov.l	@(12,r14),r1
-	mov.l	@(16,r14),r2
-	mov.l	@(8,r14),r7
-	mov	r7,r3
-	shlr2	r3
-	mov	r1,r4
-	mov	r2,r5
-	mov	r3,r6
-	mov.l	.L49,r8
-	jsr	@r8
-	nop
-.L37:
-	mov.l	@(8,r14),r1
-	mov	#-4,r2
 	and	r2,r1
-	mov.l	@(16,r14),r2
-	mov	r2,r9
-	sub	r1,r9
-	mov	r9,r1
-	mov.l	r1,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	#-4,r2
-	and	r2,r1
-	mov.l	@(12,r14),r2
-	mov	r2,r9
-	sub	r1,r9
-	mov	r9,r1
-	mov.l	r1,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	mov.l	r2,@(8,r14)
-.L35:
-.L53:
-	bra	.L25
-	nop
-	.align 2
-.L38:
-	bra	.L33
-	nop
-	.align 2
-.L34:
-.L25:
-	nop
-.L39:
-	mov.l	@(8,r14),r1
-	mov.l	r1,@(20,r14)
-.L42:
-	mov.l	@(20,r14),r1
-	cmp/pl	r1
-	bt	.L44
-	bra	.L41
-	nop
-	.align 2
-.L44:
-	mov.l	@(16,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(16,r14)
-	mov	r14,r2
-	mov	r14,r1
-	add	#24,r1
-	mov.l	@(16,r14),r2
-	mov.b	@r2,r3
-	mov.b	r3,@r1
-	mov.l	@(12,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(20,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(12,r14),r1
-	mov	r14,r2
-	mov	r14,r3
-	add	#24,r3
-	mov.b	@r3,r2
-	mov.b	r2,@r1
-	bra	.L42
-	nop
-	.align 2
-.L43:
-.L41:
-	bra	.L24
-	nop
-	.align 2
-.L45:
-	bra	.L39
-	nop
-	.align 2
-.L40:
-.L24:
-	mov.l	@r14,r1
-	mov	r1,r0
-	bra	.L1
-	nop
-	.align 2
-.L1:
-	add	#28,r14
-	mov	r14,r15
-	lds.l	@r15+,pr
-	mov.l	@r15+,r14
-	mov.l	@r15+,r9
-	mov.l	@r15+,r8
-	rts	
-	 nop
-.L50:
-	.align 2
-.L46:
-	.long	__wordcopy_fwd_aligned
-.L47:
-	.long	__wordcopy_fwd_dest_aligned
-.L48:
-	.long	__wordcopy_bwd_aligned
-.L49:
-	.long	__wordcopy_bwd_dest_aligned
-.Lfe1:
+	shll2	r1
+	mov	r0,r3		! Save the value on R0 to R3
+	mova	jmptable,r0
+	add	r1,r0
+	mov.l	@r0,r1
+	jmp	@r1
+	 mov	r3,r0		! and back to R0
+	.balign	4
+jmptable:
+	.long	case0
+	.long	case1
+	.long	case2
+	.long	case3
+
+	! copy a byte at once
+8:	mov.b	@r0+,r1
+	cmp/hs	r5,r0
+	bf/s	8b			! while (r0<r5)
+	 mov.b	r1,@(r0,r4)
+	add	#1,r4
+9:
+	add	r4,r0
+	rts
+	 sub	r6,r0
+
+case_none:
+	bra	8b
+	 add	#-1,r4
+
+case0:
+	!
+	!	GHIJ KLMN OPQR -->  GHIJ KLMN OPQR
+	!
+	! First, align to long word boundary
+	mov	r0,r3
+	and	r2,r3
+	tst	r3,r3
+	bt/s	2f
+	 add	#-1,r4
+	mov	#4,r2
+	sub	r3,r2
+1:	dt	r2
+	mov.b	@r0+,r1
+	bf/s	1b
+	 mov.b	r1,@(r0,r4)
+	!
+2:	! Second, copy a long word at once
+	add	#-3,r4
+	add	#-3,r5
+3:	mov.l	@r0+,r1
+	cmp/hs	r5,r0
+	bf/s	3b
+	 mov.l	r1,@(r0,r4)
+	add	#3,r5
+	!
+	! Third, copy a byte at once, if necessary
+	cmp/eq	r5,r0
+	bt/s	9b
+	 add	#4,r4
+	bra	8b
+	 add	#-1,r4
+
+case3:
+	!
+	!	GHIJ KLMN OPQR -->  ...G HIJK LMNO PQR.
+	!
+	! First, align to long word boundary
+	mov	r0,r3
+	and	r2,r3
+	tst	r3,r3
+	bt/s	2f
+	 add	#-1,r4
+	mov	#4,r2
+	sub	r3,r2
+1:	dt	r2
+	mov.b	@r0+,r1
+	bf/s	1b
+	 mov.b	r1,@(r0,r4)
+	!
+2:	! Second, read a long word and write a long word at once
+	add	#-2,r4
+	mov.l	@(r0,r4),r1
+	add	#-7,r5
+	add	#-4,r4
+	!
+#ifdef __LITTLE_ENDIAN__
+	shll8	r1
+3:	mov	r1,r3		! JIHG
+	shlr8	r3		! xJIH
+	mov.l	@r0+,r1		! NMLK
+	mov	r1,r2
+	shll16	r2
+	shll8	r2		! Kxxx
+	or	r2,r3		! KJIH
+	cmp/hs	r5,r0
+	bf/s	3b
+	 mov.l	r3,@(r0,r4)
+#else
+	shlr8	r1
+3:	mov	r1,r3		! GHIJ
+	shll8	r3		! HIJx
+	mov.l	@r0+,r1		! KLMN
+	mov	r1,r2
+	shlr16	r2
+	shlr8	r2		! xxxK
+	or	r2,r3		! HIJK
+	cmp/hs	r5,r0
+	bf/s	3b
+	 mov.l	r3,@(r0,r4)
+#endif
+	add	#7,r5
+	!
+	! Third, copy a byte at once, if necessary
+	cmp/eq	r5,r0
+	bt/s	9b
+	 add	#7,r4
+	add	#-3,r0
+	bra	8b
+	 add	#-1,r4
+
+case2:
+	!
+	!	GHIJ KLMN OPQR -->  ..GH IJKL MNOP QR..
+	!
+	! First, align to word boundary
+	tst	#1,r0
+	bt/s	2f
+	 add	#-1,r4
+	mov.b	@r0+,r1
+	mov.b	r1,@(r0,r4)
+	!
+2:	! Second, read a word and write a word at once
+	add	#-1,r4
+	add	#-1,r5
+	!
+3:	mov.w	@r0+,r1
+	cmp/hs	r5,r0
+	bf/s	3b
+	 mov.w	r1,@(r0,r4)
+	add	#1,r5
+	!
+	! Third, copy a byte at once, if necessary
+	cmp/eq	r5,r0
+	bt/s	9b
+	 add	#2,r4
+	mov.b	@r0,r1
+	mov.b	r1,@(r0,r4)
+	bra	9b
+	 add	#1,r0
+
+case1:
+	!
+	!	GHIJ KLMN OPQR -->  .GHI JKLM NOPQ R...
+	!
+	! First, align to long word boundary
+	mov	r0,r3
+	and	r2,r3
+	tst	r3,r3
+	bt/s	2f
+	 add	#-1,r4
+	mov	#4,r2
+	sub	r3,r2
+1:	dt	r2
+	mov.b	@r0+,r1
+	bf/s	1b
+	 mov.b	r1,@(r0,r4)
+	!
+2:	! Second, read a long word and write a long word at once
+	mov.l	@(r0,r4),r1
+	add	#-7,r5
+	add	#-4,r4
+	!
+#ifdef __LITTLE_ENDIAN__
+	shll16	r1
+	shll8	r1
+3:	mov	r1,r3		! JIHG
+	shlr16	r3
+	shlr8	r3		! xxxJ
+	mov.l	@r0+,r1		! NMLK
+	mov	r1,r2
+	shll8	r2		! MLKx
+	or	r2,r3		! MLKJ
+	cmp/hs	r5,r0
+	bf/s	3b
+	 mov.l	r3,@(r0,r4)
+#else
+	shlr16	r1
+	shlr8	r1
+3:	mov	r1,r3		! GHIJ
+	shll16	r3
+	shll8	r3		! Jxxx
+	mov.l	@r0+,r1		! KLMN
+	mov	r1,r2
+	shlr8	r2		! xKLM
+	or	r2,r3		! JKLM
+	cmp/hs	r5,r0
+	bf/s	3b		! while(r0<r5)
+	 mov.l	r3,@(r0,r4)
+#endif
+	add	#7,r5
+	!
+	! Third, copy a byte at once, if necessary
+	cmp/eq	r5,r0
+	bt/s	9b
+	 add	#5,r4
+	add	#-3,r0
+	bra	8b
+	 add	#-1,r4
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/memset.S linux/arch/sh/lib/memset.S
--- v2.3.22/linux/arch/sh/lib/memset.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/memset.S	Mon Oct 18 11:16:13 1999
@@ -1,72 +1,57 @@
-! Taken from newlib-1.8.0
+/* $Id: memset.S,v 1.1 1999/09/18 16:57:09 gniibe Exp $
+ *
+ * "memset" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ */
+
+/*
+ *            void *memset(void *s, int c, size_t n);
+ */
 
-!
-! Fast SH memset
-!
-! by Toshiyasu Morita (tm@netcom.com)
-!
-! Entry: r4: destination pointer
-!        r5: fill value
-!        r6: byte count
-!
-! Exit:  r0-r3: trashed
-!
 #include <linux/linkage.h>
 
 ENTRY(memset)
-	mov	r4,r3	! Save return value
-	
-	mov	r6,r0	! Check explicitly for zero
-	cmp/eq	#0,r0
-	bt	L_exit
-
-	mov	#12,r0	! Check for small number of bytes
+	tst	r6,r6
+	bt/s	5f		! if n=0, do nothing
+	 add	r6,r4
+	mov	#12,r0
 	cmp/gt	r6,r0
-	bt	L_store_byte_loop
-
-	neg	r4,r0	! Align destination
-	add	#4,r0
+	bt/s	4f		! if it's too small, set a byte at once
+	 mov	r4,r0
 	and	#3,r0
-	tst	r0,r0
-	bt	L_dup_bytes
-	.balignw 4,0x0009
-L_align_loop:
-	mov.b	r5,@r4
-	add	#-1,r6
-	add	#1,r4
+	cmp/eq	#0,r0
+	bt/s	2f		! It's aligned
+	 sub	r0,r6
+1:
 	dt	r0
-	bf	L_align_loop
-
-L_dup_bytes:	
-	extu.b	r5,r5	! Duplicate bytes across longword
-	swap.b	r5,r0
-	or	r0,r5
-	swap.w	r5,r0
-	or	r0,r5
-
-	mov	r6,r2	! Calculate number of double longwords
-	shlr2	r2
-	shlr	r2
-
-	.balignw 4,0x0009
-L_store_long_loop:
-	mov.l	r5,@r4	! Store double longs to memory
-	dt	r2
-	mov.l	r5,@(4,r4)
-	add	#8,r4
-	bf	L_store_long_loop
-
+	bf/s	1b
+	 mov.b	r5,@-r4
+2:				! make VVVV
+	swap.b	r5,r0		!   V0
+	or	r0,r5		!   VV
+	swap.w	r5,r0		! VV00
+	or	r0,r5		! VVVV
+	!
+	mov	r6,r0
+	shlr2	r0
+	shlr	r0		! r0 = r6 >> 3
+3:
+	dt	r0
+	mov.l	r5,@-r4		! set 8-byte at once
+	bf/s	3b
+	 mov.l	r5,@-r4
+	!
 	mov	#7,r0
 	and	r0,r6
 	tst	r6,r6
-	bt	L_exit
-	.balignw 4,0x0009
-L_store_byte_loop:
-	mov.b	r5,@r4	! Store bytes to memory
-	add	#1,r4
+	bt	5f
+	! fill bytes
+4:
 	dt	r6
-	bf	L_store_byte_loop
-
-L_exit:
+	bf/s	4b
+	 mov.b	r5,@-r4
+5:
 	rts
-	 mov	r3,r0
+	 mov	r4,r0
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/old-checksum.c linux/arch/sh/lib/old-checksum.c
--- v2.3.22/linux/arch/sh/lib/old-checksum.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/old-checksum.c	Mon Oct 18 11:16:13 1999
@@ -15,5 +15,3 @@
 
 	return sum;
 }
-
-
diff -u --recursive --new-file v2.3.22/linux/arch/sh/lib/wordcopy.S linux/arch/sh/lib/wordcopy.S
--- v2.3.22/linux/arch/sh/lib/wordcopy.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/lib/wordcopy.S	Wed Dec 31 16:00:00 1969
@@ -1,1289 +0,0 @@
-#include <linux/linkage.h>
-ENTRY(_wordcopy_fwd_aligned)
-	mov.l	r14,@-r15
-	add	#-20,r15
-	mov	r15,r14
-	mov.l	r4,@r14
-	mov.l	r5,@(4,r14)
-	mov.l	r6,@(8,r14)
-	mov.l	@(8,r14),r2
-	mov	#7,r1
-	and	r2,r1
-	mov	#0,r2
-	mov	#7,r3
-	sub	r2,r1
-	cmp/hi	r3,r1
-	bf	.L29
-	bra	.L2
-	nop
-.L29:
-	mova	.L22,r0
-	add	r1,r1
-	mov.w	@(r0,r1),r1
-	add	r0,r1
-	jmp  @r1
-	nop
-	.align 2
-	.align 2
-.L22:
-	.word	.L15-.L22
-	.word	.L18-.L22
-	.word	.L3-.L22
-	.word	.L5-.L22
-	.word	.L7-.L22
-	.word	.L9-.L22
-	.word	.L11-.L22
-	.word	.L13-.L22
-	.align 2
-.L3:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-24,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-28,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#6,r2
-	mov.l	r2,@(8,r14)
-	bra	.L4
-	nop
-	.align 2
-.L5:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-20,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-24,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#5,r2
-	mov.l	r2,@(8,r14)
-	bra	.L6
-	nop
-	.align 2
-.L7:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-20,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#4,r2
-	mov.l	r2,@(8,r14)
-	bra	.L8
-	nop
-	.align 2
-.L9:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#3,r2
-	mov.l	r2,@(8,r14)
-	bra	.L10
-	nop
-	.align 2
-.L11:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#2,r2
-	mov.l	r2,@(8,r14)
-	bra	.L12
-	nop
-	.align 2
-.L13:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L14
-	nop
-	.align 2
-.L15:
-	bra	.L16
-	nop
-	bra	.L1
-	nop
-	.align 2
-.L16:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@r14
-	bra	.L17
-	nop
-	.align 2
-.L18:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#4,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L19
-	nop
-	bra	.L20
-	nop
-	.align 2
-.L19:
-	bra	.L21
-	nop
-	.align 2
-.L23:
-.L2:
-	nop
-.L24:
-.L21:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L17:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-.L14:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L12:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-.L10:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L8:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#20,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#20,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-.L6:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#24,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#24,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L4:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#28,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#28,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#32,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#32,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@(8,r14)
-.L26:
-	mov.l	@(8,r14),r1
-	tst	r1,r1
-	bf	.L27
-	bra	.L25
-	nop
-	.align 2
-.L27:
-	bra	.L21
-	nop
-	.align 2
-.L25:
-	nop
-.L20:
-	mov.l	@r14,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L1:
-	add	#20,r14
-	mov	r14,r15
-	mov.l	@r15+,r14
-	rts	
-	nop
-.Lfe1:
-	.size	 __wordcopy_fwd_aligned,.Lfe1-__wordcopy_fwd_aligned
-	.global	___lshrsi3
-	.global	___ashlsi3
-	.align 2
-	.global	__wordcopy_fwd_dest_aligned
-	.type	 __wordcopy_fwd_dest_aligned,@function
-__wordcopy_fwd_dest_aligned:
-	mov.l	r8,@-r15
-	mov.l	r9,@-r15
-	mov.l	r14,@-r15
-	sts.l	pr,@-r15
-	add	#-40,r15
-	mov	r15,r14
-	mov.l	r4,@r14
-	mov.l	r5,@(4,r14)
-	mov.l	r6,@(8,r14)
-	mov.l	@(4,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	mov	r2,r1
-	mov	r1,r2
-	shll2	r2
-	add	r2,r2
-	mov.l	r2,@(28,r14)
-	mov.l	@(28,r14),r2
-	neg	r2,r1
-	add	#32,r1
-	mov.l	r1,@(32,r14)
-	mov.l	@(4,r14),r1
-	mov	#-4,r2
-	and	r2,r1
-	mov.l	r1,@(4,r14)
-	mov.l	@(8,r14),r2
-	mov	#3,r1
-	and	r2,r1
-	mov	#0,r2
-	mov	#3,r3
-	sub	r2,r1
-	cmp/hi	r3,r1
-	bf	.L53
-	bra	.L31
-	nop
-.L53:
-	mova	.L43,r0
-	add	r1,r1
-	mov.w	@(r0,r1),r1
-	add	r0,r1
-	jmp  @r1
-	nop
-	.align 2
-	.align 2
-.L43:
-	.word	.L36-.L43
-	.word	.L39-.L43
-	.word	.L32-.L43
-	.word	.L34-.L43
-	.align 2
-.L32:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#2,r2
-	mov.l	r2,@(8,r14)
-	bra	.L33
-	nop
-	.align 2
-.L34:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L35
-	nop
-	.align 2
-.L36:
-	bra	.L37
-	nop
-	bra	.L30
-	nop
-	.align 2
-.L37:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(24,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#4,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@r14
-	bra	.L38
-	nop
-	.align 2
-.L39:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(24,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#8,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L40
-	nop
-	bra	.L41
-	nop
-	.align 2
-.L40:
-	bra	.L42
-	nop
-	.align 2
-.L44:
-.L31:
-	nop
-.L45:
-.L42:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r8
-	mov.l	.L49,r1
-	mov.l	@(20,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L50,r1
-	mov.l	@(24,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L38:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#4,r8
-	mov.l	.L49,r1
-	mov.l	@(24,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L50,r1
-	mov.l	@(12,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L35:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#8,r8
-	mov.l	.L49,r1
-	mov.l	@(12,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L50,r1
-	mov.l	@(16,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L33:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(24,r14)
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#12,r8
-	mov.l	.L49,r1
-	mov.l	@(16,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L50,r1
-	mov.l	@(20,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#16,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#16,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@(8,r14)
-.L47:
-	mov.l	@(8,r14),r1
-	tst	r1,r1
-	bf	.L48
-	bra	.L46
-	nop
-	.align 2
-.L48:
-	bra	.L42
-	nop
-	.align 2
-.L46:
-	nop
-.L41:
-	mov.l	@r14,r8
-	mov.l	.L49,r1
-	mov.l	@(20,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L50,r1
-	mov.l	@(24,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L30:
-	add	#40,r14
-	mov	r14,r15
-	lds.l	@r15+,pr
-	mov.l	@r15+,r14
-	mov.l	@r15+,r9
-	mov.l	@r15+,r8
-	rts	
-	nop
-.L51:
-	.align 2
-.L49:
-	.long	___lshrsi3
-.L50:
-	.long	___ashlsi3
-.Lfe2:
-	.size	 __wordcopy_fwd_dest_aligned,.Lfe2-__wordcopy_fwd_dest_aligned
-	.align 2
-	.global	__wordcopy_bwd_aligned
-	.type	 __wordcopy_bwd_aligned,@function
-__wordcopy_bwd_aligned:
-	mov.l	r14,@-r15
-	add	#-20,r15
-	mov	r15,r14
-	mov.l	r4,@r14
-	mov.l	r5,@(4,r14)
-	mov.l	r6,@(8,r14)
-	mov.l	@(8,r14),r2
-	mov	#7,r1
-	and	r2,r1
-	mov	#0,r2
-	mov	#7,r3
-	sub	r2,r1
-	cmp/hi	r3,r1
-	bf	.L82
-	bra	.L55
-	nop
-.L82:
-	mova	.L75,r0
-	add	r1,r1
-	mov.w	@(r0,r1),r1
-	add	r0,r1
-	jmp  @r1
-	nop
-	.align 2
-	.align 2
-.L75:
-	.word	.L68-.L75
-	.word	.L71-.L75
-	.word	.L56-.L75
-	.word	.L58-.L75
-	.word	.L60-.L75
-	.word	.L62-.L75
-	.word	.L64-.L75
-	.word	.L66-.L75
-	.align 2
-.L56:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#6,r2
-	mov.l	r2,@(8,r14)
-	bra	.L57
-	nop
-	.align 2
-.L58:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#5,r2
-	mov.l	r2,@(8,r14)
-	bra	.L59
-	nop
-	.align 2
-.L60:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#4,r2
-	mov.l	r2,@(8,r14)
-	bra	.L61
-	nop
-	.align 2
-.L62:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-20,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#3,r2
-	mov.l	r2,@(8,r14)
-	bra	.L63
-	nop
-	.align 2
-.L64:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-24,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-20,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#20,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#2,r2
-	mov.l	r2,@(8,r14)
-	bra	.L65
-	nop
-	.align 2
-.L66:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-28,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-24,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#24,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L67
-	nop
-	.align 2
-.L68:
-	bra	.L69
-	nop
-	bra	.L54
-	nop
-	.align 2
-.L69:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-32,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-28,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#28,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	bra	.L70
-	nop
-	.align 2
-.L71:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-36,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-32,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#32,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L72
-	nop
-	bra	.L73
-	nop
-	.align 2
-.L72:
-	bra	.L74
-	nop
-	.align 2
-.L76:
-.L55:
-	nop
-.L77:
-.L74:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#28,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#28,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L70:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#24,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#24,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-.L67:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#20,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#20,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L65:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-.L63:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L61:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-.L59:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L57:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r1
-	mov.l	@(12,r14),r2
-	mov.l	r2,@r1
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-32,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-32,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@(8,r14)
-.L79:
-	mov.l	@(8,r14),r1
-	tst	r1,r1
-	bf	.L80
-	bra	.L78
-	nop
-	.align 2
-.L80:
-	bra	.L74
-	nop
-	.align 2
-.L78:
-	nop
-.L73:
-	mov.l	@r14,r2
-	mov	r2,r1
-	add	#28,r1
-	mov.l	@(16,r14),r2
-	mov.l	r2,@r1
-.L54:
-	add	#20,r14
-	mov	r14,r15
-	mov.l	@r15+,r14
-	rts	
-	nop
-.Lfe3:
-	.size	 __wordcopy_bwd_aligned,.Lfe3-__wordcopy_bwd_aligned
-	.align 2
-	.global	__wordcopy_bwd_dest_aligned
-	.type	 __wordcopy_bwd_dest_aligned,@function
-__wordcopy_bwd_dest_aligned:
-	mov.l	r8,@-r15
-	mov.l	r9,@-r15
-	mov.l	r14,@-r15
-	sts.l	pr,@-r15
-	add	#-40,r15
-	mov	r15,r14
-	mov.l	r4,@r14
-	mov.l	r5,@(4,r14)
-	mov.l	r6,@(8,r14)
-	mov.l	@(4,r14),r1
-	mov	#3,r2
-	and	r1,r2
-	mov	r2,r1
-	mov	r1,r2
-	shll2	r2
-	add	r2,r2
-	mov.l	r2,@(28,r14)
-	mov.l	@(28,r14),r2
-	neg	r2,r1
-	add	#32,r1
-	mov.l	r1,@(32,r14)
-	mov.l	@(4,r14),r1
-	mov	#-4,r2
-	and	r2,r1
-	mov.l	r1,@(4,r14)
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#4,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@(8,r14),r2
-	mov	#3,r1
-	and	r2,r1
-	mov	#0,r2
-	mov	#3,r3
-	sub	r2,r1
-	cmp/hi	r3,r1
-	bf	.L106
-	bra	.L84
-	nop
-.L106:
-	mova	.L96,r0
-	add	r1,r1
-	mov.w	@(r0,r1),r1
-	add	r0,r1
-	jmp  @r1
-	nop
-	.align 2
-	.align 2
-.L96:
-	.word	.L89-.L96
-	.word	.L92-.L96
-	.word	.L85-.L96
-	.word	.L87-.L96
-	.align 2
-.L85:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#2,r2
-	mov.l	r2,@(8,r14)
-	bra	.L86
-	nop
-	.align 2
-.L87:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-8,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(24,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L88
-	nop
-	.align 2
-.L89:
-	bra	.L90
-	nop
-	bra	.L83
-	nop
-	.align 2
-.L90:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-20,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-12,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(24,r14)
-	bra	.L91
-	nop
-	.align 2
-.L92:
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-24,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@r14
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#20,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#16,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-1,r2
-	mov.l	r2,@(8,r14)
-	bra	.L93
-	nop
-	bra	.L94
-	nop
-	.align 2
-.L93:
-	bra	.L95
-	nop
-	.align 2
-.L97:
-.L84:
-	nop
-.L98:
-.L95:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#12,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(24,r14)
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#12,r8
-	mov.l	.L102,r1
-	mov.l	@(12,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L103,r1
-	mov.l	@(16,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L91:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#8,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(20,r14)
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#8,r8
-	mov.l	.L102,r1
-	mov.l	@(24,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L103,r1
-	mov.l	@(12,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L88:
-	mov.l	@(4,r14),r2
-	mov	r2,r1
-	add	#4,r1
-	mov.l	@r1,r2
-	mov.l	r2,@(16,r14)
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#4,r8
-	mov.l	.L102,r1
-	mov.l	@(20,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L103,r1
-	mov.l	@(24,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L86:
-	mov.l	@(4,r14),r1
-	mov.l	@r1,r2
-	mov.l	r2,@(12,r14)
-	mov.l	@r14,r8
-	mov.l	.L102,r1
-	mov.l	@(16,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L103,r1
-	mov.l	@(20,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-	mov.l	@(4,r14),r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@(4,r14)
-	mov.l	@r14,r1
-	mov	r1,r2
-	add	#-16,r2
-	mov.l	r2,@r14
-	mov.l	@(8,r14),r1
-	mov	r1,r2
-	add	#-4,r2
-	mov.l	r2,@(8,r14)
-.L100:
-	mov.l	@(8,r14),r1
-	tst	r1,r1
-	bf	.L101
-	bra	.L99
-	nop
-	.align 2
-.L101:
-	bra	.L95
-	nop
-	.align 2
-.L99:
-	nop
-.L94:
-	mov.l	@r14,r1
-	mov	r1,r8
-	add	#12,r8
-	mov.l	.L102,r1
-	mov.l	@(12,r14),r4
-	mov.l	@(28,r14),r5
-	jsr	@r1
-	nop
-	mov	r0,r9
-	mov.l	.L103,r1
-	mov.l	@(16,r14),r4
-	mov.l	@(32,r14),r5
-	jsr	@r1
-	nop
-	mov.l	r0,@(36,r14)
-	mov.l	@(36,r14),r1
-	or	r9,r1
-	mov.l	r1,@r8
-.L83:
-	add	#40,r14
-	mov	r14,r15
-	lds.l	@r15+,pr
-	mov.l	@r15+,r14
-	mov.l	@r15+,r9
-	mov.l	@r15+,r8
-	rts	
-	nop
-.L104:
-	.align 2
-.L102:
-	.long	___lshrsi3
-.L103:
-	.long	___ashlsi3
-.Lfe4:
diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/Makefile linux/arch/sh/mm/Makefile
--- v2.3.22/linux/arch/sh/mm/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/mm/Makefile	Mon Oct 18 11:16:13 1999
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o ioremap.o extable.o
+O_OBJS	 := init.o fault.o ioremap.o extable.o cache.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
--- v2.3.22/linux/arch/sh/mm/cache.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/mm/cache.c	Mon Oct 18 11:16:13 1999
@@ -0,0 +1,366 @@
+/* $Id: cache.c,v 1.7 1999/09/23 11:43:07 gniibe Exp $
+ *
+ *  linux/arch/sh/mm/cache.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#if defined(__sh3__)
+#define CCR		0xffffffec	/* Address of Cache Control Register */
+#define CCR_CACHE_VAL	0x00000005	/* 8k-byte cache, P1-wb, enable */
+#define CCR_CACHE_INIT	0x0000000d	/* 8k-byte cache, CF, P1-wb, enable */
+#define CCR_CACHE_ENABLE	 1
+
+#define CACHE_IC_ADDRESS_ARRAY 0xf0000000 /* SH-3 has unified cache system */
+#define CACHE_OC_ADDRESS_ARRAY 0xf0000000
+#define CACHE_VALID	  1
+#define CACHE_UPDATED	  2
+
+/* 7709A/7729 has 16K cache (256-entry), while 7702 has only 2K(direct)
+   7702 is not supported (yet) */
+struct _cache_system_info {
+	int way_shift;
+	int entry_mask;
+	int num_entries;
+};
+
+static struct _cache_system_info cache_system_info;
+
+#define CACHE_OC_WAY_SHIFT	(cache_system_info.way_shift)
+#define CACHE_IC_WAY_SHIFT	(cache_system_info.way_shift)
+#define CACHE_OC_ENTRY_SHIFT    4
+#define CACHE_OC_ENTRY_MASK	(cache_system_info.entry_mask)
+#define CACHE_IC_ENTRY_MASK	(cache_system_info.entry_mask)
+#define CACHE_OC_NUM_ENTRIES	(cache_system_info.num_entries)
+#define CACHE_OC_NUM_WAYS	4
+#define CACHE_IC_NUM_WAYS	4
+#elif defined(__SH4__)
+#define CCR		 0xff00001c	/* Address of Cache Control Register */
+#define CCR_CACHE_VAL	 0x00000105	/* 8k+16k-byte cache,P1-wb,enable */
+#define CCR_CACHE_INIT	 0x0000090d	/* 8k+16k-byte cache,CF,P1-wb,enable */
+#define CCR_CACHE_ENABLE 0x00000101
+
+#define CACHE_IC_ADDRESS_ARRAY 0xf0000000
+#define CACHE_OC_ADDRESS_ARRAY 0xf4000000
+#define CACHE_VALID	  1
+#define CACHE_UPDATED	  2
+
+#define CACHE_OC_WAY_SHIFT       13
+#define CACHE_IC_WAY_SHIFT       13
+#define CACHE_OC_ENTRY_SHIFT      5
+#define CACHE_OC_ENTRY_MASK  0x3fe0
+#define CACHE_IC_ENTRY_MASK  0x1fe0
+#define CACHE_OC_NUM_ENTRIES	512
+#define CACHE_OC_NUM_WAYS	  1
+#define CACHE_IC_NUM_WAYS	  1
+#endif
+
+#define jump_to_p2(__dummy) \
+	asm volatile("mova	1f,%0\n\t" \
+		     "add	%1,%0\n\t" \
+		     "jmp	@r0		! Jump to P2 area\n\t" \
+		     " nop\n\t" \
+		     ".balign 4\n" \
+		     "1:" \
+		     : "=&z" (__dummy) \
+		     : "r" (0x20000000))
+
+#define back_to_p1(__dummy) \
+	asm volatile("nop;nop;nop;nop;nop;nop\n\t" \
+		     "mova	9f,%0\n\t" \
+		     "sub	%1,%0\n\t" \
+		     "jmp	@r0		! Back to P1 area\n\t" \
+		     " nop\n\t" \
+		     ".balign 4\n" \
+		     "9:" \
+		     : "=&z" (__dummy) \
+		     : "r" (0x20000000), "0" (__dummy))
+
+/* Write back caches to memory (if needed) and invalidates the caches */
+void cache_flush_area(unsigned long start, unsigned long end)
+{
+	unsigned long flags, __dummy;
+	unsigned long addr, data, v, p;
+
+	start &= ~(L1_CACHE_BYTES-1);
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	for (v = start; v < end; v+=L1_CACHE_BYTES) {
+		p = __pa(v);
+		addr = CACHE_IC_ADDRESS_ARRAY |
+			(v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+		data = (v&0xfffffc00); /* U=0, V=0 */
+		ctrl_outl(data,addr);
+#if CACHE_IC_ADDRESS_ARRAY != CACHE_OC_ADDRESS_ARRAY
+		asm volatile("ocbp	%0"
+			     : /* no output */
+			     : "m" (__m(v)));
+#endif
+	}
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+/* Purge (just invalidate, no write back) the caches */
+/* This is expected to work well.. but..
+
+   On SH7708S, the write-back cache is written back on "purge".
+   (it's not expected, though).
+
+   It seems that we have no way to just purge (with no write back action)
+   the cache line. */
+void cache_purge_area(unsigned long start, unsigned long end)
+{
+	unsigned long flags, __dummy;
+	unsigned long addr, data, v, p, j;
+
+	start &= ~(L1_CACHE_BYTES-1);
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	for (v = start; v < end; v+=L1_CACHE_BYTES) {
+		p = __pa(v);
+		for (j=0; j<CACHE_IC_NUM_WAYS; j++) {
+			addr = CACHE_IC_ADDRESS_ARRAY|(j<<CACHE_IC_WAY_SHIFT)|
+				(v&CACHE_IC_ENTRY_MASK);
+			data = ctrl_inl(addr);
+			if ((data & 0xfffffc00) == (p&0xfffffc00)
+			    && (data & CACHE_VALID)) {
+				data &= ~CACHE_VALID;
+				ctrl_outl(data,addr);
+				break;
+			}
+		}
+#if CACHE_IC_ADDRESS_ARRAY != CACHE_OC_ADDRESS_ARRAY
+		asm volatile("ocbi	%0"
+			     : /* no output */
+			     : "m" (__m(v)));
+#endif
+	}
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+/* write back the dirty cache, but not invalidate the cache */
+void cache_wback_area(unsigned long start, unsigned long end)
+{
+	unsigned long flags, __dummy;
+	unsigned long v;
+
+	start &= ~(L1_CACHE_BYTES-1);
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	for (v = start; v < end; v+=L1_CACHE_BYTES) {
+#if CACHE_IC_ADDRESS_ARRAY == CACHE_OC_ADDRESS_ARRAY
+		unsigned long addr, data, j;
+		unsigned long p = __pa(v);
+
+		for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
+			addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
+				(v&CACHE_OC_ENTRY_MASK);
+			data = ctrl_inl(addr);
+			if ((data & 0xfffffc00) == (p&0xfffffc00)
+			    && (data & CACHE_VALID)
+			    && (data & CACHE_UPDATED)) {
+				data &= ~CACHE_UPDATED;
+				ctrl_outl(data,addr);
+				break;
+			}
+		}
+#else
+		asm volatile("ocbwb	%0"
+			     : /* no output */
+			     : "m" (__m(v)));
+#endif
+	}
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+/*
+ * Write back the cache.
+ *
+ * For SH-4, flush (write back) Operand Cache, as Instruction Cache
+ * doesn't have "updated" data.
+ */
+static void cache_wback_all(void)
+{
+	unsigned long flags, __dummy;
+	unsigned long addr, data, i, j;
+
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
+		for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
+			addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
+				(i<<CACHE_OC_ENTRY_SHIFT);
+			data = ctrl_inl(addr);
+			if (data & CACHE_VALID) {
+				data &= ~(CACHE_VALID|CACHE_UPDATED);
+				ctrl_outl(data,addr);
+			}
+		}
+	}
+
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+static void
+detect_cpu_and_cache_system(void)
+{
+#if defined(__sh3__)
+	unsigned long __dummy, addr0, addr1, data0, data1, data2, data3;
+
+	jump_to_p2(__dummy);
+	/* Check if the entry shadows or not.
+	 * When shadowed, it's 128-entry system.
+	 * Otherwise, it's 256-entry system.
+	 */
+	addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
+	addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
+	data0  = ctrl_inl(addr0);
+	data0  ^= 0x00000001;
+	ctrl_outl(data0,addr0);
+	data1 = ctrl_inl(addr1);
+	data2 = data1 ^ 0x00000001;
+	ctrl_outl(data2,addr1);
+	data3 = ctrl_inl(addr0);
+
+	/* Invaliate them, in case the cache has been enabled already. */
+	ctrl_outl(data0&~0x00000001,addr0);
+	ctrl_outl(data2&~0x00000001,addr1);
+	back_to_p1(__dummy);
+
+	if (data0 == data1 && data2 == data3) {	/* Shadow */
+		cache_system_info.way_shift = 11;
+		cache_system_info.entry_mask = 0x7f0;
+		cache_system_info.num_entries = 128;
+		cpu_data->type = CPU_SH7708;
+	} else {				/* 7709A or 7729  */
+		cache_system_info.way_shift = 12;
+		cache_system_info.entry_mask = 0xff0;
+		cache_system_info.num_entries = 256;
+		cpu_data->type = CPU_SH7729;
+	}
+#elif defined(__SH4__)
+	cpu_data->type = CPU_SH7750;
+#endif
+}
+
+void __init cache_init(void)
+{
+	unsigned long __dummy, ccr;
+
+	detect_cpu_and_cache_system();
+
+	ccr = ctrl_inl(CCR);
+	if (ccr == CCR_CACHE_VAL)
+		return;
+	if (ccr & CCR_CACHE_ENABLE)
+		/* Should check RA here. If RA was 1,
+		   we only need to flush the half of the caches. */
+		cache_wback_all();
+
+	jump_to_p2(__dummy);
+	ctrl_outl(CCR_CACHE_INIT, CCR);
+	back_to_p1(__dummy);
+}
+
+#if defined(__SH4__)
+/* Write back data caches, and invalidates instructiin caches */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+	unsigned long flags, __dummy;
+	unsigned long addr, data, v;
+
+	start &= ~(L1_CACHE_BYTES-1);
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	for (v = start; v < end; v+=L1_CACHE_BYTES) {
+		/* Write back O Cache */
+		asm volatile("ocbwb	%0"
+			     : /* no output */
+			     : "m" (__m(v)));
+		/* Invalidate I Cache */
+		addr = CACHE_IC_ADDRESS_ARRAY |
+			(v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+		data = (v&0xfffffc00); /* Valid=0 */
+		ctrl_outl(data,addr);
+	}
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+void flush_cache_all(void)
+{
+	unsigned long flags,__dummy;
+
+	/* Write back Operand Cache */
+	cache_wback_all ();
+
+	/* Then, invalidate Instruction Cache and Operand Cache */
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+	ctrl_outl(CCR_CACHE_INIT, CCR);
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+	/* Is there any good way? */
+	/* XXX: possibly call flush_cache_range for each vm area */
+	flush_cache_all();
+}
+
+void flush_cache_range(struct mm_struct *mm, unsigned long start,
+		       unsigned long end)
+{
+	unsigned long flags, __dummy;
+	unsigned long addr, data, v;
+
+	start &= ~(L1_CACHE_BYTES-1);
+	save_and_cli(flags);
+	jump_to_p2(__dummy);
+
+	for (v = start; v < end; v+=L1_CACHE_BYTES) {
+		addr = CACHE_IC_ADDRESS_ARRAY |
+			(v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */;
+		data = (v&0xfffffc00); /* Update=0, Valid=0 */
+		ctrl_outl(data,addr);
+		addr = CACHE_OC_ADDRESS_ARRAY |
+			(v&CACHE_OC_ENTRY_MASK) | 0x8 /* A-bit */;
+		ctrl_outl(data,addr);
+	}
+	back_to_p1(__dummy);
+	restore_flags(flags);
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
+{
+	flush_cache_range(vma->vm_mm, addr, addr+PAGE_SIZE);
+}
+
+void flush_page_to_ram(unsigned long page)
+{				/* Page is in physical address */
+	/* XXX: for the time being... */
+	flush_cache_all();
+}
+#endif
diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/extable.c linux/arch/sh/mm/extable.c
--- v2.3.22/linux/arch/sh/mm/extable.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/mm/extable.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: extable.c,v 1.1 1999/09/18 16:57:37 gniibe Exp $
+ *
  * linux/arch/sh/mm/extable.c
  *  Taken from:
  *   linux/arch/i386/mm/extable.c
diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.3.22/linux/arch/sh/mm/fault.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/mm/fault.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: fault.c,v 1.3 1999/09/21 23:09:53 gniibe Exp $
+ *
  *  linux/arch/sh/mm/fault.c
  *  Copyright (C) 1999  Niibe Yutaka
  *
@@ -20,6 +21,7 @@
 #include <linux/interrupt.h>
 
 #include <asm/system.h>
+#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/hardirq.h>
@@ -225,20 +227,23 @@
 
 	asid = get_asid();
 
-	save_and_cli(flags);
 	address &= PAGE_MASK;
+#if 0/*defined(__SH4__)*//* SH-4 has separate I/D caches: XXX really needed? */
+	if ((vma->vm_flags & VM_EXEC) != 0)
+/*	 &&
+	    ((pte_val(pte) & (_PAGE_PRESENT | _PAGE_DIRTY)) ==
+	    (_PAGE_PRESENT | _PAGE_DIRTY))) */
+		flush_icache_range(address,address+PAGE_SIZE);
+#endif
+	save_and_cli(flags);
 	/* Set PTEH register */
-	asm volatile ("mov.l	%0,%1"
-		      : /* no output */
-		      : "r" (address | asid), "m" (__m(MMU_PTEH)));
+	ctrl_outl((address|asid), MMU_PTEH);
 
 	pteval = pte_val(pte);
 	pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
 	pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */
 	/* Set PTEL register */
-	asm volatile ("mov.l	%0,%1"
-		      : /* no output */
-		      : "r" (pteval), "m" (__m(MMU_PTEL)));
+	ctrl_outl(pteval, MMU_PTEL);
 
 	/* Load the TLB */
 	asm volatile ("ldtlb" : /* no output */ : /* no input */
@@ -250,11 +255,27 @@
 {
 	unsigned long addr, data;
 
+#if defined(__sh3__)
 	addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000) | MMU_PAGE_ASSOC_BIT;
 	data = page | asid; /* VALID bit is off */
-	__asm__ __volatile__ ("mov.l	%0,%1"
-			      : /* no output */
-			      : "r" (data), "m" (__m(addr)));
+	ctrl_outl(data, addr);
+#elif defined(__SH4__)
+	int i;
+
+	addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
+	data = page | asid; /* VALID bit is off */
+	ctrl_outl(data, addr);
+
+	for (i=0; i<4; i++) {
+		addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8);
+		data = ctrl_inl(addr);
+		data &= ~0x30;
+		if (data == (page | asid)) {
+			ctrl_outl(data, addr);
+			break;
+		}
+	}
+#endif
 }
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
@@ -262,9 +283,13 @@
 	unsigned long asid;
 
 	if (vma->vm_mm->context != NO_CONTEXT) {
+		unsigned long flags;
+
 		page &= PAGE_MASK;
 		asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
+		save_and_cli(flags);
 		__flush_tlb_page (asid, page);
+		restore_flags(flags);
 	}
 }
 
@@ -277,7 +302,7 @@
 
 		save_and_cli(flags);
 		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-		if (size > (MMU_NTLB_ENTRIES/4)) { /* So many TLB to flush */
+		if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
 			get_new_mmu_context(mm);
 			if (mm == current->mm)
 				set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
@@ -314,13 +339,11 @@
 
 void flush_tlb_all(void)
 {
-	unsigned long flags, __dummy;
+	unsigned long flags, status;
 
 	save_and_cli(flags);
-	asm volatile("mov.l	%1,%0\n\t"
-		     "or	#4,%0\n\t" /* Set TF-bit to flush */
-		     "mov.l	%0,%1"
-		     : "=&z" (__dummy)
-		     : "m" (__m(MMUCR)));
+	status = ctrl_inl(MMUCR);
+	status |= 0x04;		/* Set TF-bit to flush */
+	ctrl_outl(status,MMUCR);
 	restore_flags(flags);
 }
diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c
--- v2.3.22/linux/arch/sh/mm/init.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/mm/init.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: init.c,v 1.3 1999/10/11 10:41:30 gniibe Exp $
+ *
  *  linux/arch/sh/mm/init.c
  *
  *  Copyright (C) 1999  Niibe Yutaka
@@ -29,6 +30,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
+#include <asm/io.h>
 
 /*
  * Cache of MMU context last used.
@@ -127,7 +129,7 @@
  */
 pte_t * __bad_pagetable(void)
 {
-	extern char empty_bad_page_table[PAGE_SIZE];
+	extern unsigned long empty_bad_page_table[PAGE_SIZE];
 	unsigned long page = (unsigned long)empty_bad_page_table;
 
 	clear_page(page);
@@ -202,16 +204,17 @@
 	pgd_val(pg_dir[0]) = 0;
 
 	/* Enable MMU */
-	__asm__ __volatile__ ("mov.l	%0,%1"
-			      : /* no output */
-			      : "r" (MMU_CONTROL_INIT), "m" (__m(MMUCR)));
+	ctrl_outl(MMU_CONTROL_INIT, MMUCR);
+
+	mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
+	set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
 
 	return free_area_init(start_mem, end_mem);
 }
 
 unsigned long empty_bad_page[1024];
 unsigned long empty_bad_page_table[1024];
-unsigned long empty_zero_page[1024];
+extern unsigned long empty_zero_page[1024];
 
 void __init mem_init(unsigned long start_mem, unsigned long end_mem)
 {
diff -u --recursive --new-file v2.3.22/linux/arch/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c
--- v2.3.22/linux/arch/sh/mm/ioremap.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/mm/ioremap.c	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: ioremap.c,v 1.1 1999/09/18 16:57:48 gniibe Exp $
+ *
  * arch/sh/mm/ioremap.c
  *
  * Re-map IO memory to kernel address space so that we can access it.
diff -u --recursive --new-file v2.3.22/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S
--- v2.3.22/linux/arch/sh/vmlinux.lds.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/vmlinux.lds.S	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,5 @@
-/* ld script to make SuperH Linux kernel
+/* $Id: vmlinux.lds.S,v 1.3 1999/10/05 12:33:48 gniibe Exp $
+ * ld script to make SuperH Linux kernel
  * Written by Niibe Yutaka
  */
 #include <linux/config.h>
@@ -15,6 +16,7 @@
   __text = .;			/* Text and read-only data */
   _text = .;			/* Text and read-only data */
   .text : {
+	*(.empty_zero_page)
 	*(.text)
 	*(.fixup)
 	*(.gnu.warning)
@@ -65,9 +67,6 @@
 
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  . = ALIGN(4096);
-  .data.disk_image : { *(.data.disk_image) }
 
   . = ALIGN(4);
   ___bss_start = .;		/* BSS */
diff -u --recursive --new-file v2.3.22/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.3.22/linux/arch/sparc/mm/init.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc/mm/init.c	Sat Oct 16 10:50:48 1999
@@ -106,6 +106,7 @@
 	printk("%ld page tables cached\n",pgtable_cache_size);
 	if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
 		printk("%ld page dirs cached\n", pgd_cache_size);
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
diff -u --recursive --new-file v2.3.22/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.22/linux/arch/sparc64/mm/init.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/mm/init.c	Sat Oct 16 10:50:48 1999
@@ -150,6 +150,7 @@
 #ifndef __SMP__
 	printk("%d entries in page dir cache\n",pgd_cache_size);
 #endif	
+	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/Makefile linux/drivers/acorn/Makefile
--- v2.3.22/linux/drivers/acorn/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/acorn/Makefile	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,12 @@
+#
+# Makefile for the Acorn-specific Linux kernel device drivers.
+#
+# 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 (not a .c file).
+
+SUB_DIRS     := block char net scsi
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/README linux/drivers/acorn/README
--- v2.3.22/linux/drivers/acorn/README	Mon Feb 16 15:49:47 1998
+++ linux/drivers/acorn/README	Wed Oct 20 16:29:08 1999
@@ -1,3 +1 @@
 Drivers for the ACORN "podule" ARM specific bus.
-
-
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/block/Makefile linux/drivers/acorn/block/Makefile
--- v2.3.22/linux/drivers/acorn/block/Makefile	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/block/Makefile	Wed Oct 20 16:29:08 1999
@@ -32,17 +32,11 @@
 
 include $(TOPDIR)/Rules.make
 
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+
 fd1772_mod.o: $(FLOPPY)
 	$(LD) -r -o $@ $(FLOPPY)
 
 mfmhd_mod.o: mfmhd.o mfm.o
 	$(LD) -r -o $@ mfmhd.o mfm.o
-
-%.o: %.S
-ifndef $(CONFIG_BINUTILS_NEW)
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s
-	$(CC) $(CFLAGS) -c -o $@ ..tmp.s
-	$(RM) ..tmp.s
-else
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
-endif
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c
--- v2.3.22/linux/drivers/acorn/char/keyb_arc.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/acorn/char/keyb_arc.c	Wed Oct 20 16:29:08 1999
@@ -31,7 +31,7 @@
 #include <asm/ioc.h>
 #include <asm/hardware.h>
 
-#include "../../char/mouse.h"
+#include "../../char/busmouse.h"
 
 extern void kbd_reset_kdown(void);
 
@@ -47,7 +47,7 @@
 static unsigned char kbd_txhead, kbd_txtail;
 #define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3)
 static int kbd_id = -1;
-static struct wait_queue *kbd_waitq;
+static DECLARE_WAIT_QUEUE_HEAD(kbd_waitq);
 #ifdef CONFIG_KBDMOUSE
 static int mousedev;
 #endif
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- v2.3.22/linux/drivers/acorn/net/ether1.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/acorn/net/ether1.c	Wed Oct 20 16:29:08 1999
@@ -255,7 +255,7 @@
 }
 
 static int __init
-ether1_ramtest (struct net_device *dev, unsigned char byte)
+ether1_ramtest(struct net_device *dev, unsigned char byte)
 {
 	unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
 	int i, ret = BUFFER_SIZE;
@@ -309,7 +309,7 @@
 }
 
 static int __init
-ether1_init_2 (struct net_device *dev)
+ether1_init_2(struct net_device *dev)
 {
 	int i;
 	dev->mem_start = 0;
@@ -613,7 +613,7 @@
 }
 
 static int __init
-ether1_probe1 (struct net_device *dev)
+ether1_probe1(struct net_device *dev)
 {
 	static unsigned int version_printed = 0;
 	struct ether1_priv *priv;
@@ -665,7 +665,7 @@
 /* ------------------------------------------------------------------------- */
 
 static void __init
-ether1_addr (struct net_device *dev)
+ether1_addr(struct net_device *dev)
 {
 	int i;
     
@@ -674,7 +674,7 @@
 }
 
 int __init
-ether1_probe (struct net_device *dev)
+ether1_probe(struct net_device *dev)
 {
 #ifndef MODULE
 	struct expansion_card *ec;
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/net/net-probe.c linux/drivers/acorn/net/net-probe.c
--- v2.3.22/linux/drivers/acorn/net/net-probe.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/acorn/net/net-probe.c	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/*
- * Acorn specific net device driver probe routine
- *
- * Copyright (C) 1998 Russell King
- */
-#include <linux/config.h>
-#include <linux/netdevice.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-extern int ether1_probe (struct net_device *dev);
-extern int ether3_probe (struct net_device *dev);
-extern int etherh_probe (struct net_device *dev);
-
-int __init acorn_ethif_probe(struct net_device *dev)
-{
-	if (1
-#ifdef CONFIG_ARM_ETHERH
-        && etherh_probe (dev)
-#endif
-#ifdef CONFIG_ARM_ETHER3
-        && ether3_probe (dev)
-#endif
-#ifdef CONFIG_ARM_ETHER1
-        && ether1_probe (dev)
-#endif
-	&& 1) {
-		return 1;
-	}
-	return 0;
-}
diff -u --recursive --new-file v2.3.22/linux/drivers/acorn/scsi/Makefile linux/drivers/acorn/scsi/Makefile
--- v2.3.22/linux/drivers/acorn/scsi/Makefile	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/Makefile	Wed Oct 20 16:29:08 1999
@@ -108,14 +108,8 @@
 
 include $(TOPDIR)/Rules.make
 
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
+
 acornscsi_mod.o: acornscsi.o acornscsi-io.o
 	$(LD) $(LD_RFLAG) -r -o $@ acornscsi.o acornscsi-io.o
-
-%.o: %.S
-ifndef $(CONFIG_BINUTILS_NEW)
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s
-	$(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s
-	$(RM) ..tmp.$<.s
-else
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
-endif
diff -u --recursive --new-file v2.3.22/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.22/linux/drivers/block/Config.in	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/Config.in	Mon Oct 18 11:26:31 1999
@@ -62,17 +62,15 @@
 	    fi
 	    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
   	       bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
-	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
-	 	     "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
-	       bool '      HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
+	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+		  bool '      HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA
 	       fi
   	       bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366
 	    fi
 	    if [ "$CONFIG_X86" = "y" ]; then
 	       bool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
-	       if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
-		    "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
-		  bool '      PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
+	       if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+		  bool '      PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING
 	       fi
 	    fi
 	    if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
@@ -83,19 +81,20 @@
 	    fi
 	    if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
 	       bool '    PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
-	       if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
-		    "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
-		  bool '      Special UDMA Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_BURST_BIT
-		  bool '      Special Mode Feature (DANGEROUS)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+	       if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+		  bool '      Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT
+		  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+		    bool '      Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+		  fi
+	       fi
+  	       if [ "$CONFIG_X86" = "y" ]; then
+	          bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
 	       fi
-	    fi
-	    if [ "$CONFIG_X86" = "y" ]; then
-	       bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
 	    fi
 	    if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
 	       bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
 	       if [ "$CONFIG_X86" = "y" ]; then
-		  bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
+		  bool '     VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX
 	       fi
 	    fi
          fi
@@ -139,8 +138,7 @@
 	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
 	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
 	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
-	      "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
 	 fi
 	 bool '    QDI QD6580 support' CONFIG_BLK_DEV_QD6580
@@ -225,6 +223,7 @@
      "$CONFIG_BLK_DEV_HPT366" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
      "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
+     "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
diff -u --recursive --new-file v2.3.22/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.22/linux/drivers/block/Makefile	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/Makefile	Mon Oct 18 11:14:22 1999
@@ -230,8 +230,8 @@
 IDE_OBJS += umc8672.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_VIA82C586),y)
-IDE_OBJS += via82c586.o
+ifeq ($(CONFIG_BLK_DEV_VIA82CXXX),y)
+IDE_OBJS += via82cxxx.o
 endif
 
 ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
@@ -379,4 +379,3 @@
 
 ide-probe-mod.o: ide-probe.o ide-geometry.o
 	$(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
-
diff -u --recursive --new-file v2.3.22/linux/drivers/block/aec6210.c linux/drivers/block/aec6210.c
--- v2.3.22/linux/drivers/block/aec6210.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/aec6210.c	Mon Oct 18 11:14:22 1999
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/block/aec6210.c		Version 0.01	Nov 17, 1998
+ * linux/drivers/block/aec6210.c	Version 0.02	Sept. 3, 1999
  *
- * Copyright (C) 1998-99	Andre Hedrick
+ * Copyright (C) 1998-99	Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
  *
  *  pio 0 ::       40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02
  *  pio 1 ::       40: 0a 07 00 00 00 00 00 00 02 07 a6 05 00 02 00 02
@@ -49,6 +50,10 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
 
 unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
 {
diff -u --recursive --new-file v2.3.22/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c
--- v2.3.22/linux/drivers/block/alim15x3.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/alim15x3.c	Mon Oct 18 11:14:22 1999
@@ -1,21 +1,28 @@
 /*
- * linux/drivers/block/alim15x3.c	Version 0.05	Jun. 29, 1999
+ * linux/drivers/block/alim15x3.c	Version 0.06	Sept. 3, 1999
  *
  *  Copyright (C) 1998-99 Michel Aubry, Maintainer
  *  Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer
  *
- *  (U)DMA capable version of ali 1533/1543(C)
+ *  Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ *  May be copied or modified under the terms of the GNU General Public License
  *
- *  Default disable (U)DMA on all devices execpt hard disks.
- *  This measure of overkill is needed to stablize the chipset code.
+ *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
  *
+ *  version: 1.0 beta2 (Sep. 2, 1999)
+ *	e-mail your problems to cjtsai@ali.com.tw
+ *
+ **********************************************************************
+ *  9/7/99 --Parts from the above author are included and need to be
+ *  converted into standard interface, once I finish the thought.
  */
 
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -59,188 +66,7 @@
 	"error DRQ     ",
 	"error DRQ busy"
 };
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	int s_time, a_time, c_time;
-	byte s_clc, a_clc, r_clc;
-	unsigned long flags;
-	int bus_speed = ide_system_bus_speed();
-	int port = hwif->index ? 0x5c : 0x58;
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-	s_time = ide_pio_timings[pio].setup_time;
-	a_time = ide_pio_timings[pio].active_time;
-	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
-		s_clc = 0;
-	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
-		a_clc = 0;
-	c_time = ide_pio_timings[pio].cycle_time;
-
-#if 0
-	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
-		r_clc = 0;
-#endif
-
-	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
-		r_clc = 1;
-	} else {
-		if (r_clc >= 16)
-		r_clc = 0;
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_byte(dev, port, s_clc);
-	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
-	restore_flags(flags);
-
-	/*
-	 * setup   active  rec
-	 * { 70,   165,    365 },   PIO Mode 0
-	 * { 50,   125,    208 },   PIO Mode 1
-	 * { 30,   100,    110 },   PIO Mode 2
-	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
-	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
-	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
-	 */
-
-}
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	byte confreg0 = 0, confreg1 =0, progif = 0;
-	int errors = 0;
-
-	if (pci_read_config_byte(dev, 0x50, &confreg1))
-		goto veryspecialsettingserror;
-	if (!(confreg1 & 0x02))
-		if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02))
-			goto veryspecialsettingserror;
-
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif))
-		goto veryspecialsettingserror;
-	if (!(progif & 0x40)) {
-		/*
-		 * The way to enable them is to set progif
-		 * writable at 0x4Dh register, and set bit 6
-		 * of progif to 1:
-		 */
-		if (pci_read_config_byte(dev, 0x4d, &confreg0))
-			goto veryspecialsettingserror;
-		if (confreg0 & 0x80)
-			if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80))
-				goto veryspecialsettingserror;
-		if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40))
-			goto veryspecialsettingserror;
-		if (confreg0 & 0x80)
-			if (pci_write_config_byte(dev, 0x4d, confreg0))
-				errors++;
-	}
-
-	if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40)))
-		goto veryspecialsettingserror;
-
-	printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n",
-		name, errors ? "with Error(s)" : "Succeeded" );
-	return 0;
-
-veryspecialsettingserror:
-	printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name);
-	return 0;
-}
-
-int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			if (drive->media == ide_cdrom) {
-				ide_hwif_t *hwif	= HWIF(drive);
-				struct pci_dev *dev	= hwif->pci_dev;
-				struct hd_driveid *id	= drive->id;
-				byte cd_dma_fifo	= 0;
-
-				pci_read_config_byte(dev, 0x53, &cd_dma_fifo);
-
-				if (((id->field_valid & 4) || (id->field_valid & 2)) &&
-				    (id->capability & 1) && hwif->autodma) {
-					unsigned long dma_set_bit  = hwif->dma_base + 2;
-#if 0
-					if (cd_dma_fifo & 0x02)
-						pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x02);
-					pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01);
-#else
-					pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x01|0x02);
-#endif
-					if (drive->select.b.unit & 0x01) {
-						outb(inb(dma_set_bit)|0x40, dma_set_bit);
-					} else {
-						outb(inb(dma_set_bit)|0x20, dma_set_bit);
-					}
-				} else {
-					if (cd_dma_fifo & 0x01)
-						pci_write_config_byte(dev, 0x53, cd_dma_fifo & ~0x01);
-					pci_write_config_byte(dev, 0x53, cd_dma_fifo|0x02);
-				}
-			} else if (drive->media != ide_disk) {
-				return ide_dmaproc(ide_dma_off_quietly, drive);
-			}
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev;
-	byte ideic, inmir, iderev;
-	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-				      1, 11, 0, 12, 0, 14, 0, 15 };
-
-	pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev);
-
-	hwif->irq = hwif->channel ? 15 : 14;
-	for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */
-		if (dev->vendor==PCI_VENDOR_ID_AL &&
-		    dev->device==PCI_DEVICE_ID_AL_M1533)
-			break;
-	if (dev) {			
-		pci_read_config_byte(dev, 0x58, &ideic);
-		ideic = ideic & 0x03;
-		if ((hwif->channel && ideic == 0x03) ||
-		    (!hwif->channel && !ideic)) {
-			pci_read_config_byte(dev, 0x44, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		} else
-			if (hwif->channel && !(ideic & 0x01)) {
-				pci_read_config_byte(dev, 0x75, &inmir);
-				inmir = inmir & 0x0f;
-				hwif->irq = irq_routing_table[inmir];
-			}
-	}
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-	bmide_dev = hwif->pci_dev;
-	ali_display_info = &ali_get_info;
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-	hwif->tuneproc = &ali15x3_tune_drive;
-	if ((hwif->dma_base) && (iderev >= 0xC1)) {
-		/* M1543C or newer for DMAing */
-		hwif->dmaproc = &ali15x3_dmaproc;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-	return;
-}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
 static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy)
 {
 	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
@@ -407,3 +233,540 @@
 	return p-buffer; /* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static byte m5229_revision	= 0;
+static byte chip_is_1543c_e	= 0;
+static byte cable_80_pin[2]	= { 0, 0 };
+
+byte ali_proc = 0;
+static struct pci_dev *isa_dev;
+
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	byte s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = ide_system_bus_speed();
+	int port = hwif->index ? 0x5c : 0x58;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+		r_clc = 0;
+	}
+	save_flags(flags);
+	cli();
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	restore_flags(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
+static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
+{
+	if (bits & 0x04)
+		return XFER_MW_DMA_2;
+	if (bits & 0x02)
+		return XFER_MW_DMA_1;
+	return XFER_MW_DMA_0;
+}
+
+static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
+{
+	if (bits & 0x10)
+		return XFER_UDMA_4;
+	if (bits & 0x08)
+		return XFER_UDMA_3;
+	if (bits & 0x04)
+		return XFER_UDMA_2;
+	if (bits & 0x02)
+		return XFER_UDMA_1;
+	return XFER_UDMA_0;
+}
+
+static __inline__ int wait_for_ready(ide_drive_t *drive)
+{
+	int timeout = 20000;	/* (old value: 100) */
+	byte stat;
+
+	while (--timeout) {
+		stat = GET_STAT();
+		/*
+		 * printk("STAT(%2x) ", stat);
+		 */
+		if (!(stat & BUSY_STAT)) {
+			if ((stat & READY_STAT) || (stat & ERR_STAT)) {
+				break;
+			}
+		}
+		/*
+		 * (old value: 100)
+		 */
+		udelay(150);
+	}
+	if ((stat & ERR_STAT) || timeout <= 0)
+		return 1;
+	return 0;
+}
+
+static void ali15x3_do_setfeature(ide_drive_t *drive, byte command)
+{
+	unsigned long flags;
+	byte old_select;
+
+	save_flags(flags);
+	cli();
+		
+	/* save old selected device */
+	old_select = IN_BYTE(IDE_SELECT_REG);
+	/* "SELECT " */
+	OUT_BYTE(drive->select.all, IDE_SELECT_REG);
+	/* "SETXFER " */
+	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+	/* "CMND " */
+	OUT_BYTE(command, IDE_NSECTOR_REG);
+
+	if(wait_for_ready(drive))	/* "wait " */
+		goto out;
+
+	/* "SETFEATURE " */
+	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+	/* "wait " */
+	(void) wait_for_ready(drive);
+
+out:
+	/*
+	 * restore to old "selected device"
+	 */
+	OUT_BYTE(old_select, IDE_SELECT_REG);
+	restore_flags(flags);
+}
+
+static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
+{
+	byte unit = (drive->select.b.unit & 0x01);
+	byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
+	byte tmpbyte;
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;		
+	
+	ali15x3_do_setfeature(drive, dma2_bits_to_command(bits));
+
+	/*
+	 * clear "ultra enable" bit
+	 */
+	pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
+	if (unit) {
+		tmpbyte &= 0x7f;
+	} else {
+		tmpbyte &= 0xf7;
+	}
+	save_flags(flags);
+	cli();
+	pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
+	restore_flags(flags);
+	drive->id->dma_ultra = 0x00;
+
+	/*
+	 * Enable DMA
+	 */
+	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+	printk("ALI15X3: MultiWord DMA enabled\n");
+}
+
+static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base)
+{	
+	byte unit = (drive->select.b.unit & 0x01);
+	byte bits = drive->id->dma_ultra & 0x1f;	
+	byte tmpbyte;
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	unsigned char udma_mode = 0;
+	int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
+
+	if (bits & 0x18) {
+		/*
+		 * 00011000, disk: ultra66
+		 */
+		if (m5229_revision < 0xc2) {
+			/*
+			 * controller: ultra33
+			 */
+			bits = 0x04;
+			/*
+			 * 00000100, use ultra33, mode 2
+			 */
+			drive->id->dma_ultra &= ~0xFF00;
+			drive->id->dma_ultra |= 0x0004;			
+		} else {
+			/*
+			 * controller: ultra66
+			 *
+			 * Try to detect word93 bit13 and
+			 * 80-pin cable (from host view)
+			 */
+			if (!((drive->id->word93 & 0x2000) &&
+			    cable_80_pin[hwif->channel])) {	
+				bits = 0x04;
+				/*
+				 * 00000100, use ultra33, mode 2
+				 */
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x0004;
+			}
+		}
+	}
+
+	/*
+	 * set feature regardless
+	 */
+	ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits));
+	udma_mode &= 0x0f;	/* get UDMA mode */
+
+	/*
+	 * Enable DMA and UltraDMA
+	 */
+	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+	/*
+	 * m5229 ultra
+	 */
+	pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
+	/*
+	 * clear bit0~3 or bit 4~7
+	 */
+	tmpbyte &= (0x0f << ((1-unit) << 2));
+	/*
+	 * enable ultra dma and set timing
+	 */
+	tmpbyte |= ((0x08 | (4-udma_mode)) << (unit << 2));
+	/*
+	 * set to m5229
+	 */
+	save_flags(flags);
+	cli();		
+	pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
+	restore_flags(flags);
+
+	if (udma_mode >= 3) {
+		/*
+		 * ultra 66
+		 */
+		pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte);
+		tmpbyte |= 1;			
+		save_flags(flags);
+		cli();
+		pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte);		
+		restore_flags(flags);
+	}
+
+	printk("ALI15X3: Ultra DMA enabled\n");
+}
+
+static int ali15x3_dma_onoff(ide_drive_t *drive, int enable)
+{
+	if (enable) {
+		ide_hwif_t *hwif = HWIF(drive);
+		unsigned long dma_base = hwif->dma_base;
+		struct hd_driveid *id = drive->id;
+				
+		if ((id->field_valid & 0x0004) && 
+		    (id->dma_ultra & 0x001f)) {
+			/*
+			 * 1543C_E, in ultra mode, WDC "harddisk"
+			 * will cause "CRC" errors (even if no CRC problem),
+			 * so we try to use "DMA" here
+			 */
+			if (m5229_revision <= 0x20) {
+				/*
+				 * Normal MultiWord DMA modes.
+				 */
+				ali15x3_dma2_enable(drive, dma_base);
+			} else if ((m5229_revision < 0xC2) && 
+				   ((drive->media!=ide_disk) ||
+				    (chip_is_1543c_e &&
+				     strstr(id->model, "WDC ")))) {
+				/*
+				 * Normal MultiWord DMA modes.
+				 */
+				ali15x3_dma2_enable(drive, dma_base);
+			} else {
+				/*
+				 * m5229_revision >= 0xC2 for UltraDMA modes.
+				 */
+				ali15x3_udma_enable(drive, dma_base);
+			}
+		} else {
+			/*
+			 * Normal MultiWord DMA modes.
+			 */
+			ali15x3_dma2_enable(drive, dma_base);
+		}
+	}
+
+	drive->using_dma = enable;	/* on, off */
+	return 0;
+}
+
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+		return hwif->dmaproc(ide_dma_off_quietly, drive);
+	/*
+	 * Even if the drive is not _currently_ in a DMA
+	 * mode, we succeed, and we'll enable it manually
+	 * below in alim15x3_dma_onoff
+	 */
+	if ((id != NULL) && (id->capability & 1) && hwif->autodma) {
+		if (id->field_valid & 0x0004) {
+			if (id->dma_ultra & 0x001F)
+				return hwif->dmaproc(ide_dma_on, drive);
+		}
+		if (id->field_valid & 0x0002) {
+			if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007))
+				return hwif->dmaproc(ide_dma_on, drive);
+		}
+	}
+	return hwif->dmaproc(ide_dma_off_quietly, drive);
+}
+
+static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch(func) {
+		case ide_dma_check:
+			return ali15x3_config_drive_for_dma(drive);
+		case ide_dma_on:
+		case ide_dma_off:
+		case ide_dma_off_quietly:
+			return ali15x3_dma_onoff(drive, (func == ide_dma_on));
+		case ide_dma_write:
+			if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+				return 1;	/* try PIO instead of DMA */
+			break;
+		default:
+			break;
+	}
+
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+
+unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *isa;
+	unsigned long fixdma_base = dev->resource[4].start;
+	byte tmpbyte;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+	for (isa = pci_devices; isa; isa=isa->next) {
+		/*
+		 * look for ISA bridge
+		 */
+		if (isa->vendor == PCI_VENDOR_ID_AL &&
+		    isa->device == PCI_DEVICE_ID_AL_M1533) {
+			isa_dev = isa;
+			break;
+		}
+	}
+
+	if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
+		/*
+		 *
+		 */
+	} else {
+		/*
+		 * enable DMA capable bit, and "not" simplex only
+		 */
+		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
+
+		if (inb(fixdma_base+2) & 0x80)
+			printk("%s: simplex device: DMA will fail!!\n", name);
+	}
+
+	/*
+	 * FIXME !!! This detection needs to be in "ata66_ali15x3()"
+	 * below as a standard detection return.
+	 */
+
+	if (m5229_revision >= 0xC2) {
+		unsigned long flags;
+		/*
+		 * 1543C-B?, 1535, 1535D, 1553
+		 * Note 1: not all "motherboard" support this detection
+		 * Note 2: if no udma 66 device, the detection may "error".
+		 *         but in this case, we will not set the device to
+		 *         ultra 66, the detection result is not important
+		 */
+		save_flags(flags);
+		cli();
+
+		/*
+		 * enable "Cable Detection", m5229, 0x4b, bit3
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+		/*
+		 * set south-bridge's enable bit, m1533, 0x79
+		 */
+		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+		if (m5229_revision == 0xC2) {
+			/*
+			 * 1543C-B0 (m1533, 0x79, bit 2)
+			 */
+			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+		} else if (m5229_revision == 0xC3) {
+			/*
+			 * 1553/1535 (m1533, 0x79, bit 1)
+			 */
+			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+		}
+		restore_flags(flags);
+		/*
+		 * Ultra66 cable detection (from Host View)
+		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+		 */
+		pci_read_config_byte(dev, 0x4a, &tmpbyte);
+		/*
+		 * 0x4a, bit0 is 0 => primary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x01))
+			cable_80_pin[0] = 1;
+		/*
+		 * 0x4a, bit1 is 0 => secondary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x02))
+			cable_80_pin[1] = 1;
+	} else {
+		unsigned long flags;
+		/*
+		 * revision 0x20 (1543-E, 1543-F)
+		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		save_flags(flags);
+		cli();
+		/*
+		 * clear bit 7
+		 */
+		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+		restore_flags(flags);
+
+		/*
+		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+		 */
+		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+	}
+
+	return 0;
+}
+
+unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+	/*
+	 * FIXME !!!!
+	 * {0x4a,0x01,0x01}, {0x4a,0x02,0x02}
+	 */
+	return 0;
+}
+
+void __init ide_init_ali15x3 (ide_hwif_t *hwif)
+{
+	byte ideic, inmir;
+	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+				      1, 11, 0, 12, 0, 14, 0, 15 };
+
+	hwif->irq = hwif->channel ? 15 : 14;
+
+	if (isa_dev) {
+		/*
+		 * read IDE interface control
+		 */
+		pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+		/* bit0, bit1 */
+		ideic = ideic & 0x03;
+
+		/* get IRQ for IDE Controller */
+		if ((hwif->channel && ideic == 0x03) ||
+		    (!hwif->channel && !ideic)) {
+			/*
+			 * get SIRQ1 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x44, &inmir);
+			inmir = inmir & 0x0f;
+			hwif->irq = irq_routing_table[inmir];
+		} else if (hwif->channel && !(ideic & 0x01)) {
+			/*
+			 * get SIRQ2 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x75, &inmir);
+			inmir = inmir & 0x0f;
+			hwif->irq = irq_routing_table[inmir];
+		}
+	}
+
+	hwif->tuneproc = &ali15x3_tune_drive;
+	if ((hwif->dma_base) && (m5229_revision >= 0xC1)) {
+		/*
+		 * M1543C or newer for DMAing
+		 */
+		hwif->dmaproc = &ali15x3_dmaproc;
+		hwif->autodma = 1;
+	} else {
+		hwif->autodma = 0;
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	ali_proc = 1;
+	bmide_dev = hwif->pci_dev;
+	ali_display_info = &ali_get_info;
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+	return;
+}
+
+void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((dmabase) && (m5229_revision < 0x20)) {
+		return;
+	}
+	ide_setup_dma(hwif, dmabase, 8);
+}
diff -u --recursive --new-file v2.3.22/linux/drivers/block/cy82c693.c linux/drivers/block/cy82c693.c
--- v2.3.22/linux/drivers/block/cy82c693.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/cy82c693.c	Mon Oct 18 11:14:22 1999
@@ -1,8 +1,8 @@
 /*
- * linux/drivers/block/cy82c693.c	Version 0.33	Jan. 23, 1999
+ * linux/drivers/block/cy82c693.c	Version 0.34	Sept 3, 1999
  *
- *  Copyright (C) 1998, 1999 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- *  Copyright (C) 1998 Andre Hedrick, Integrater
+ *  Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998-99 Andre Hedrick, Integrater
  *
  * CYPRESS CY82C693 chipset IDE controller
  *
@@ -31,6 +31,7 @@
  *
  *
  * History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
  * ASK@1999-01-23: v0.33 made a few minor code clean ups
  *                       removed DMA clock speed setting by default
  *                       added boot message
@@ -53,7 +54,7 @@
 #include "ide_modes.h"
 
 /* the current version */
-#define CY82_VERSION	"CY82C693U driver v0.33 99-01-23 Andreas S. Krebs (akrebs@altavista.net)"
+#define CY82_VERSION	"CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)"
 
 /*
  *	The following are used to debug the driver.
@@ -377,20 +378,10 @@
 
 unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
 {
-	return 0;
-}
-
-static void init_cy82c693_chip (struct pci_dev *dev)
-{
-	static int initDone = 0;
 #ifdef CY82C693_SETDMA_CLOCK
         byte data;
 #endif /* CY82C693_SETDMA_CLOCK */ 
 
-	if (initDone != 0)	/* only perform setup once */
-		return;
-	initDone = 1;
-
 	/* write info about this verion of the driver */
 	printk (KERN_INFO CY82_VERSION "\n");
 
@@ -401,7 +392,7 @@
         data = IN_BYTE(CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "CY82U693: Peripheral Configuration Register: 0x%X\n", data);
+	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
 #endif /* CY82C693_DEBUG_INFO */
 
         /*
@@ -422,10 +413,11 @@
         OUT_BYTE(data, CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "CY82U693: New Peripheral Configuration Register: 0x%X\n", data);
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
 #endif /* CY82C693_DEBUG_INFO */
 
-#endif /* CY82C693_SETDMA_CLOCK */ 
+#endif /* CY82C693_SETDMA_CLOCK */
+	return 0;
 }
 
 /*
@@ -437,7 +429,5 @@
 	if (hwif->dma_base)
 		hwif->dmaproc = &cy82c693_dmaproc;
 	hwif->tuneproc = &cy82c693_tune_drive;
-
-	init_cy82c693_chip(hwif->pci_dev);
 }
 
diff -u --recursive --new-file v2.3.22/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.3.22/linux/drivers/block/genhd.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/genhd.c	Tue Oct 19 13:47:59 1999
@@ -26,6 +26,8 @@
 extern void console_map_init(void);
 extern int soc_probe(void);
 extern int atmdev_init(void);
+extern int i2o_init(void);
+extern int cpqarray_init(void);
 
 void __init device_init(void)
 {
diff -u --recursive --new-file v2.3.22/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c
--- v2.3.22/linux/drivers/block/hpt34x.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/hpt34x.c	Mon Oct 18 11:14:22 1999
@@ -1,7 +1,9 @@
 /*
- * linux/drivers/block/hpt34x.c		Version 0.25	July 11, 1999
+ * linux/drivers/block/hpt34x.c		Version 0.27	Sept 03, 1999
+ *
+ * Copyright (C) 1998-99	Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
  *
- * Copyright (C) 1998-99	Andre Hedrick
  *
  * 00:12.0 Unknown mass storage controller:
  * Triones Technologies, Inc.
@@ -14,9 +16,6 @@
  * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
  * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
  *
- * drive_number
- *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
  */
 
 #include <linux/config.h>
@@ -58,7 +57,7 @@
 	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
 	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
 	tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
-	tmp2 = ((0x00 << drive_number) | reg2);
+	tmp2 = (reg2 & ~(0x11 << drive_number));
 	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
 	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
 }
@@ -105,7 +104,7 @@
  * after the drive is reported by the OS.  Initally for designed for
  * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
  */
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
@@ -117,76 +116,29 @@
 		return ((int) ide_dma_off_quietly);
 #endif /* HPT343_DISABLE_ALL_DMAING */
 
-	if (id->dma_ultra & 0x0010) {
-		goto backspeed;
-	} else if (id->dma_ultra & 0x0008) {
-		goto backspeed;
-	} else if (id->dma_ultra & 0x0004) {
-backspeed:
-		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
+	hpt34x_clear_chipset(drive);
+
+	if ((id->dma_ultra & 0x0010) && ultra) {
 		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
+	} else if ((id->dma_ultra & 0x0008) && ultra) {
+		speed = XFER_UDMA_2;
+	} else if ((id->dma_ultra & 0x0004) && ultra) {
+		speed = XFER_UDMA_2;
+	} else if ((id->dma_ultra & 0x0002) && ultra) {
 		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
+	} else if ((id->dma_ultra & 0x0001) && ultra) {
 		speed = XFER_UDMA_0;
 	} else if (id->dma_mword & 0x0004) {
-		if (!((id->dma_mword >> 8) & 4)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0404;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_2;
 	} else if (id->dma_mword & 0x0002) {
-		if (!((id->dma_mword >> 8) & 2)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0202;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_1;
 	} else if (id->dma_mword & 0x0001) {
-		if (!((id->dma_mword >> 8) & 1)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0101;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_0;
 	} else if (id->dma_1word & 0x0004) {
-		if (!((id->dma_1word >> 8) & 4)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_2;
 	} else if (id->dma_1word & 0x0002) {
-		if (!((id->dma_1word >> 8) & 2)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_1;
 	} else if (id->dma_1word & 0x0001) {
-		if (!((id->dma_1word >> 8) & 1)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_0;
         } else {
 		return ((int) ide_dma_off_quietly);
@@ -242,7 +194,6 @@
 {
 	byte speed;
 
-	hpt34x_clear_chipset(drive);
 	switch(pio) {
 		case 4:		speed = XFER_PIO_4;break;
 		case 3:		speed = XFER_PIO_3;break;
@@ -250,6 +201,7 @@
 		case 1:		speed = XFER_PIO_1;break;
 		default:	speed = XFER_PIO_0;break;
 	}
+	hpt34x_clear_chipset(drive);
 	(void) hpt34x_tune_chipset(drive, speed);
 }
 
@@ -268,7 +220,7 @@
 		if (id->field_valid & 4) {
 			if (id->dma_ultra & 0x0007) {
 				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
+				dma_func = config_chipset_for_dma(drive, 1);
 				if ((id->field_valid & 2) &&
 				    (dma_func != ide_dma_on))
 					goto try_dma_modes;
@@ -278,7 +230,7 @@
 			if ((id->dma_mword & 0x0007) ||
 			    (id->dma_1word & 0x0007)) {
 				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
+				dma_func = config_chipset_for_dma(drive, 0);
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
@@ -287,7 +239,7 @@
 				goto no_dma_set;
 			}
 			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
+			dma_func = config_chipset_for_dma(drive, 0);
 			if (dma_func != ide_dma_on)
 				goto no_dma_set;
 		} else {
@@ -300,6 +252,12 @@
 
 		config_chipset_for_pio(drive);
 	}
+
+#if 0
+	if (dma_func == ide_dma_on)
+		dma_func = ide_dma_off;
+#endif
+
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
@@ -313,22 +271,44 @@
 
 int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte unit = (drive->select.b.unit & 0x01);
+	unsigned int count, reading = 0;
+	byte dma_stat;
+
 	switch (func) {
-		case ide_dma_check:
-			hpt34x_clear_chipset(drive);
-			return config_drive_xfer_rate(drive);
-#if 0
 		case ide_dma_off:
 		case ide_dma_off_quietly:
+			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+			break;
 		case ide_dma_on:
+			outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+			break;
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
 		case ide_dma_read:
+			reading = 1 << 3;
 		case ide_dma_write:
-		case ide_dma_begin:
-		case ide_dma_end:
-		case ide_dma_test_irq:
-#endif
+			if (!(count = ide_build_dmatable(drive, func)))
+				return 1;	/* try PIO instead of DMA */
+			outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */
+			reading |= 0x01;
+			outb(reading, dma_base);		/* specify r/w */
+			outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
+			drive->waiting_for_dma = 1;
+			if (drive->media != ide_disk)
+				return 0;
+			drive->timeout = WAIT_CMD;
+			ide_set_handler(drive, &ide_dma_intr);	/* issue cmd to drive */
+			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			return 0;
+		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
+			drive->waiting_for_dma = 0;
+			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
+			dma_stat = inb(dma_base+2);		/* get DMA status */
+			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
+			return (dma_stat & 7) != 4;		/* verify good DMA status */
 		default:
 			break;
 	}
@@ -342,10 +322,17 @@
 
 unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
 {
+	int i = 0;
+	unsigned long hpt34xIoBase = dev->resource[4].start;
 	unsigned short cmd;
+	unsigned long flags;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
 
 	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
 	if (cmd & PCI_COMMAND_MEMORY) {
 		if (dev->resource[PCI_ROM_RESOURCE].start) {
 			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
@@ -353,27 +340,28 @@
 		}
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
 	} else {
-		int i = 0;
-		unsigned long hpt34xIoBase = dev->resource[4].start;
-
-		pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-		dev->resource[0].start = (hpt34xIoBase + 0x20);
-		dev->resource[1].start = (hpt34xIoBase + 0x34);
-		dev->resource[2].start = (hpt34xIoBase + 0x28);
-		dev->resource[3].start = (hpt34xIoBase + 0x3c);
-		for(i=0; i<4; i++)
-			dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-		/*
-		 * Since 20-23 can be assigned and are R/W, we correct them.
-		 */
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 	}
+
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	dev->resource[0].start = (hpt34xIoBase + 0x20);
+	dev->resource[1].start = (hpt34xIoBase + 0x34);
+	dev->resource[2].start = (hpt34xIoBase + 0x28);
+	dev->resource[3].start = (hpt34xIoBase + 0x3c);
+	for(i=0; i<4; i++)
+		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+	/*
+	 * Since 20-23 can be assigned and are R/W, we correct them.
+	 */
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
+
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	__restore_flags(flags);	/* local CPU only */
+
 	return dev->irq;
 }
 
diff -u --recursive --new-file v2.3.22/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c
--- v2.3.22/linux/drivers/block/hpt366.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/block/hpt366.c	Mon Oct 18 11:14:22 1999
@@ -1,11 +1,13 @@
 /*
- * linux/drivers/block/hpt366.c		Version 0.12	August 16, 1999
+ * linux/drivers/block/hpt366.c		Version 0.13	Sept. 3, 1999
  *
  * Copyright (C) 1999			Andre Hedrick <andre@suse.com>
+ * May be copied or modified under the terms of the GNU General Public License
  *
- * drive_number
- *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
  */
 
 #include <linux/types.h>
@@ -114,17 +116,18 @@
 };
 
 #define HPT366_DEBUG_DRIVE_INFO		0
-#define HPT366_ALLOW_ATA66_4		0
+#define HPT366_ALLOW_ATA66_4		1
 #define HPT366_ALLOW_ATA66_3		1
-#define HPT366_ALLOW_ATA33_2		1
-#define HPT366_ALLOW_ATA33_1		1
-#define HPT366_ALLOW_ATA33_0		1
 
 extern char *ide_xfer_verbose (byte xfer_rate);
+byte hpt363_shared_irq = 0;
 
 static int check_in_drive_lists (ide_drive_t *drive, const char **list)
 {
 	struct hd_driveid *id = drive->id;
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("check_in_drive_lists(%s, %p)\n", drive->name, list);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 
 	while (*list) {
 		if (!strcmp(*list++,id->model)) {
@@ -139,50 +142,62 @@
 
 static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("pci_bus_clock_list(speed=0x%02x, table=%p)\n", speed, chipset_table);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed)
+		if (chipset_table->xfer_speed == speed) {
+#if HPT366_DEBUG_DRIVE_INFO
+			printk("pci_bus_clock_list: found match: 0x%08x\n", chipset_table->chipset_settings);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 			return chipset_table->chipset_settings;
+		}
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("pci_bus_clock_list: using default: 0x%08x\n", 0x01208585);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 	return 0x01208585;
 }
 
 static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	int			err;
-	byte			busclock;
-
 #if HPT366_DEBUG_DRIVE_INFO
 	int drive_number	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
 #endif /* HPT366_DEBUG_DRIVE_INFO */
-	byte regtime		= (drive->select.b.unit & 0x01) ? 0x43 : 0x40;
+	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
 	unsigned int reg1	= 0;
 	unsigned int reg2	= 0;
 
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("hpt366_tune_chipset(%s, speed=0x%02x)\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+
 	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
-	pci_read_config_byte(HWIF(drive)->pci_dev, regtime|0x01, &busclock);	
-	switch(busclock) {
-		case 0xd9:
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
 			reg2 = pci_bus_clock_list(speed, forty_base);
 			break;
-		case 0x85:
+		case 9:
 			reg2 = pci_bus_clock_list(speed, twenty_five_base);
 			break;
-		case 0xa7:
 		default:
+			printk("hpt366: assuming 33Mhz PCI bus\n");
+		case 7:
 			reg2 = pci_bus_clock_list(speed, thirty_three_base);
 			break;
 	}
-
-	if (drive->id->dword_io & 1)
-		reg2 |= 0x80000000;
-	else
-		reg2 &= ~0x80000000;
+	/*
+	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
+	 */
+	reg2 &= ~0x80000000;
 
 	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
 	err = ide_config_drive_speed(drive, speed);
 
 #if HPT366_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%08x 0x%08x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
+	printk("%s: speed=0x%02x(%s), drive%d, old=0x%08x, new=0x%08x, err=0x%04x\n",
+		drive->name, speed, ide_xfer_verbose(speed),
 		drive_number, reg1, reg2, err);
 #endif /* HPT366_DEBUG_DRIVE_INFO */
 	return(err);
@@ -203,127 +218,89 @@
 {
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
+	unsigned int reg40 = 0;
+	int  rval;
 
 	if ((id->dma_ultra & 0x0010) &&
 	    (!check_in_drive_lists(drive, bad_ata66_4)) &&
 	    (HPT366_ALLOW_ATA66_4) &&
 	    (HWIF(drive)->udma_four)) {
-		if (!((id->dma_ultra >> 8) & 16)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x1010;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_UDMA_4;
 	} else if ((id->dma_ultra & 0x0008) &&
 		   (!check_in_drive_lists(drive, bad_ata66_3)) &&
 		   (HPT366_ALLOW_ATA66_3) &&
 		   (HWIF(drive)->udma_four)) {
-		if (!((id->dma_ultra >> 8) & 8)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0808;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) &&
-		   (HPT366_ALLOW_ATA33_2) &&
-		   (!check_in_drive_lists(drive, bad_ata33))) {
-		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) &&
-		   (HPT366_ALLOW_ATA33_1) &&
-		   (!check_in_drive_lists(drive, bad_ata33))) {
-		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
+	} else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
+		if (id->dma_ultra & 0x0004) {
+			speed = XFER_UDMA_2;
+		} else if (id->dma_ultra & 0x0002) {
+			speed = XFER_UDMA_1;
+		} else if (id->dma_ultra & 0x0001) {
+			speed = XFER_UDMA_0;
 		}
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) &&
-		   (HPT366_ALLOW_ATA33_0) &&
-		   (!check_in_drive_lists(drive, bad_ata33))) {
-		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
-		speed = XFER_UDMA_0;
 	} else if (id->dma_mword & 0x0004) {
-		drive->id->dma_ultra &= ~0xFF00;
-		if (!((id->dma_mword >> 8) & 4)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0404;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_2;
 	} else if (id->dma_mword & 0x0002) {
-		drive->id->dma_ultra &= ~0xFF00;
-		if (!((id->dma_mword >> 8) & 2)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0202;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_1;
 	} else if (id->dma_mword & 0x0001) {
-		drive->id->dma_ultra &= ~0xFF00;
-		if (!((id->dma_mword >> 8) & 1)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0101;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_0;
 	} else if (id->dma_1word & 0x0004) {
-		drive->id->dma_ultra &= ~0xFF00;
-		if (!((id->dma_1word >> 8) & 4)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_2;
 	} else if (id->dma_1word & 0x0002) {
-		drive->id->dma_ultra &= ~0xFF00;
-		if (!((id->dma_1word >> 8) & 2)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_1;
 	} else if (id->dma_1word & 0x0001) {
-		drive->id->dma_ultra &= ~0xFF00;
-		if (!((id->dma_1word >> 8) & 1)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_0;
         } else {
+#if HPT366_DEBUG_DRIVE_INFO
+		printk("%s: config_chipset_for_dma: returning 'ide_dma_off_quietly'\n", drive->name);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 		return ((int) ide_dma_off_quietly);
 	}
 
+	/* Disable the "fast interrupt" prediction.
+	 * Instead, always wait for the real interrupt from the drive!
+	 */
+	{
+		byte reg51h = 0;
+		pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, &reg51h);
+		if (reg51h & 0x80)
+			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
+	}
+
+	/*
+	 * Preserve existing PIO settings:
+	 */
+	pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, &reg40);
+	speed = (speed & ~0xc0000000) | (reg40 & 0xc0000000);
+
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("%s: config_chipset_for_dma:  speed=0x%04x\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 	(void) hpt366_tune_chipset(drive, speed);
 
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+	rval = (int)(	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
 			((id->dma_mword >> 8) & 7) ? ide_dma_on :
 			((id->dma_1word >> 8) & 7) ? ide_dma_on :
 						     ide_dma_off_quietly);
+
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("%s: config_chipset_for_dma: returning %d (%s)\n", drive->name, rval, rval == ide_dma_on ? "dma_on" : "dma_off");
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+	return rval;
 }
 
 static void config_chipset_for_pio (ide_drive_t *drive)
 {
 	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
 	unsigned short xfer_pio	= drive->id->eide_pio_modes;
-
 	byte			timing, speed, pio;
+	unsigned int reg40 = 0;
 
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("%s: config_chipset_for_pio\n", drive->name);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
 
 	if (xfer_pio> 4)
@@ -353,6 +330,14 @@
 			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
 			break;
 	}
+	/*
+	 * Preserve existing DMA settings:
+	 */
+	pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, &reg40);
+	speed = (speed & ~0x30070000) | (reg40 & 0x30070000);
+#if HPT366_DEBUG_DRIVE_INFO
+	printk("%s: config_chipset_for_pio:  speed=0x%04x\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
 	(void) hpt366_tune_chipset(drive, speed);
 }
 
@@ -428,8 +413,9 @@
 
 int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
+#if 0
 	byte reg50h = 0, reg52h = 0;
-
+#endif
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
@@ -463,28 +449,81 @@
 
 unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
-	byte ata66 = 0;
+	byte test = 0;
 
-	pci_read_config_byte(dev, 0x5a, &ata66);
 	if (dev->resource[PCI_ROM_RESOURCE].start)
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-	printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn));
+
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+	if (test != 0x78)
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
 	return dev->irq;
 }
 
+unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
+{
+	byte ata66 = 0;
+
+	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+#ifdef DEBUG
+	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+		ata66, (ata66 & 0x02) ? "33" : "66",
+		PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+	return ((ata66 & 0x02) ? 0 : 1);
+}
+
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
+#if 0
+	if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) {
+		hwif->mate = &ide_hwifs[hwif->index-1];
+		hwif->mate->mate = hwif;
+		hwif->serialized = hwif->mate->serialized = 1;
+	}
+#endif
+
 	hwif->tuneproc = &hpt366_tune_drive;
 	if (hwif->dma_base) {
-		byte ata66 = 0;
-
 		hwif->dmaproc = &hpt366_dmaproc;
-		pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
-		hwif->udma_four = (ata66 & 0x02) ? 0 : 1;
 	} else {
-		hwif->udma_four = 0;
 		hwif->autodma = 0;
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
+}
+
+void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	byte masterdma = 0, slavedma = 0;
+	byte dma_new = 0, dma_old = inb(dmabase+2);
+	unsigned long flags;
+
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
+	dma_new = dma_old;
+	pci_read_config_byte(hwif->pci_dev, 0x43, &masterdma);
+	pci_read_config_byte(hwif->pci_dev, 0x47, &slavedma);
+
+	if (masterdma & 0x30)	dma_new |= 0x20;
+	if (slavedma & 0x30)	dma_new |= 0x40;
+	if (dma_new != dma_old) outb(dma_new, dmabase+2);
+
+	__restore_flags(flags);	/* local CPU only */
+
+	ide_setup_dma(hwif, dmabase, 8);
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/block/icside.c linux/drivers/block/icside.c
--- v2.3.22/linux/drivers/block/icside.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/icside.c	Thu Oct 21 13:38:12 1999
@@ -288,7 +288,6 @@
 static int
 icside_config_drive(ide_drive_t *drive, int mode)
 {
-	ide_hwif_t *hwif = HWIF(drive);
 	int speed, err;
 
 	if (mode == 2) {
@@ -382,7 +381,8 @@
 		if (drive->media != ide_disk)
 			return 0;
 
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+		drive->timeout = WAIT_CMD;
+		ide_set_handler(drive, &ide_dma_intr);
 		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
 			 IDE_COMMAND_REG);
 
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.3.22/linux/drivers/block/ide-cd.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/block/ide-cd.c	Tue Oct 19 13:47:40 1999
@@ -339,14 +339,15 @@
 		    failed_command->c[0] == GPCMD_READ_SUBCHANNEL)
 			return;
 	}
+
 	if (reqbuf->error_code == 0x70 && reqbuf->sense_key  == 0x02
 	 && ((reqbuf->asc      == 0x3a && reqbuf->ascq       == 0x00) ||
 	     (reqbuf->asc      == 0x04 && reqbuf->ascq       == 0x01)))
 	{
 		/*
 		 * Suppress the following errors:
-		 * "Medium not present", and "in progress of becoming ready",
-		 * to keep the noise level down to a dull roar.
+		 * "Medium not present", "in progress of becoming ready",
+		 * and "writing" to keep the noise level down to a dull roar.
 		 */
 		return;
 	}
@@ -431,6 +432,19 @@
 			printk ("\"\n");
 		}
 
+		/* The SKSV bit specifies validity of the sense_key_specific
+		 * in the next two commands. It is bit 7 of the first byte.
+		 * In the case of NOT_READY, if SKSV is set the drive can
+		 * give us nice ETA readings.
+		 */
+		if (reqbuf->sense_key == NOT_READY &&
+		    (reqbuf->sense_key_specific[0] & 0x80)) {
+			int progress = (reqbuf->sense_key_specific[1] << 8 |
+					reqbuf->sense_key_specific[2]) * 100;
+			printk("  Command is %02d%% complete\n", progress / 0xffff);
+
+		}
+
 		if (reqbuf->sense_key == ILLEGAL_REQUEST &&
 		    (reqbuf->sense_key_specific[0] & 0x80) != 0) {
 			printk ("  Error in %s byte %d",
@@ -466,21 +480,6 @@
 #endif /* not VERBOSE_IDE_CD_ERRORS */
 }
 
-
-/* Fix up a possibly partially-processed request so that we can
-   start it over entirely, or even put it back on the request queue. */
-static void restore_request (struct request *rq)
-{
-	if (rq->buffer != rq->bh->b_data) {
-		int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
-		rq->buffer = rq->bh->b_data;
-		rq->nr_sectors += n;
-		rq->sector -= n;
-	}
-	rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;
-}
-
-
 static void cdrom_queue_request_sense (ide_drive_t *drive, 
 				       struct semaphore *sem,
 				       struct atapi_request_sense *reqbuf,
@@ -533,10 +532,8 @@
 		struct packet_command *pc = (struct packet_command *)
 			                      rq->buffer;
 		cdrom_analyze_sense_data (drive,
-					  (struct atapi_request_sense *)
-					  	(pc->buffer - pc->c[4]), 
-					  (struct packet_command *)
-					  	pc->sense_data);
+			(struct atapi_request_sense *) (pc->buffer - pc->c[4]),
+			(struct packet_command *) pc->sense_data);
 	}
 	if (rq->cmd == READ && !rq->current_nr_sectors)
 		uptodate = 1;
@@ -680,7 +677,7 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	/* Wait for the controller to be idle. */
-	if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;
+	if (ide_wait_stat(drive, 0, BUSY_STAT, WAIT_READY)) return 1;
 
 	if (info->dma)
 		info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
@@ -699,7 +696,7 @@
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ide_set_handler (drive, handler, WAIT_CMD);
+		ide_set_handler (drive, handler);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
@@ -716,9 +713,14 @@
    HANDLER is the interrupt handler to call when the command completes
    or there's data ready. */
 static int cdrom_transfer_packet_command (ide_drive_t *drive,
-                                          char *cmd_buf, int cmd_len,
+                                          unsigned char *cmd_buf, int cmd_len,
 					  ide_handler_t *handler)
 {
+	/* don't timeout for blank and format commands. they may take
+	 * a _very_ long time. */
+	if (cmd_buf[0] == GPCMD_BLANK || cmd_buf[0] == GPCMD_FORMAT_UNIT)
+		drive->timeout = 0;
+
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
@@ -734,7 +736,7 @@
 	}
 
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, WAIT_CMD);
+	ide_set_handler (drive, handler);
 
 	/* Send the command to the device. */
 	atapi_output_bytes (drive, cmd_buf, cmd_len);
@@ -770,13 +772,12 @@
 	/* If we don't yet have a sector buffer, try to allocate one.
 	   If we can't get one atomically, it's not fatal -- we'll just throw
 	   the data away rather than caching it. */
-	if (info->sector_buffer == NULL) {
-		info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE,
-							GFP_ATOMIC);
+	if (info->buffer == NULL) {
+		info->buffer = (char *) kmalloc(SECTOR_BUFFER_SIZE, GFP_ATOMIC);
 
 		/* If we couldn't get a buffer,
 		   don't try to buffer anything... */
-		if (info->sector_buffer == NULL)
+		if (info->buffer == NULL)
 			sectors_to_buffer = 0;
 	}
 
@@ -785,7 +786,7 @@
 		info->sector_buffered = sector;
 
 	/* Read the data into the buffer. */
-	dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE;
+	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
 		atapi_input_bytes (drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
@@ -802,7 +803,6 @@
 	}
 }
 
-
 /*
  * Check the contents of the interrupt reason register from the cdrom
  * and attempt to recover if there are problems.  Returns  0 if everything's
@@ -827,6 +827,12 @@
 			atapi_output_bytes (drive, &dum, sizeof (dum));
 			len -= sizeof (dum);
 		}
+	} else  if (ireason == 1) {
+		/* Some drives (ASUS) seem to tell us that status
+		 * info is available. just get it and ignore.
+		 */
+		GET_STAT();
+		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
 		printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
@@ -837,7 +843,6 @@
 	return -1;
 }
 
-
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
@@ -912,8 +917,7 @@
 
 	/* First, figure out if we need to bit-bucket
 	   any of the leading sectors. */
-	nskip = MIN ((int)(rq->current_nr_sectors -
-			   (rq->bh->b_size >> SECTOR_BITS)),
+	nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)),
 		     sectors_to_transfer);
 
 	while (nskip > 0) {
@@ -939,8 +943,7 @@
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
 		if (rq->current_nr_sectors == 0) {
-			cdrom_buffer_sectors (drive,
-					      rq->sector, sectors_to_transfer);
+			cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer);
 			sectors_to_transfer = 0;
 		} else {
 			/* Transfer data to the buffers.
@@ -952,8 +955,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_input_bytes (drive,
-						   rq->buffer, SECTOR_SIZE);
+				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -966,10 +968,9 @@
 
 	/* Done moving data!
 	   Wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_read_intr, WAIT_CMD);
+	ide_set_handler(drive, &cdrom_read_intr);
 }
 
-
 /*
  * Try to satisfy some of the current read request from our cached data.
  * Returns nonzero if the request has been completed, zero otherwise.
@@ -980,7 +981,7 @@
 	struct request *rq = HWGROUP(drive)->rq;
 
 	/* Can't do anything if there's no buffer. */
-	if (info->sector_buffer == NULL) return 0;
+	if (info->buffer == NULL) return 0;
 
 	/* Loop while this request needs data and the next block is present
 	   in our cache. */
@@ -991,7 +992,7 @@
 			cdrom_end_request (1, drive);
 
 		memcpy (rq->buffer,
-			info->sector_buffer +
+			info->buffer +
 			(rq->sector - info->sector_buffered) * SECTOR_SIZE,
 			SECTOR_SIZE);
 		rq->buffer += SECTOR_SIZE;
@@ -1026,8 +1027,6 @@
 	return 0;
 }
 
-
-
 /*
  * Routine to send a read packet command to the drive.
  * This is usually called directly from cdrom_start_read.
@@ -1056,14 +1055,13 @@
 	nskip = (sector % SECTORS_PER_FRAME);
 	if (nskip > 0) {
 		/* Sanity check... */
-		if (rq->current_nr_sectors !=
-		    (rq->bh->b_size >> SECTOR_BITS)) {
-			printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
+		if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) &&
+			(rq->sector % CD_FRAMESIZE != 0)) {
+			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
 			cdrom_end_request (0, drive);
 			return;
 		}
-
 		sector -= nskip;
 		nsect += nskip;
 		rq->current_nr_sectors += nskip;
@@ -1091,9 +1089,10 @@
 					      &cdrom_read_intr);
 }
 
+
 #define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */
-#define IDECD_SEEK_TIMER	(2 * WAIT_MIN_SLEEP)	/* 40 ms */
-#define IDECD_SEEK_TIMEOUT     WAIT_CMD                /* 10 sec */
+#define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
+#define IDECD_SEEK_TIMEOUT     WAIT_CMD			/* 10 sec */
 
 static void cdrom_seek_intr (ide_drive_t *drive)
 {
@@ -1107,7 +1106,7 @@
 
 	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
 		if (--retry == 0) {
-			printk ("%s: disabled DSC seek overlap\n", drive->name);
+			printk("%s: disabled DSC seek overlap\n", drive->name);
 			drive->dsc_overlap = 0;
 		}
 	}
@@ -1127,7 +1126,7 @@
 
 	memset (&pc.c, 0, sizeof (pc.c));
 	pc.c[0] = GPCMD_SEEK;
-	put_unaligned(htonl (frame), (unsigned int *) &pc.c[2]);
+	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
 	(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c), &cdrom_seek_intr);
 }
 
@@ -1140,6 +1139,19 @@
 	cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
 }
 
+/* Fix up a possibly partially-processed request so that we can
+   start it over entirely, or even put it back on the request queue. */
+static void restore_request (struct request *rq)
+{
+	if (rq->buffer != rq->bh->b_data) {
+		int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
+		rq->buffer = rq->bh->b_data;
+		rq->nr_sectors += n;
+		rq->sector -= n;
+	}
+	rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;
+}
+
 /*
  * Start a read request from the CD-ROM.
  */
@@ -1162,25 +1174,22 @@
 	restore_request (rq);
 
 	/* Satisfy whatever we can of this request from our cached sector. */
-	if (cdrom_read_from_buffer (drive))
+	if (cdrom_read_from_buffer(drive))
 		return;
 
-	/* Clear the local sector buffer. */
 	info->nsectors_buffered = 0;
 
-	if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && (rq->nr_sectors % SECTORS_PER_FRAME == 0))
+	/* use dma, if possible. */
+	if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) &&
+				(rq->nr_sectors % SECTORS_PER_FRAME == 0))
 		info->dma = 1;
 	else
 		info->dma = 0;
 
 	/* Start sending the read request to the drive. */
-	cdrom_start_packet_command (drive, 32768,
-				    cdrom_start_read_continuation);
+	cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
 }
 
-
-
-
 /****************************************************************************
  * Execute all other packet commands.
  */
@@ -1197,6 +1206,9 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
+	/* restore timeout after blank or format command */
+	drive->timeout = WAIT_CMD;
+
 	/* Check for errors. */
 	if (cdrom_decode_status (drive, 0, &stat))
 		return;
@@ -1282,7 +1294,7 @@
 	}
 
 	/* Now we wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD);
+	ide_set_handler (drive, &cdrom_pc_intr);
 }
 
 
@@ -1334,6 +1346,7 @@
 	if (pc->sense_data == NULL)
 		pc->sense_data = &my_reqbuf;
 	pc->sense_data->sense_key = 0;
+
 	/* Start of retry loop. */
 	do {
 		ide_init_drive_cmd (&req);
@@ -1353,7 +1366,7 @@
 			if (reqbuf->sense_key == UNIT_ATTENTION)
 				cdrom_saw_media_change (drive);
 			else if (reqbuf->sense_key == NOT_READY &&
-				 reqbuf->asc == 4) {
+				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
 				   a disk.  Retry, but wait a little to give
 				   the drive time to complete the load. */
@@ -1368,7 +1381,6 @@
 		/* End of retry loop. */
 	} while (pc->stat != 0 && retries >= 0);
 
-
 	/* Return an error if the command failed. */
 	if (pc->stat != 0)
 		return -EIO;
@@ -1397,25 +1409,17 @@
 static
 void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
-		cdrom_do_packet_command (drive);
-	else if (rq -> cmd == RESET_DRIVE_COMMAND) {
-		cdrom_end_request (1, drive);
-		ide_do_reset (drive);
-		return;
-	} else if (rq -> cmd != READ) {
-		printk ("ide-cd: bad cmd %d\n", rq -> cmd);
-		cdrom_end_request (0, drive);
-	} else {
-		struct cdrom_info *info = drive->driver_data;
+	struct cdrom_info *info = drive->driver_data;
 
+	switch (rq->cmd) {
+	case READ: {
 		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
 			unsigned long elpased = jiffies - info->start_seek;
 			int stat = GET_STAT();
 
 			if ((stat & SEEK_STAT) != SEEK_STAT) {
 				if (elpased < IDECD_SEEK_TIMEOUT) {
-					ide_stall_queue (drive, IDECD_SEEK_TIMER);
+					ide_stall_queue(drive, IDECD_SEEK_TIMER);
 					return;
 				}
 				printk ("%s: DSC timeout\n", drive->name);
@@ -1427,6 +1431,26 @@
 		else
 			cdrom_start_read (drive, block);
 		info->last_block = block;
+		break;
+	}
+
+	case PACKET_COMMAND:
+	case REQUEST_SENSE_COMMAND: {
+		cdrom_do_packet_command(drive);
+		break;
+	}
+
+	case RESET_DRIVE_COMMAND: {
+		cdrom_end_request(1, drive);
+		ide_do_reset(drive);
+		break;
+	}
+
+	default: {
+		printk("ide-cd: bad cmd %d\n", rq -> cmd);
+		cdrom_end_request(0, drive);
+		break;
+	}
 	}
 }
 
@@ -1600,7 +1624,7 @@
 
 	stat = cdrom_queue_packet_command (drive, &pc);
 	if (stat == 0)
-		*capacity = ntohl (capbuf.lba);
+		*capacity = be32_to_cpu(capbuf.lba);
 
 	return stat;
 }
@@ -1879,64 +1903,7 @@
 
 
 
-/* This gets the mechanism status per ATAPI draft spec 2.6 */
-static int
-cdrom_read_mech_status (ide_drive_t *drive, char *buf, int buflen,
-			struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.buffer = buf;
-	pc.buflen = buflen;
-	pc.c[0] = GPCMD_MECHANISM_STATUS;
-	pc.c[8] = (buflen >> 8);
-	pc.c[9] = (buflen & 0xff);
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-/* Read the drive mechanism status and slot table into our internal buffer.
-   If the buffer does not yet exist, allocate it. */
-static int
-cdrom_read_changer_info (ide_drive_t *drive)
-{
-	int nslots;
-	struct cdrom_info *info = drive->driver_data;
-
-	if (info->changer_info)
-		nslots = info->changer_info->hdr.nslots;
-
-	else {
-		struct atapi_mechstat_header mechbuf;
-		int stat;
-
-		stat = cdrom_read_mech_status (drive,
-					       (char *)&mechbuf,
-					       sizeof (mechbuf),
-					       NULL);
-		if (stat)
-			return stat;
-
-		nslots = mechbuf.nslots;
-		info->changer_info =
-			(struct atapi_changer_info *)
-			kmalloc (sizeof (struct atapi_changer_info) +
-				 nslots * sizeof (struct atapi_slot),
-				 GFP_KERNEL);
-
-		if (info->changer_info == NULL)
-			return -ENOMEM;
-	}
 
-	return cdrom_read_mech_status
-		(drive,
-		 (char *)&info->changer_info->hdr,
-		 sizeof (struct atapi_mechstat_header) +
-		 nslots * sizeof (struct atapi_slot),
-		 NULL);
-}
 
 /* the generic packet interface to cdrom.c */
 static int ide_cdrom_packet(struct cdrom_device_info *cdi,
@@ -1952,8 +1919,7 @@
 	memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
 	pc.buffer = cgc->buffer;
 	pc.buflen = cgc->buflen;
-	cgc->stat = cdrom_queue_packet_command(drive, &pc);
-	return cgc->stat;
+	return cgc->stat = cdrom_queue_packet_command(drive, &pc);
 }
 
 static
@@ -2130,16 +2096,19 @@
 int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
 
 	if (slot_nr == CDSL_CURRENT) {
 
-		struct atapi_request_sense my_reqbuf;
-		int stat = cdrom_check_status (drive, &my_reqbuf);
-		if (stat == 0 || my_reqbuf.sense_key == UNIT_ATTENTION)
+		struct atapi_request_sense sense;
+		int stat = cdrom_check_status (drive, &sense);
+		if (stat == 0 || sense.sense_key == UNIT_ATTENTION)
+			return CDS_DISC_OK;
+
+		if (sense.sense_key == NOT_READY && sense.asc == 0x04 &&
+		    sense.ascq == 0x04)
 			return CDS_DISC_OK;
 
-		if (my_reqbuf.sense_key == NOT_READY) {
+		if (sense.sense_key == NOT_READY) {
 			/* ATAPI doesn't have anything that can help
 			   us decide whether the drive is really
 			   emtpy or the tray is just open. irk. */
@@ -2147,24 +2116,8 @@
 		}
 
 		return CDS_DRIVE_NOT_READY;
-	}
-
-#if ! STANDARD_ATAPI
-	else if (cdi->sanyo_slot > 0)
-		return CDS_NO_INFO;
-#endif /* not STANDARD_ATAPI */
-
-	else {
-		struct atapi_changer_info *ci;
-		int stat = cdrom_read_changer_info (drive);
-		if (stat < 0)
-			return stat;
-		ci = info->changer_info;
-
-		if (ci->slots[slot_nr].disc_present)
-			return CDS_DISC_OK;
-		else
-			return CDS_NO_DISC;
+	} else {
+		return -EINVAL;
 	}
 }
 
@@ -2215,47 +2168,14 @@
 				       int slot_nr)
 {
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
-	struct cdrom_info *info = drive->driver_data;
-	struct atapi_request_sense reqbuf;
-	int retval;
 	
 	if (slot_nr == CDSL_CURRENT) {
 		(void) cdrom_check_status (drive, NULL);
-		retval = CDROM_STATE_FLAGS (drive)->media_changed;
 		CDROM_STATE_FLAGS (drive)->media_changed = 0;
+		return CDROM_STATE_FLAGS (drive)->media_changed;
+	} else {
+		return -EINVAL;
 	}
-
-#if ! STANDARD_ATAPI
-	else if (cdi->sanyo_slot > 0) {
-		retval = 0;
-	}
-#endif /* not STANDARD_ATAPI */
-
-	else {
-		struct atapi_changer_info *ci;
-		int stat = cdrom_read_changer_info (drive);
-		if (stat < 0)
-			return stat;
-		ci = info->changer_info;
-
-		/* This test may be redundant with cdrom.c. */
-		if (slot_nr < 0 || slot_nr >= ci->hdr.nslots)
-			return -EINVAL;
-
-		retval = ci->slots[slot_nr].change;
-	}
-	
-	/* if the media has changed, check if a disc is in the drive
-	   and read the toc info. */
-	if (retval || !CDROM_STATE_FLAGS (drive)->toc_valid) {
-		/* if cdrom_read_toc fails, return 1 to indicate
-		   that a disc change has occured. there might not
-		   be a disc in the drive. */
-		if ((retval = cdrom_read_toc (drive, &reqbuf)))
-			return 1;
-	}
-		
-	return retval;
 }
 
 
@@ -2361,11 +2281,12 @@
 	 * be queued with ide_cdrom_packet(), which extracts the
 	 * drive from cdi->handle. Since this device hasn't been
 	 * registered with the Uniform layer yet, it can't do this.
-	 * Same goes cdi->ops.
+	 * Same goes for cdi->ops.
 	 */
 	cdi->handle = (ide_drive_t *) drive;
 	cdi->ops = &ide_cdrom_dops;
-	do {	/* we seem to get stat=0x01,err=0x00 the first time (??) */
+	/* we seem to get stat=0x01,err=0x00 the first time (??) */
+	do {
 		if (attempts-- <= 0)
 			return 0;
 		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
@@ -2402,14 +2323,9 @@
 #endif /* not STANDARD_ATAPI */
 	if (buf.cap.mechtype == mechtype_individual_changer ||
 	    buf.cap.mechtype == mechtype_cartridge_changer) {
-		struct atapi_mechstat_header mechbuf;
-
-		stat = cdrom_read_mech_status (drive, (char*)&mechbuf,
-					       sizeof (mechbuf), NULL);
-		if (!stat) {
+		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
 			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
 			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
-			nslots = mechbuf.nslots;
 		}
 	}
 
@@ -2445,7 +2361,7 @@
         else 	
         	printk (" drive");
 
-	printk (", %dkB Cache", ntohs(buf.cap.buffer_size));
+	printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
 
 	if (drive->using_dma) {
 		if ((drive->id->field_valid & 4) &&
@@ -2473,7 +2389,6 @@
 	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1,	1, &drive->dsc_overlap, NULL);
 }
 
-
 static
 int ide_cdrom_setup (ide_drive_t *drive)
 {
@@ -2482,13 +2397,12 @@
 	int minor = drive->select.b.unit << PARTN_BITS;
 	int nslots;
 
-	kdev_t dev = MKDEV(HWIF(drive)->major, minor);
-
-	set_device_ro (dev, 1);
+	set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
 	blksize_size[HWIF(drive)->major][minor] = CD_FRAMESIZE;
 
-	drive->special.all = 0;
-	drive->ready_stat = 0;
+	drive->special.all	= 0;
+	drive->ready_stat	= 0;
+	drive->timeout		= WAIT_CMD;
 
 	CDROM_STATE_FLAGS (drive)->media_changed = 1;
 	CDROM_STATE_FLAGS (drive)->toc_valid     = 0;
@@ -2589,11 +2503,13 @@
 	}
 #endif /* not STANDARD_ATAPI */
 
-	info->toc               = NULL;
-	info->sector_buffer     = NULL;
-	info->sector_buffered   = 0;
-	info->nsectors_buffered = 0;
+	info->toc		= NULL;
+	info->buffer		= NULL;
+	info->sector_buffered	= 0;
+	info->nsectors_buffered	= 0;
 	info->changer_info      = NULL;
+	info->last_block	= 0;
+	info->start_seek	= 0;
 
 	nslots = ide_cdrom_probe_capabilities (drive);
 
@@ -2653,15 +2569,15 @@
 
 	if (ide_unregister_subdriver (drive))
 		return 1;
-	if (info->sector_buffer != NULL)
-		kfree (info->sector_buffer);
+	if (info->buffer != NULL)
+		kfree(info->buffer);
 	if (info->toc != NULL)
-		kfree (info->toc);
+		kfree(info->toc);
 	if (info->changer_info != NULL)
-		kfree (info->changer_info);
+		kfree(info->changer_info);
 	if (devinfo->handle == drive && unregister_cdrom (devinfo))
 		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
-	kfree (info);
+	kfree(info);
 	drive->driver_data = NULL;
 	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.3.22/linux/drivers/block/ide-cd.h	Mon Oct  4 15:49:29 1999
+++ linux/drivers/block/ide-cd.h	Fri Oct 22 12:46:22 1999
@@ -34,19 +34,13 @@
 #define NO_DOOR_LOCKING 0
 #endif
 
-
-/* Size of buffer to allocate, in blocks, for audio reads. */
-
-#ifndef CDROM_NBLOCKS_BUFFER
-#define CDROM_NBLOCKS_BUFFER 8
-#endif
-
-
 /************************************************************************/
 
-#define SECTOR_SIZE 512
-#define SECTOR_BITS 9
-#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE)
+#define SECTOR_SIZE		512
+#define SECTOR_BITS 		9
+#define SECTORS_PER_FRAME	(CD_FRAMESIZE / SECTOR_SIZE)
+#define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
+#define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE / SECTOR_SIZE)
 
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
@@ -84,7 +78,8 @@
 	__u8 seeking		: 1; /* Seeking in progress */
 	__u8 audio_play		: 1; /* can do audio related commands */
 	__u8 close_tray		: 1; /* can close the tray */
-	__u8 reserved		: 4;
+	__u8 writing		: 1; /* pseudo write in progress */
+	__u8 reserved		: 3;
 	byte max_speed;		     /* Max speed of the drive */
 };
 #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
@@ -96,7 +91,8 @@
 	__u8 media_changed : 1; /* Driver has noticed a media change. */
 	__u8 toc_valid     : 1; /* Saved TOC information is current. */
 	__u8 door_locked   : 1; /* We think that the drive door is locked. */
-	__u8 reserved      : 5;
+	__u8 writing       : 1; /* the drive is currently writing */
+	__u8 reserved      : 4;
 	byte current_speed;	/* Current speed of the drive */
 };
 #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
@@ -487,13 +483,11 @@
 	byte reserved2[3];
 };
 
-
 struct atapi_changer_info {
 	struct atapi_mechstat_header hdr;
 	struct atapi_slot slots[0];
 };
 
-
 /* Extra per-device info for cdrom drives. */
 struct cdrom_info {
 
@@ -502,17 +496,9 @@
 
 	struct atapi_toc *toc;
 
-	/* Sector buffer.  If a read request wants only the first part
-	   of a cdrom block, we cache the rest of the block here,
-	   in the expectation that the data is going to be wanted soon.
-	   SECTOR_BUFFERED is the number of the first buffered sector,
-	   and NSECTORS_BUFFERED is the number of sectors in the buffer.
-	   Before the buffer is allocated, we should have
-	   SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
-
-	unsigned long sector_buffered;
-	unsigned long nsectors_buffered;
-	char *sector_buffer;
+	unsigned long	sector_buffered;
+	unsigned long	nsectors_buffered;
+	unsigned char	*buffer;
 
 	/* The result of the last successful request sense command
 	   on this device. */
@@ -533,10 +519,6 @@
         struct cdrom_device_info devinfo;
 };
 
-
-#define SECTOR_BUFFER_SIZE CD_FRAMESIZE
-
-
 /****************************************************************************
  * Descriptions of ATAPI error codes.
  */
@@ -652,6 +634,7 @@
 	{ 0x000013, "Play operation successfully completed" },
 	{ 0x000014, "Play operation stopped due to error" },
 	{ 0x000015, "No current audio status to return" },
+	{ 0x010c0a, "Write error - padding blocks added" },
 	{ 0x011700, "Recovered data with no error correction applied" },
 	{ 0x011701, "Recovered data with retries" },
 	{ 0x011702, "Recovered data with positive head offset" },
@@ -668,6 +651,7 @@
 	{ 0x015d01, 
 	    "Failure prediction threshold exceeded - Predicted media failure" },
 	{ 0x015dff, "Failure prediction threshold exceeded - False" },
+	{ 0x017301, "Power calibration area almost full" },
 	{ 0x020400, "Logical unit not ready - cause not reportable" },
 	/* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
 	{ 0x020401,
@@ -680,9 +664,35 @@
 	{ 0x023a00, "Medium not present" },
 	{ 0x025300, "Media load or eject failed" },
 	{ 0x025700, "Unable to recover table of contents" },
+	{ 0x030300, "Peripheral device write fault" },
+	{ 0x030301, "No write current" },
+	{ 0x030302, "Excessive write errors" },
+	{ 0x030c00, "Write error" },
+	{ 0x030c01, "Write error - Recovered with auto reallocation" },
+	{ 0x030c02, "Write error - auto reallocation failed" },
+	{ 0x030c03, "Write error - recommend reassignment" },
+	{ 0x030c04, "Compression check miscompare error" },
+	{ 0x030c05, "Data expansion occurred during compress" },
+	{ 0x030c06, "Block not compressible" },
+	{ 0x030c07, "Write error - recovery needed" },
+	{ 0x030c08, "Write error - recovery failed" },
+	{ 0x030c09, "Write error - loss of streaming" },
 	{ 0x031100, "Unrecovered read error" },
 	{ 0x031106, "CIRC unrecovered error" },
 	{ 0x033101, "Format command failed" },
+	{ 0x033200, "No defect spare location available" },
+	{ 0x033201, "Defect list update failure" },
+	{ 0x035100, "Erase failure" },
+	{ 0x037200, "Session fixation error" },
+	{ 0x037201, "Session fixation error writin lead-in" },
+	{ 0x037202, "Session fixation error writin lead-out" },
+	{ 0x037300, "CD control error" },
+	{ 0x037302, "Power calibration area is full" },
+	{ 0x037303, "Power calibration area error" },
+	{ 0x037304, "Program memory area / RMA update failure" },
+	{ 0x037305, "Program memory area / RMA is full" },
+	{ 0x037306, "Program memory area / RMA is (almost) full" },
+
 	{ 0x040200, "No seek complete" },
 	{ 0x040300, "Write fault" },
 	{ 0x040900, "Track following error" },
@@ -700,11 +710,15 @@
 	{ 0x052000, "Invalid command operation code" },
 	{ 0x052c00, "Command sequence error" },
 	{ 0x052100, "Logical block address out of range" },
+	{ 0x052102, "Invalid address for write" },
 	{ 0x052400, "Invalid field in command packet" },
 	{ 0x052600, "Invalid field in parameter list" },
 	{ 0x052601, "Parameter not supported" },
 	{ 0x052602, "Parameter value invalid" },
 	{ 0x052700, "Write protected media" },
+	{ 0x052c00, "Command sequence error" },
+	{ 0x052c03, "Current program area is not empty" },
+	{ 0x052c04, "Current program area is empty" },
 	{ 0x053001, "Cannot read medium - unknown format" },
 	{ 0x053002, "Cannot read medium - incompatible format" },
 	{ 0x053900, "Saving parameters not supported" },
@@ -713,11 +727,15 @@
 	{ 0x055500, "System resource failure" },
 	{ 0x056300, "End of user area encountered on this track" },
 	{ 0x056400, "Illegal mode for this track or incompatible medium" },
-	{ 0x056f00, 
-	    "Copy protection key exchange failure - Authentication failure" },
+	{ 0x056f00, "Copy protection key exchange failure - Authentication failure" },
 	{ 0x056f01, "Copy protection key exchange failure - Key not present" },
-	{ 0x056f02, 
-	    "Copy protection key exchange failure - Key not established" },
+	{ 0x056f02, "Copy protection key exchange failure - Key not established" },
+	{ 0x056f03, "Read of scrambled sector without authentication" },
+	{ 0x056f04, "Media region code is mismatched to logical unit" },
+	{ 0x056f05,  "Drive region must be permanent / region reset count error" },
+	{ 0x057203, "Session fixation error - incomplete track in session" },
+	{ 0x057204, "Empty or partially written reserved track" },
+	{ 0x057205, "No more RZONE reservations are allowed" },
 	{ 0x05bf00, "Loss of streaming" },
 	{ 0x062800, "Not ready to ready transition, medium may have changed" },
 	{ 0x062900, "Power on, reset or hardware reset occurred" },
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.3.22/linux/drivers/block/ide-disk.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/ide-disk.c	Mon Oct 18 11:14:22 1999
@@ -175,7 +175,7 @@
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD);
+		ide_set_handler (drive, &read_intr);
 	}
 }
 
@@ -206,7 +206,7 @@
 				ide_end_request(1, hwgroup);
 			if (i > 0) {
 				idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
-				ide_set_handler (drive, &write_intr, WAIT_CMD);
+				ide_set_handler (drive, &write_intr);
 			}
 			goto out;
 		}
@@ -271,7 +271,7 @@
 		if (stat & DRQ_STAT) {
 			if (rq->nr_sectors) {
 				ide_multwrite(drive, drive->mult_count);
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
+				ide_set_handler (drive, &multwrite_intr);
 				goto out;
 			}
 		} else {
@@ -385,7 +385,7 @@
 		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
 			return;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		ide_set_handler(drive, &read_intr, WAIT_CMD);
+		ide_set_handler(drive, &read_intr);
 		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
 		return;
 	}
@@ -404,10 +404,10 @@
 			__cli();	/* local CPU only */
 		if (drive->mult_count) {
 			HWGROUP(drive)->wrq = *rq; /* scratchpad */
-			ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
+			ide_set_handler (drive, &multwrite_intr);
 			ide_multwrite(drive, drive->mult_count);
 		} else {
-			ide_set_handler (drive, &write_intr, WAIT_CMD);
+			ide_set_handler (drive, &write_intr);
 			idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
 		}
 		return;
@@ -506,6 +506,7 @@
 	drive->special.all = 0;
 	drive->special.b.set_geometry = 1;
 	drive->special.b.recalibrate  = 1;
+	drive->timeout = WAIT_CMD;
 	if (OK_TO_RESET_CONTROLLER)
 		drive->mult_count = 0;
 	if (!drive->keep_settings)
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.3.22/linux/drivers/block/ide-dma.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/ide-dma.c	Tue Oct 19 10:22:20 1999
@@ -420,7 +420,8 @@
 			drive->waiting_for_dma = 1;
 			if (drive->media != ide_disk)
 				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */
+			drive->timeout = WAIT_CMD;
+			ide_set_handler(drive, &ide_dma_intr);/* issue cmd to drive */
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
@@ -460,7 +461,7 @@
 int ide_release_dma (ide_hwif_t *hwif)
 {
 	if (hwif->dmatable) {
-		clear_page((unsigned long)hwif->dmatable);	/* clear PRD 1st */
+		clear_page((void *)hwif->dmatable);	/* clear PRD 1st */
 		free_page((unsigned long)hwif->dmatable);	/* free PRD 2nd */
 	}
 	if ((hwif->dma_extra) && (hwif->channel == 0))
@@ -537,14 +538,7 @@
 
 		switch(dev->device) {
 			case PCI_DEVICE_ID_CMD_643:
-#ifdef CONFIG_BLK_DEV_ALI15X3
 			case PCI_DEVICE_ID_AL_M5219:
-			case PCI_DEVICE_ID_AL_M5229:
-				/*
-				 * Ali 15x3 chipsets know as ALI IV and V report
-				 * this as simplex, skip this test for them.
-				 */
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
 				outb(inb(dma_base+2) & 0x60, dma_base+2);
 				if (inb(dma_base+2) & 0x80) {
 					printk("%s: simplex device: DMA forced\n", name);
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.3.22/linux/drivers/block/ide-floppy.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/ide-floppy.c	Mon Oct 18 11:14:22 1999
@@ -916,7 +916,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);
+				ide_set_handler (drive,&idefloppy_pc_intr);
 				return;
 			}
 #if IDEFLOPPY_DEBUG_LOG
@@ -938,7 +938,7 @@
 	pc->actually_transferred+=bcount.all;				/* Update the current position */
 	pc->current_position+=bcount.all;
 
-	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);		/* And set the interrupt handler again */
+	ide_set_handler (drive,&idefloppy_pc_intr);		/* And set the interrupt handler again */
 }
 
 static void idefloppy_transfer_pc (ide_drive_t *drive)
@@ -956,7 +956,7 @@
 		ide_do_reset (drive);
 		return;
 	}
-	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD);	/* Set the interrupt routine */
+	ide_set_handler (drive, &idefloppy_pc_intr);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, floppy->pc->c, 12);		/* Send the actual packet */
 }
 
@@ -1025,7 +1025,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD);
+		ide_set_handler (drive, &idefloppy_transfer_pc);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -1519,6 +1519,7 @@
 	*((unsigned short *) &gcw) = drive->id->config;
 	drive->driver_data = floppy;
 	drive->ready_stat = 0;
+	drive->timeout = IDEFLOPPY_WAIT_CMD;
 	memset (floppy, 0, sizeof (idefloppy_floppy_t));
 	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-geometry.c linux/drivers/block/ide-geometry.c
--- v2.3.22/linux/drivers/block/ide-geometry.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/ide-geometry.c	Mon Oct 18 11:14:22 1999
@@ -5,6 +5,9 @@
 
 #include <asm/io.h>
 
+extern ide_drive_t * get_info_ptr(kdev_t);
+extern unsigned long current_capacity (ide_drive_t *);
+
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.22/linux/drivers/block/ide-pci.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/block/ide-pci.c	Mon Oct 18 11:14:22 1999
@@ -57,8 +57,9 @@
 #define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
 #define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
 #define DEVID_CX5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
+#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     0x7409})
 
-#define IDE_IGNORE	((void *)-1)
+#define	IDE_IGNORE	((void *)-1)
 
 #ifdef CONFIG_BLK_DEV_TRM290
 extern void ide_init_trm290(ide_hwif_t *);
@@ -106,54 +107,66 @@
 #define INIT_RZ1000	IDE_IGNORE
 #endif
 
-#ifdef CONFIG_BLK_DEV_VIA82C586
-extern unsigned int pci_init_via82c568(struct pci_dev *, const char *);
-extern void ide_init_via82c586(ide_hwif_t *);
-extern void ide_dmacapable_via82c586(ide_hwif_t *, unsigned long dmabase);
-#define	PCI_VIA82C586	&pci_init_via82c568
-#define	INIT_VIA82C586	&ide_init_via82c586
-#define	DMA_VIA82C586	&ide_dmacapable_via82c586
-#else
-#define PCI_VIA82C586	NULL
-#define	INIT_VIA82C586	NULL
-#define	DMA_VIA82C586	NULL
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
+extern unsigned int ata66_via82cxxx(ide_hwif_t *);
+extern void ide_init_via82cxxx(ide_hwif_t *);
+extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+#define PCI_VIA82CXXX	&pci_init_via82cxxx
+#define ATA66_VIA82CXXX	&ata66_via82cxxx
+#define INIT_VIA82CXXX	&ide_init_via82cxxx
+#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
+#else
+#define PCI_VIA82CXXX	NULL
+#define ATA66_VIA82CXXX	NULL
+#define INIT_VIA82CXXX	NULL
+#define DMA_VIA82CXXX	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_ALI15X3
 extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
+extern unsigned int ata66_ali15x3(ide_hwif_t *);
 extern void ide_init_ali15x3(ide_hwif_t *);
+extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
 #define PCI_ALI15X3	&pci_init_ali15x3
-#define	INIT_ALI15X3	&ide_init_ali15x3
+#define ATA66_ALI15X3	&ata66_ali15x3
+#define INIT_ALI15X3	&ide_init_ali15x3
+#define DMA_ALI15X3	&ide_dmacapable_ali15x3
 #else
 #define PCI_ALI15X3	NULL
-#define	INIT_ALI15X3	NULL
+#define ATA66_ALI15X3	NULL
+#define INIT_ALI15X3	NULL
+#define DMA_ALI15X3	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_CY82C693
 extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
 extern void ide_init_cy82c693(ide_hwif_t *);
 #define PCI_CY82C693	&pci_init_cy82c693
-#define	INIT_CY82C693	&ide_init_cy82c693
+#define INIT_CY82C693	&ide_init_cy82c693
 #else
 #define PCI_CY82C693	NULL
-#define	INIT_CY82C693	NULL
+#define INIT_CY82C693	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC202XX
 extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
+extern unsigned int ata66_pdc202xx(ide_hwif_t *);
 extern void ide_init_pdc202xx(ide_hwif_t *);
 #define PCI_PDC202XX	&pci_init_pdc202xx
-#define	INIT_PDC202XX	&ide_init_pdc202xx
+#define ATA66_PDC202XX	&ata66_pdc202xx
+#define INIT_PDC202XX	&ide_init_pdc202xx
 #else
 #define PCI_PDC202XX	NULL
-#define	INIT_PDC202XX	NULL
+#define ATA66_PDC202XX	NULL
+#define INIT_PDC202XX	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_PIIX
 extern void ide_init_piix(ide_hwif_t *);
-#define	INIT_PIIX	&ide_init_piix
+#define INIT_PIIX	&ide_init_piix
 #else
-#define	INIT_PIIX	NULL
+#define INIT_PIIX	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_AEC6210
@@ -167,29 +180,40 @@
 extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
 extern void ide_init_hpt34x(ide_hwif_t *);
 #define PCI_HPT34X	&pci_init_hpt34x
-#define	INIT_HPT34X	&ide_init_hpt34x
+#define INIT_HPT34X	&ide_init_hpt34x
 #else
 #define PCI_HPT34X	NULL
-#define	INIT_HPT34X	NULL
+#define INIT_HPT34X	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT366
+extern byte hpt363_shared_irq;
 extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
+extern unsigned int ata66_hpt366(ide_hwif_t *);
 extern void ide_init_hpt366(ide_hwif_t *);
+extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
 #define PCI_HPT366	&pci_init_hpt366
+#define ATA66_HPT366	&ata66_hpt366
 #define INIT_HPT366	&ide_init_hpt366
+#define DMA_HPT366	&ide_dmacapable_hpt366
 #else
+static byte hpt363_shared_irq = 0;
 #define PCI_HPT366	NULL
-#define INIT_HPT366	IDE_IGNORE
+#define ATA66_HPT366	NULL
+#define INIT_HPT366	NULL
+#define DMA_HPT366	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_SIS5513
 extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
+extern unsigned int ata66_sis5513(ide_hwif_t *);
 extern void ide_init_sis5513(ide_hwif_t *);
 #define PCI_SIS5513	&pci_init_sis5513
+#define ATA66_SIS5513	&ata66_sis5513
 #define INIT_SIS5513	&ide_init_sis5513
 #else
 #define PCI_SIS5513	NULL
+#define ATA66_SIS5513	NULL
 #define INIT_SIS5513	NULL
 #endif
 
@@ -206,49 +230,48 @@
 	ide_pci_devid_t		devid;
 	const char		*name;
 	unsigned int		(*init_chipset)(struct pci_dev *dev, const char *name);
+	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
 	void 			(*init_hwif)(ide_hwif_t *hwif);
 	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
 	ide_pci_enablebit_t	enablebits[2];
 	byte			bootable;
-	byte			sixtysix;
 	unsigned int		extra;
 } ide_pci_device_t;
 
 static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	0 },
-	{DEVID_PIIX3,	"PIIX3",	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	0 },
-	{DEVID_PIIX4,	"PIIX4",	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82C586,	INIT_VIA82C586,	DMA_VIA82C586,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0,	0 },
-	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	0,	16 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	1,	48 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0,	0 },
-	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	1,	0 },
-	{DEVID_CMD643,	"CMD643",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{DEVID_CMD646,	"CMD646",	NULL,		INIT_CMD646,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0,	0 },
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_OPTI621,	"OPTI621",	NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC6210,	NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0,	0 },
-	{DEVID_W82C105,	"W82C105",	NULL,		INIT_W82C105,	NULL,		{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	INIT_HPT366,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	1,	256 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	INIT_ALI15X3,	NULL,		{{0x09,0x20,0x20}, {0x09,0x10,0x10}},	ON_BOARD,	0,	0 },
-	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{DEVID_CX5530,	"CX5530",	NULL,		INIT_CX5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0,	0 }};
-
-static byte hpt363_shared_irq = 0;
+	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIX3,	"PIIX3",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_PIIX4,	"PIIX4",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
+	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
+	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
+	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
+	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
+	{DEVID_CMD643,	"CMD643",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD646,	"CMD646",	NULL,		NULL,		INIT_CMD646,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_AEC6210,	"AEC6210",	PCI_AEC6210,	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
+	{DEVID_W82C105,	"W82C105",	NULL,		NULL,		INIT_W82C105,	NULL,		{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
+	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
+	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	256 },
+	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CX5530,	"CX5530",	NULL,		NULL,		INIT_CX5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_AMD7409,	"AMD7409",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
 
 /*
  * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
@@ -260,24 +283,24 @@
 	switch(dev->device) {
 		case PCI_DEVICE_ID_TTI_HPT343:
 			{
+				int i;
+				unsigned long hpt34xIoBase = dev->resource[4].start;
 				unsigned short pcicmd = 0;
 
 				pci_write_config_byte(dev, 0x80, 0x00);
 				pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
 				if (!(pcicmd & PCI_COMMAND_MEMORY)) {
-					int i;
-					unsigned long hpt34xIoBase = dev->resource[4].start;
-
-					dev->resource[0].start = (hpt34xIoBase + 0x20);
-					dev->resource[1].start = (hpt34xIoBase + 0x34);
-					dev->resource[2].start = (hpt34xIoBase + 0x28);
-					dev->resource[3].start = (hpt34xIoBase + 0x3c);
-					for(i=0; i<4; i++)
-						dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 					pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
 				} else {
 					pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
 				}
+
+				dev->resource[0].start = (hpt34xIoBase + 0x20);
+				dev->resource[1].start = (hpt34xIoBase + 0x34);
+				dev->resource[2].start = (hpt34xIoBase + 0x28);
+				dev->resource[3].start = (hpt34xIoBase + 0x3c);
+				for(i=0; i<4; i++)
+					dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 			}
 		case PCI_DEVICE_ID_TTI_HPT366:
 		case PCI_DEVICE_ID_PROMISE_20246:
@@ -530,8 +553,7 @@
 			hwif->irq = hwif->channel ? 15 : 14;
 			goto bypass_umc_dma;
 		}
-		if ((!d->sixtysix) && (hwif->udma_four))
-			hwif->udma_four = 0;
+		hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X))
@@ -582,40 +604,35 @@
 
 static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
 {
-	struct pci_dev *dev2;
+	struct pci_dev *dev2 = NULL, *findev;
 	ide_pci_device_t *d2;
 	unsigned char pin1 = 0, pin2 = 0;
 
-	d2 = d;
 	if (PCI_FUNC(dev->devfn) & 1)
 		return;
-
-	for (dev2=pci_devices; dev2; dev2=dev2->next) {
-		if ((dev2->vendor == dev->vendor) &&
-		    (dev2->device == dev->device) &&
-		    (PCI_FUNC(dev2->devfn) & 1))
-			break;
-	}
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	if (dev2) {
-		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-		hpt363_shared_irq = (pin1 != pin2) ? 1 : 0;
-	}
-
-	if (hpt363_shared_irq) {
-		printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
-			d->name, pin1, pin2);
+	for (findev=pci_devices; findev; findev=findev->next) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			dev2 = findev;
+			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+			hpt363_shared_irq = (pin1 != pin2) ? 1 : 0;
+			if (hpt363_shared_irq) {
+				d->bootable = ON_BOARD;
+				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
+			}
+			break;
+		}
 	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
 	ide_setup_pci_device(dev, d);
-
-	if (dev2 && !hpt363_shared_irq) {
-		printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-			d2->name, dev2->bus->number, dev2->devfn);
-		ide_setup_pci_device(dev2, d2);
-	}
+	if (!dev2)
+		return;
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
 }
 
 /*
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.22/linux/drivers/block/ide-pmac.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/ide-pmac.c	Mon Oct 18 11:14:22 1999
@@ -363,7 +363,8 @@
 		drive->waiting_for_dma = 1;
 		if (drive->media != ide_disk)
 			return 0;
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+		drive->timeout = WAIT_CMD;
+		ide_set_handler(drive, &ide_dma_intr);
 		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
 			 IDE_COMMAND_REG);
 	case ide_dma_begin:
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.22/linux/drivers/block/ide-probe.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide-probe.c	Mon Oct 18 11:14:22 1999
@@ -42,7 +42,6 @@
 #include <linux/delay.h>
 #include <linux/ide.h>
 
-
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -85,6 +84,9 @@
 	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
 	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
+	if (strstr(id->model, "E X A B Y T E N E S T"))
+		return;
+
 	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
 	printk("%s: %s, ", drive->name, id->model);
 	drive->present = 1;
@@ -324,6 +326,35 @@
 }
 
 /*
+ *
+ */
+static void enable_nest (ide_drive_t *drive)
+{
+	unsigned long timeout;
+
+	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
+	SELECT_DRIVE(HWIF(drive), drive);
+	ide_delay_50ms();
+	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (jiffies > timeout) {
+			printk("failed (timeout)\n");
+			return;
+		}
+		ide_delay_50ms();
+	} while (GET_STAT() & BUSY_STAT);
+	ide_delay_50ms();
+	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
+		printk("failed (status = 0x%02x)\n", GET_STAT());
+	else
+		printk("success\n");
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {	/* if !(success||timed-out) */
+		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
+	}
+}
+
+/*
  * probe_for_drive() tests for existence of a given drive using do_probe().
  *
  * Returns:	0  no device was found
@@ -336,6 +367,8 @@
 	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
 		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
 	}
+	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
+		enable_nest(drive);
 	if (!drive->present)
 		return 0;			/* drive not found */
 	if (drive->id == NULL) {		/* identification failed? */
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
--- v2.3.22/linux/drivers/block/ide-proc.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide-proc.c	Mon Oct 18 11:14:22 1999
@@ -73,14 +73,21 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_BLK_DEV_VIA82C586
-int (*via_display_info)(char *, char **, off_t, int, int) = NULL;
-#endif /* CONFIG_BLK_DEV_VIA82C586 */
-
 #ifdef CONFIG_BLK_DEV_ALI15X3
+extern byte ali_proc;
 int (*ali_display_info)(char *, char **, off_t, int, int) = NULL;
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
 
+#ifdef CONFIG_BLK_DEV_SIS5513
+extern byte sis_proc;
+int (*sis_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern byte via_proc;
+int (*via_display_info)(char *, char **, off_t, int, int) = NULL;
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
 static int ide_getxdigit(char c)
 {
 	int digit;
@@ -243,7 +250,27 @@
 					}
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 				} else {	/* not pci */
-#ifndef CONFIG_Q40
+#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+
+/*
+ * Geert Uytterhoeven
+ *
+ * unless you can explain me what it really does.
+ * On m68k, we don't have outw() and outl() yet,
+ * and I need a good reason to implement it.
+ * 
+ * BTW, IMHO the main remaining portability problem with the IDE driver 
+ * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
+ * 
+ * I think all accesses should be done using
+ * 
+ *     ide_in[bwl](ide_device_instance, offset)
+ *     ide_out[bwl](ide_device_instance, value, offset)
+ * 
+ * so the architecture specific code can #define ide_{in,out}[bwl] to the
+ * appropriate function.
+ * 
+ */
 					switch (digits) {
 						case 2:	outb(val, reg);
 							break;
@@ -252,7 +279,7 @@
 						case 8:	outl(val, reg);
 							break;
 					}
-#endif	/* CONFIG_Q40 */
+#endif /* !__mc68000__ && !CONFIG_APUS */
 				}
 			}
 		}
@@ -750,18 +777,24 @@
 	ent = create_proc_entry("drivers", 0, proc_ide_root);
 	if (!ent) return;
 	ent->read_proc  = proc_ide_read_drivers;
-#ifdef CONFIG_BLK_DEV_VIA82C586
-	if (via_display_info) {
-		ent = create_proc_entry("via", 0, proc_ide_root);
-		ent->get_info = via_display_info;
-	}
-#endif /* CONFIG_BLK_DEV_VIA82C586 */
 #ifdef CONFIG_BLK_DEV_ALI15X3
-	if (ali_display_info) {
+	if ((ali_display_info) && (ali_proc)) {
 		ent = create_proc_entry("ali", 0, proc_ide_root);
 		ent->get_info = ali_display_info;
 	}
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_SIS5513
+	if ((sis_display_info) && (sis_proc)) {
+		ent = create_proc_entry("sis", 0, proc_ide_root);
+		ent->get_info = sis_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	if ((via_display_info) && (via_proc)) {
+		ent = create_proc_entry("via", 0, proc_ide_root);
+		ent->get_info = via_display_info;
+	}
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
 }
 
 void proc_ide_destroy(void)
@@ -770,14 +803,18 @@
 	 * Mmmm.. does this free up all resources,
 	 * or do we need to do a more proper cleanup here ??
 	 */
-#ifdef CONFIG_BLK_DEV_VIA82C586
-	if (via_display_info)
-		remove_proc_entry("ide/via",0);
-#endif /* CONFIG_BLK_DEV_VIA82C586 */
 #ifdef CONFIG_BLK_DEV_ALI15X3
-	if (ali_display_info)
+	if ((ali_display_info) && (ali_proc))
 		remove_proc_entry("ide/ali",0);
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_SIS5513
+	if ((sis_display_info) && (sis_proc))
+		remove_proc_entry("ide/sis", 0);
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	if ((via_display_info) && (via_proc))
+		remove_proc_entry("ide/via",0);
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
 	remove_proc_entry("ide/drivers", 0);
 	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.3.22/linux/drivers/block/ide-tape.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/block/ide-tape.c	Mon Oct 18 11:14:22 1999
@@ -1833,7 +1833,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				idetape_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);
+				ide_set_handler (drive,&idetape_pc_intr);
 				return;
 			}
 #if IDETAPE_DEBUG_LOG
@@ -1855,7 +1855,7 @@
 	pc->actually_transferred+=bcount.all;					/* Update the current position */
 	pc->current_position+=bcount.all;
 
-	ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);		/* And set the interrupt handler again */
+	ide_set_handler (drive,&idetape_pc_intr);		/* And set the interrupt handler again */
 }
 
 /*
@@ -1928,7 +1928,7 @@
 		ide_do_reset (drive);
 		return;
 	}
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD);	/* Set the interrupt routine */
+	ide_set_handler(drive, &idetape_pc_intr);	/* Set the interrupt routine */
 	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
 }
 
@@ -1995,7 +1995,7 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD);
+		ide_set_handler(drive, &idetape_transfer_pc);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
 	} else {
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -3579,6 +3579,7 @@
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
 	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
+	drive->timeout = IDETAPE_WAIT_CMD;
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	/*
 	 *  These two ide-pci host adapters appear to need this disabled.
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.22/linux/drivers/block/ide.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/ide.c	Tue Oct 19 13:47:40 1999
@@ -149,9 +149,9 @@
 #include <linux/kmod.h>
 #endif /* CONFIG_KMOD */
 
-#ifdef CONFIG_BLK_DEV_VIA82C586
-extern byte fifoconfig;           /* defined in via82c586.c used by ide_setup()*/
-#endif
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+extern byte fifoconfig;		/* defined in via82cxxx.c used by ide_setup() */
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
 
 static const byte	ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
 						IDE2_MAJOR, IDE3_MAJOR,
@@ -498,13 +498,25 @@
 }
 
 /*
+ * The below two are helpers used when modifying the drive timeout.
+ */
+static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeout)
+{
+	unsigned long foo = drive->timeout;
+	drive->timeout = timeout;
+	return foo;
+}
+
+#define restore_timeout(drive, old)	(drive->timeout = old)
+
+/*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
  * at the appropriate code to handle the next interrupt, and a
  * timer is started to prevent us from waiting forever in case
  * something goes wrong (see the ide_timer_expiry() handler later on).
  */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout)
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler)
 {
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -517,8 +529,11 @@
 	}
 #endif
 	hwgroup->handler       = handler;
-	hwgroup->timer.expires = jiffies + timeout;
-	add_timer(&(hwgroup->timer));
+	/* 0 means don't timeout */
+	if (drive->timeout && !timer_pending(&hwgroup->timer)) {
+		hwgroup->timer.expires = jiffies + drive->timeout;
+		add_timer(&(hwgroup->timer));
+	}
 	spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 }
 
@@ -565,6 +580,7 @@
 static void atapi_reset_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned long old_timeout;
 	byte stat;
 
 	SELECT_DRIVE(HWIF(drive),drive);
@@ -574,7 +590,9 @@
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+			old_timeout = set_timeout(drive, HZ / 20);
+			ide_set_handler (drive, &atapi_reset_pollfunc);
+			restore_timeout(drive, old_timeout);
 			return;	/* continue polling */
 		}
 		hwgroup->poll_timeout = 0;	/* end of polling */
@@ -595,11 +613,14 @@
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long old_timeout;
 	byte tmp;
 
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &reset_pollfunc, HZ/20);
+			old_timeout = set_timeout(drive, HZ / 20);
+			ide_set_handler (drive, &reset_pollfunc);
+			restore_timeout(drive, old_timeout);
 			return;	/* continue polling */
 		}
 		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
@@ -667,6 +688,7 @@
 	unsigned long flags;
 	ide_hwif_t *hwif = HWIF(drive);
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned long old_timeout;
 
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
@@ -678,7 +700,9 @@
 		udelay (20);
 		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+		old_timeout = set_timeout(drive, HZ / 20);
+		ide_set_handler (drive, &atapi_reset_pollfunc);
+		restore_timeout(drive, old_timeout);
 		__restore_flags (flags);	/* local CPU only */
 		return;
 	}
@@ -708,7 +732,18 @@
 	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler (drive, &reset_pollfunc, HZ/20);
+	old_timeout = set_timeout(drive, HZ / 20);
+	ide_set_handler (drive, &reset_pollfunc);
+	restore_timeout(drive, old_timeout);
+
+	/*
+	 * Some weird controller like resetting themselves to a strange
+	 * state when the disks are reset this way. At least, the Winbond
+	 * 553 documentation says that
+	 */
+	if (hwif->resetproc != NULL)
+		hwif->resetproc(drive);
+
 #endif	/* OK_TO_RESET_CONTROLLER */
 
 	__restore_flags (flags);	/* local CPU only */
@@ -899,7 +934,7 @@
  */
 void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
-	ide_set_handler (drive, handler, WAIT_CMD);
+	ide_set_handler (drive, handler);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
 	OUT_BYTE(nsect,IDE_NSECTOR_REG);
@@ -1018,6 +1053,10 @@
 		if (args[0] == WIN_SMART) {
 			OUT_BYTE(0x4f, IDE_LCYL_REG);
 			OUT_BYTE(0xc2, IDE_HCYL_REG);
+			OUT_BYTE(args[2],IDE_FEATURE_REG);
+			OUT_BYTE(args[1],IDE_SECTOR_REG);
+			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+			return;
 		}
 		OUT_BYTE(args[2],IDE_FEATURE_REG);
 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
@@ -1218,13 +1257,37 @@
 		bdev->current_request = hwgroup->rq = drive->queue;
 		spin_unlock_irqrestore(&io_request_lock, io_flags);
 
+#if 0
 		if (hwif->irq != masked_irq)
-			disable_irq(hwif->irq);
+			disable_irq_nosync(hwif->irq);
 		spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
 		start_request(drive);
 		spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
 		if (hwif->irq != masked_irq)
 			enable_irq(hwif->irq);
+#else
+
+		if (masked_irq && hwif->irq != masked_irq) {
+			printk("%s: (disable_irq) %smasked_irq %d\n",
+				drive->name,
+				masked_irq  ? "" : "un_", hwif->irq);
+
+#if 0
+			disable_irq(hwif->irq);
+#else
+			disable_irq_nosync(hwif->irq);
+#endif
+		}
+		spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
+		start_request(drive);
+		spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
+		if (masked_irq && hwif->irq != masked_irq) {
+			printk("%s: (enable_irq) %smasked_irq %d\n",
+				drive->name,
+				masked_irq ? "" : "un_", hwif->irq);
+			enable_irq(hwif->irq);
+		}
+#endif
 	}
 }
 
@@ -1373,8 +1436,8 @@
 	}
 	hwgroup->busy = 1;	/* should already be "1" */
 	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);	/* Is this needed?? */
-	if (hwgroup->poll_timeout != 0) {	/* polling in progress? */
+	/* polling in progress or just don't timeout */
+	if (hwgroup->poll_timeout != 0) {
 		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		handler(drive);
 	} else if (drive_is_ready(drive)) {
@@ -1612,8 +1675,10 @@
 	}
 	spin_unlock_irqrestore(&io_request_lock, flags);
 	do_hwgroup_request(hwgroup);
-	if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
+	if (action == ide_wait) {
 		down(&sem);	/* wait for it to be serviced */
+		rq->sem = NULL;
+	}
 	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 }
 
@@ -2270,8 +2335,13 @@
 
 int ide_config_drive_speed (ide_drive_t *drive, byte speed)
 {
+	struct hd_driveid *id = drive->id;
+	unsigned long flags;
 	int err;
 
+	__save_flags(flags);	/* local CPU only */
+	__cli();		/* local CPU only */
+
 	/*
 	 * Don't use ide_wait_cmd here - it will
 	 * attempt to set_geometry and recalibrate,
@@ -2287,6 +2357,109 @@
 
 	err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
 
+#if 0
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+#endif
+
+	__restore_flags(flags);	/* local CPU only */
+
+        switch(speed) {
+		case XFER_UDMA_4:
+			if (!((id->dma_ultra >> 8) & 16)) {
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x1010;
+			}
+			drive->id->dma_mword &= ~0x0F00;
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_UDMA_3:
+			if (!((id->dma_ultra >> 8) & 8)) {
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x0808;
+			}
+			drive->id->dma_mword &= ~0x0F00;
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_UDMA_2:
+			if (!((id->dma_ultra >> 8) & 4)) {
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x0404;
+			}
+			drive->id->dma_mword &= ~0x0F00;
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_UDMA_1:
+			if (!((id->dma_ultra >> 8) & 2)) {
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x0202;
+			}
+			drive->id->dma_mword &= ~0x0F00;
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_UDMA_0:
+			if (!((id->dma_ultra >> 8) & 1)) {
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x0101;
+			}
+			drive->id->dma_mword &= ~0x0F00;
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_MW_DMA_2:
+			drive->id->dma_ultra &= ~0xFF00;
+			if (!((id->dma_mword >> 8) & 4)) {
+				drive->id->dma_mword &= ~0x0F00;
+				drive->id->dma_mword |= 0x0404;
+			}
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_MW_DMA_1:
+			drive->id->dma_ultra &= ~0xFF00;
+			if (!((id->dma_mword >> 8) & 2)) {
+				drive->id->dma_mword &= ~0x0F00;
+				drive->id->dma_mword |= 0x0202;
+			}
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_MW_DMA_0:
+			drive->id->dma_ultra &= ~0xFF00;
+			if (!((id->dma_mword >> 8) & 1)) {
+				drive->id->dma_mword &= ~0x0F00;
+				drive->id->dma_mword |= 0x0101;
+			}
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+		case XFER_SW_DMA_2:
+			drive->id->dma_ultra &= ~0xFF00;
+			drive->id->dma_mword &= ~0x0F00;
+			if (!((id->dma_1word >> 8) & 4)) {
+				drive->id->dma_1word &= ~0x0F00;
+				drive->id->dma_1word |= 0x0404;
+			}
+			break;
+		case XFER_SW_DMA_1:
+			drive->id->dma_ultra &= ~0xFF00;
+			drive->id->dma_mword &= ~0x0F00;
+			if (!((id->dma_1word >> 8) & 2)) {
+				drive->id->dma_1word &= ~0x0F00;
+				drive->id->dma_1word |= 0x0202;
+			}
+			break;
+		case XFER_SW_DMA_0:
+			drive->id->dma_ultra &= ~0xFF00;
+			drive->id->dma_mword &= ~0x0F00;
+			if (!((id->dma_1word >> 8) & 1)) {
+				drive->id->dma_1word &= ~0x0F00;
+				drive->id->dma_1word |= 0x0101;
+			}
+			break;
+		default:
+			drive->id->dma_ultra &= ~0xFF00;
+			drive->id->dma_mword &= ~0x0F00;
+			drive->id->dma_1word &= ~0x0F00;
+			break;
+	}
+
 	return(err);
 }
 
@@ -2803,7 +2976,7 @@
 		}
 	}
 
-#if defined(CONFIG_BLK_DEV_VIA82C586)
+#if defined(CONFIG_BLK_DEV_VIA82CXXX)
 	/*
 	 *  Look for drive option "splitfifo=..."
 	 */
@@ -2853,7 +3026,7 @@
 		fifoconfig = tmp;		
 		goto done;
 	}
-#endif  /* defined(CONFIG_BLK_DEV_VIA82C586) */
+#endif  /* defined(CONFIG_BLK_DEV_VIA82CXXX) */
 
 	if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
 		goto bad_option;
@@ -3393,6 +3566,7 @@
 EXPORT_SYMBOL(ide_scan_devices);
 EXPORT_SYMBOL(ide_register_subdriver);
 EXPORT_SYMBOL(ide_unregister_subdriver);
+EXPORT_SYMBOL(ide_replace_subdriver);
 EXPORT_SYMBOL(ide_input_data);
 EXPORT_SYMBOL(ide_output_data);
 EXPORT_SYMBOL(atapi_input_bytes);
@@ -3464,7 +3638,11 @@
 	while ((line = next) != NULL) {
  		if ((next = strchr(line,' ')) != NULL)
 			*next++ = 0;
-		if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '='))
+		if (!strncmp(line,"ide",3) ||
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+		    !strncmp(line,"splitfifo",9) ||
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+		    (!strncmp(line,"hd",2) && line[2] != '='))
 			ide_setup(line);
 	}
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.22/linux/drivers/block/ll_rw_blk.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/block/ll_rw_blk.c	Sat Oct 16 10:50:48 1999
@@ -416,10 +416,6 @@
 	count = bh->b_size >> 9;
 	sector = bh->b_rsector;
 
-	/* We'd better have a real physical mapping! */
-	if (!buffer_mapped(bh))
-		BUG();
-
 	/* It had better not be a new buffer by the time we see it */
 	if (buffer_new(bh))
 		BUG();
@@ -480,6 +476,13 @@
 			goto end_io;
 	}
 
+	/* We'd better have a real physical mapping!
+	   Check this bit only if the buffer was dirty and just locked
+	   down by us so at this point flushpage will block and
+	   won't clear the mapped bit under us. */
+	if (!buffer_mapped(bh))
+		BUG();
+
 /* look for a free request. */
        /* Loop uses two requests, 1 for loop and 1 for the real device.
         * Cut max_req in half to avoid running out and deadlocking. */
@@ -694,7 +697,7 @@
 
       sorry:
 	for (i = 0; i < nr; i++) {
-		clear_bit(BH_Dirty, &bh[i]->b_state);
+		mark_buffer_clean(bh[i]); /* remeber to refile it */
 		clear_bit(BH_Uptodate, &bh[i]->b_state);
 		bh[i]->b_end_io(bh[i], 0);
 	}
diff -u --recursive --new-file v2.3.22/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.3.22/linux/drivers/block/paride/pcd.c	Fri Oct 15 15:25:13 1999
+++ linux/drivers/block/paride/pcd.c	Mon Oct 18 11:14:22 1999
@@ -214,8 +214,11 @@
 static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
 static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
 				unsigned int cmd, void *arg);
+static int pcd_packet(struct cdrom_device_info *cdi,
+				struct cdrom_generic_command *cgc);
 
 static int 	pcd_detect(void);
+static void 	pcd_probe_capabilities(void);
 static void     do_pcd_read_drq(void);
 static void 	do_pcd_request(void);
 static void 	do_pcd_read(void);
@@ -276,14 +279,18 @@
 	pcd_drive_reset,
 	pcd_audio_ioctl,
 	0,			/* dev_ioctl */
-	CDC_CLOSE_TRAY    |
-	CDC_OPEN_TRAY     |
-	CDC_LOCK          |
-	CDC_MCN		  |
-	CDC_MEDIA_CHANGED |
-	CDC_RESET	  |
-	CDC_PLAY_AUDIO,
-	0
+	CDC_CLOSE_TRAY	   |
+	CDC_OPEN_TRAY	   |
+	CDC_LOCK	   |
+	CDC_MCN		   |
+	CDC_MEDIA_CHANGED  |
+	CDC_RESET	   |
+	CDC_PLAY_AUDIO	   |
+	CDC_GENERIC_PACKET |
+	CDC_CD_R	   |
+	CDC_CD_RW,
+	0,
+	pcd_packet,
 };
 
 static void pcd_init_units( void )
@@ -325,6 +332,9 @@
 
 	if (pcd_detect()) return -1;
 
+	/* get the atapi capabilities page */
+	pcd_probe_capabilities();
+
 	if (register_blkdev(MAJOR_NR,name,&cdrom_fops)) {
 		printk("pcd: unable to get major number %d\n",MAJOR_NR);
 		return -1;
@@ -525,6 +535,16 @@
 	return r;
 }
 
+static int pcd_packet(struct cdrom_device_info *cdi,
+				struct cdrom_generic_command *cgc)
+{
+	char	*un_cmd;
+	int	unit = DEVICE_NR(cdi->dev);
+
+	un_cmd = cgc->cmd;
+	return pcd_atapi(unit,un_cmd,cgc->buflen,cgc->buffer, "generic packet");
+}
+
 #define DBMSG(msg)	((verbose>1)?(msg):NULL)
 
 static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
@@ -667,6 +687,32 @@
 	return -1;
 }
 
+static void pcd_probe_capabilities( void )
+
+{	int	unit, r;
+	char	buffer[32];
+	char 	cmd[12]={0x5a,1<<3,0x2a,0,0,0,0,18,0,0,0,0};
+
+	for (unit=0;unit<PCD_UNITS;unit++) {
+		if (!PCD.present) continue;
+		r = pcd_atapi(unit,cmd,18, buffer,"mode sense capabilities");
+		if (r) continue;
+		/* we should now have the cap page */
+		if ((buffer[11] & 1) == 0)
+			PCD.info.mask |= CDC_CD_R;
+		if ((buffer[11] & 2) == 0)
+			PCD.info.mask |= CDC_CD_RW;
+		if ((buffer[12] & 1) == 0)
+			PCD.info.mask |= CDC_PLAY_AUDIO;
+		if ((buffer[14] & 1) == 0)
+			PCD.info.mask |= CDC_LOCK;
+		if ((buffer[14] & 8) == 0)
+			PCD.info.mask |= CDC_OPEN_TRAY;
+		if ((buffer[14] >> 6) == 0)
+			PCD.info.mask |= CDC_CLOSE_TRAY;
+	}
+}
+
 static int pcd_detect( void )
 
 {	char    id[18];
@@ -836,63 +882,6 @@
  
     	switch (cmd) { 
     
-	case CDROMPAUSE: 
-
-	{       char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,0,0,0,0};
-
-		return (pcd_atapi(unit,cmd,0,NULL,"pause")) * EIO;
-	}
-
-	case CDROMRESUME:
-	
-	{       char cmd[12]={GPCMD_PAUSE_RESUME,0,0,0,0,0,0,0,1,0,0,0};
-
-		return (pcd_atapi(unit,cmd,0,NULL,"resume")) * EIO;
-	}
-	
-	case CDROMPLAYMSF:
-
-	{	char cmd[12]={GPCMD_PLAY_AUDIO_MSF,0,0,0,0,0,0,0,0,0,0,0};
-		struct cdrom_msf* msf = (struct cdrom_msf*)arg;
-
-		cmd[3] = msf->cdmsf_min0;
-		cmd[4] = msf->cdmsf_sec0;
-		cmd[5] = msf->cdmsf_frame0;
-		cmd[6] = msf->cdmsf_min1;
-		cmd[7] = msf->cdmsf_sec1;
-		cmd[8] = msf->cdmsf_frame1;
-	
-		return (pcd_atapi(unit,cmd,0,NULL,"play msf")) * EIO;
-    	}
-
-    	case CDROMPLAYBLK:
-
-    	{	char cmd[12]={GPCMD_PLAY_AUDIO_10,0,0,0,0,0,0,0,0,0,0,0};
-		struct cdrom_blk* blk = (struct cdrom_blk*)arg;
-
-		cmd[2] = blk->from >> 24;
-		cmd[3] = blk->from >> 16;
-		cmd[4] = blk->from >> 8;
-		cmd[5] = blk->from;
-		cmd[7] = blk->len >> 8;
-		cmd[8] = blk->len;
-	
-		return (pcd_atapi(unit,cmd,0,NULL,"play block")) * EIO;
-    	}
-		
-    	case CDROMPLAYTRKIND:
-
-    	{	char cmd[12]={GPCMD_PLAYAUDIO_TI,0,0,0,0,0,0,0,0,0,0,0};
-		struct cdrom_ti* ti = (struct cdrom_ti*)arg;
-
-		cmd[4] = ti->cdti_trk0;
-		cmd[5] = ti->cdti_ind0;
-		cmd[7] = ti->cdti_trk1;
-		cmd[8] = ti->cdti_ind1;
-
-		return (pcd_atapi(unit,cmd,0,NULL,"play track")) * EIO;
-    	}
-	
     	case CDROMREADTOCHDR:
     
 	{	char cmd[12]={GPCMD_READ_TOC_PMA_ATIP,0,0,0,0,0,0,0,12,0,0,0};
@@ -935,97 +924,6 @@
 	
                 return r * EIO;
         }
-
-    	case CDROMSTOP:
-
-	{	char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,0,0,0,0,0,0,0,0};
-
-                return (pcd_atapi(unit,cmd,0,NULL,"stop")) * EIO;
-        }                                                         
-	
-    	case CDROMSTART:
-
-        {       char cmd[12]={GPCMD_START_STOP_UNIT,1,0,0,1,0,0,0,0,0,0,0};
-
-                return (pcd_atapi(unit,cmd,0,NULL,"start")) * EIO;
-        } 
-	
-    	case CDROMVOLCTRL:
-
-	{	char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0};
-		char buffer[32];
-		char mask[32];
-		struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-
-		cmd[2] = 0xe;
-		cmd[4] = 28;
-
-                if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol")) 
-			return -EIO;
-
-		cmd[2] = 0x4e;
-	
-		if (pcd_atapi(unit,cmd,28,buffer,"mode sense vol mask"))
-			return -EIO;
-	
-		buffer[0] = 0;
-	
-		buffer[21] = volctrl->channel0 & mask[21];
-		buffer[23] = volctrl->channel1 & mask[23];
-		buffer[25] = volctrl->channel2 & mask[25];
-		buffer[27] = volctrl->channel3 & mask[27];
-	
-		cmd[0] = 0x55;
-		cmd[1] = 0x10;
-
-		return pcd_atapi(unit,cmd,28,buffer,"mode select vol") * EIO;
-    	}
-
-    	case CDROMVOLREAD:
-
-        {       char cmd[12]={GPCMD_MODE_SENSE_10,0,0,0,0,0,0,0,0,0,0,0};
-                char buffer[32];
-                struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-                int     r;
-
-                cmd[2] = 0xe;
-                cmd[4] = 28;
-
-                r = pcd_atapi(unit,cmd,28,buffer,"mode sense vol read");
-
-		volctrl->channel0 = buffer[21];
-		volctrl->channel1 = buffer[23];
-		volctrl->channel2 = buffer[25];
-		volctrl->channel3 = buffer[27];
-
-                return r * EIO;
-        }
-  
-	
-    	case CDROMSUBCHNL:
-
-	{	char cmd[12]={GPCMD_READ_SUBCHANNEL,2,0x40,1,0,0,0,0,16,0,0,0};
-		struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
-		char buffer[32];
-	
-                if (pcd_atapi(unit,cmd,16,buffer,"read subchannel"))
-                        return -EIO;
-   	
-		subchnl->cdsc_audiostatus = buffer[1];
-		subchnl->cdsc_format = CDROM_MSF;
-		subchnl->cdsc_ctrl = buffer[5] & 0xf;
-		subchnl->cdsc_trk = buffer[6];
-		subchnl->cdsc_ind = buffer[7];
-	
-		subchnl->cdsc_reladdr.msf.minute = buffer[13];
-		subchnl->cdsc_reladdr.msf.second = buffer[14];
-		subchnl->cdsc_reladdr.msf.frame = buffer[15];
-		subchnl->cdsc_absaddr.msf.minute = buffer[9];
-		subchnl->cdsc_absaddr.msf.second = buffer[10];
-		subchnl->cdsc_absaddr.msf.frame = buffer[11];
-
-		return 0;	
-    	}
 
     	default:
 
diff -u --recursive --new-file v2.3.22/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c
--- v2.3.22/linux/drivers/block/pdc202xx.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/block/pdc202xx.c	Mon Oct 18 11:14:22 1999
@@ -1,8 +1,8 @@
 /*
- *  linux/drivers/block/pdc202xx.c	Version 0.26	May 12, 1999
+ *  linux/drivers/block/pdc202xx.c	Version 0.27	Sept. 3, 1999
  *
- *  Copyright (C) 1998-99	Andre Hedrick
- *					(hedrick@astro.dyer.vanderbilt.edu)
+ *  Copyright (C) 1998-99	Andre Hedrick (andre@suse.com)
+ *  May be copied or modified under the terms of the GNU General Public License
  *
  *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
  *  compiled into the kernel if you have more than one card installed.
@@ -72,6 +72,12 @@
  *      = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
  */
 
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -88,6 +94,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
+#include "ide_modes.h"
+
 #define PDC202XX_DEBUG_DRIVE_INFO		0
 #define PDC202XX_DECODE_REGISTER_INFO		0
 
@@ -208,27 +216,78 @@
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK;
 
 	int			err;
 	unsigned int		drive_conf;
 	byte			drive_pci;
-	byte			test1, test2, speed;
-	byte			AP, BP, CP, DP, EP;
+	byte			test1, test2, speed = -1;
+	byte			AP, BP, CP, DP, TB, TC;
+	unsigned short		EP;
+	byte CLKSPD		= IN_BYTE(high_16 + 0x11);
 	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
 	byte udma_66		= ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
-	byte udma_33		= ultra ? (inb((dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0;
+	byte udma_33		= ultra ? (inb(high_16 + 0x001f) & 1) : 0;
 
-	pci_read_config_byte(dev, 0x50, &EP);
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	byte mask		= hwif->channel ? 0x08 : 0x02;
+	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
+	byte ultra_66		= ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	pci_read_config_word(dev, 0x50, &EP);
+
+	if ((ultra_66) && (EP & c_mask)) {
+#ifdef DEBUG
+		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary", "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+	} else {
+		if (ultra_66) {
+			/*
+			 * check to make sure drive on same channel
+			 * is u66 capable
+			 */
+			if (hwif->drives[!(drive_number%2)].id) {
+				if ((hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0010) ||
+				    (hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0008)) {
+					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+				} else {
+					OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+			}
+		}
+	}
 
 	switch(drive_number) {
 		case 0:	drive_pci = 0x60;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
 			pci_read_config_byte(dev, (drive_pci), &test1);
 			if (!(test1 & SYNC_ERRDY_EN))
 				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
 			break;
 		case 1:	drive_pci = 0x64;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
 			pci_read_config_byte(dev, 0x60, &test1);
 			pci_read_config_byte(dev, (drive_pci), &test2);
 			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -236,12 +295,16 @@
 			break;
 		case 2:	drive_pci = 0x68;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
 			pci_read_config_byte(dev, (drive_pci), &test1);
 			if (!(test1 & SYNC_ERRDY_EN))
 				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
 			break;
 		case 3:	drive_pci = 0x6c;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
+			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+				goto chipset_is_set;
 			pci_read_config_byte(dev, 0x68, &test1);
 			pci_read_config_byte(dev, (drive_pci), &test2);
 			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -251,6 +314,8 @@
 			return ide_dma_off;
 	}
 
+chipset_is_set:
+
 	if (drive->media != ide_disk)
 		return ide_dma_off_quietly;
 
@@ -285,127 +350,46 @@
 	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
 
 	if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
-		if (!((id->dma_ultra >> 8) & 16)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x1010;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 8 == UDMA mode 4 == speed 6 plus cable */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01);
-		speed = XFER_UDMA_4;
+		speed = XFER_UDMA_4; TB = 0x20; TC = 0x01;
 	} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
-		if (!((id->dma_ultra >> 8) & 8)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0808;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 7 == UDMA mode 3 == speed 5 plus cable */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02);
-		speed = XFER_UDMA_3;
+		speed = XFER_UDMA_3; TB = 0x40; TC = 0x02;
 	} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
-		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 6 == UDMA mode 2 */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x20);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x01);
-		speed = XFER_UDMA_2;
+		speed = XFER_UDMA_2; TB = 0x20; TC = 0x01;
 	} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
-		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 5 == UDMA mode 1 */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x40);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x02);
-		speed = XFER_UDMA_1;
+		speed = XFER_UDMA_1; TB = 0x40; TC = 0x02;
 	} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
-		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 4 == UDMA mode 0 */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03);
-		speed = XFER_UDMA_0;
+		speed = XFER_UDMA_0; TB = 0x60; TC = 0x03;
 	} else if (id->dma_mword & 0x0004) {
-		if (!((id->dma_mword >> 8) & 4)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0404;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 4 == DMA mode 2 multi-word */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x03);
-		speed = XFER_MW_DMA_2;
+		speed = XFER_MW_DMA_2; TB = 0x60; TC = 0x03;
 	} else if (id->dma_mword & 0x0002) {
-		if (!((id->dma_mword >> 8) & 2)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0202;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 3 == DMA mode 1 multi-word */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x04);
-		speed = XFER_MW_DMA_1;
+		speed = XFER_MW_DMA_1; TB = 0x60; TC = 0x04;
 	} else if (id->dma_mword & 0x0001) {
-		if (!((id->dma_mword >> 8) & 1)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0101;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		/* speed 2 == DMA mode 0 multi-word */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05);
-		speed = XFER_MW_DMA_0;
+		speed = XFER_MW_DMA_0; TB = 0x60; TC = 0x05;
 	} else if (id->dma_1word & 0x0004) {
-		if (!((id->dma_1word >> 8) & 4)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0404;
-		}
 		/* speed 2 == DMA mode 2 single-word */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x60);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x05);
-		speed = XFER_SW_DMA_2;
+		speed = XFER_SW_DMA_2; TB = 0x60; TC = 0x05;
 	} else if (id->dma_1word & 0x0002) {
-		if (!((id->dma_1word >> 8) & 2)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0202;
-		}
 		/* speed 1 == DMA mode 1 single-word */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0x80);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x06);
-		speed = XFER_SW_DMA_1;
+		speed = XFER_SW_DMA_1; TB = 0x80; TC = 0x06;
 	} else if (id->dma_1word & 0x0001) {
-		if (!((id->dma_1word >> 8) & 1)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0101;
-		}
 		/* speed 0 == DMA mode 0 single-word */
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|0xC0);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|0x0B);
-		speed = XFER_SW_DMA_0;
+		speed = XFER_SW_DMA_0; TB = 0xC0; TC = 0x0B;
 	} else {
 		/* restore original pci-config space */
 		pci_write_config_dword(dev, drive_pci, drive_conf);
 		return ide_dma_off_quietly;
 	}
 
-	err = ide_config_drive_speed(drive, speed);
+	pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
 
 #if PDC202XX_DECODE_REGISTER_INFO
 	pci_read_config_byte(dev, (drive_pci), &AP);
@@ -418,6 +402,8 @@
 	decode_registers(REG_D, DP);
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
+	err = ide_config_drive_speed(drive, speed);
+
 #if PDC202XX_DEBUG_DRIVE_INFO
 	printk("%s: %s drive%d 0x%08x ",
 		drive->name, ide_xfer_verbose(speed),
@@ -441,6 +427,83 @@
  *  11,   5,   4,   3,   2,   1,   0
  */
 
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte			drive_pci, speed;
+	byte			AP, BP, TA, TB;
+
+	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+	int err;
+
+	switch (drive_number) {
+		case 0: drive_pci = 0x60;	break;
+		case 1: drive_pci = 0x64;	break;
+		case 2: drive_pci = 0x68;	break;
+		case 3: drive_pci = 0x6c;	break;
+		default:			return 1;
+	}
+
+        pci_read_config_byte(dev, (drive_pci), &AP);
+        pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+
+        if ((AP & 0x0F) || (BP & 0x07)) {
+		/* clear PIO modes of lower 8421 bits of A Register */
+		pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
+		pci_read_config_byte(dev, (drive_pci), &AP);
+
+		/* clear PIO modes of lower 421 bits of B Register */
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
+		pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	}
+
+	pio = (pio == 5) ? 4 : pio;
+	switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
+		case 4:  speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
+		case 3:  speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
+		case 2:  speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
+		case 1:  speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
+		case 0:
+		default: speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
+	}
+	pci_write_config_byte(dev, (drive_pci), AP|TA);
+	pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+	err = ide_config_drive_speed(drive, speed);
+
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive_number, drive_conf);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return err;
+}
+
+static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
 static int config_drive_xfer_rate (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -450,9 +513,10 @@
 	if (id && (id->capability & 1) && hwif->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			return HWIF(drive)->dmaproc(ide_dma_off, drive);
+			dma_func = ide_dma_off;
+			goto fast_ata_pio;
 		}
-
+		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
 			if (id->dma_ultra & 0x001F) {
 				/* Force if Capable UltraDMA */
@@ -463,17 +527,31 @@
 			}
 		} else if (id->field_valid & 2) {
 try_dma_modes:
-			if ((id->dma_mword & 0x0004) ||
-			    (id->dma_1word & 0x0004)) {
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
 				/* Force if Capable regular DMA modes */
 				dma_func = config_chipset_for_dma(drive, 0);
+				if (dma_func != ide_dma_on)
+					goto no_dma_set;
+			}
+		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			if (id->eide_dma_time > 150) {
+				goto no_dma_set;
 			}
-		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
-			   (id->eide_dma_time > 150)) {
 			/* Consult the list of known "good" drives */
 			dma_func = config_chipset_for_dma(drive, 0);
-		}
+			if (dma_func != ide_dma_on)
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		dma_func = ide_dma_off_quietly;
+no_dma_set:
+		(void) config_chipset_for_pio(drive, 5);
 	}
+
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
@@ -498,6 +576,26 @@
 	byte primary_mode	= inb(high_16 + 0x001a);
 	byte secondary_mode	= inb(high_16 + 0x001b);
 
+	if (dev->device == PCI_DEVICE_ID_PROMISE_20262) {
+		int i = 0;
+		/*
+		 * software reset -  this is required because the bios
+		 * will set UDMA timing on if the hdd supports it. The
+		 * user may want to turn udma off. A bug in the pdc20262
+		 * is that it cannot handle a downgrade in timing from UDMA
+		 * to DMA. Disk accesses after issuing a set feature command
+		 * will result in errors. A software reset leaves the timing
+		 * registers intact, but resets the drives.
+		 */
+
+		OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+		ide_delay_50ms();
+		ide_delay_50ms();
+		OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+		for (i=0; i<40; i++)
+			ide_delay_50ms();
+	}
+
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
@@ -547,24 +645,23 @@
 	return dev->irq;
 }
 
+unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
+{
+	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+	unsigned short CIS;
+
+	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+        return ((CIS & mask) ? 0 : 1);
+}
+
 void __init ide_init_pdc202xx (ide_hwif_t *hwif)
 {
+	hwif->tuneproc = &pdc202xx_tune_drive;
+
 	if (hwif->dma_base) {
 		hwif->dmaproc = &pdc202xx_dmaproc;
-
-		switch(hwif->pci_dev->device) {
-			case PCI_DEVICE_ID_PROMISE_20262:
-#if 0
-				{
-					unsigned long high_16 = hwif->pci_dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
-					hwif->udma_four = 1;
-				}
-#endif
-				break;
-			case PCI_DEVICE_ID_PROMISE_20246:
-			default:
-				hwif->udma_four = 0;
-				break;
-		}
+	} else {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
 	}
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c
--- v2.3.22/linux/drivers/block/pdc4030.c	Sat Jun 26 08:34:20 1999
+++ linux/drivers/block/pdc4030.c	Tue Oct 19 13:47:40 1999
@@ -162,6 +162,7 @@
 	if (!hwif) return 0;
 
 	drive = &hwif->drives[0];
+	drive->timeout = HZ/100;
 	hwif2 = &ide_hwifs[hwif->index+1];
 	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
 		return 1;
@@ -169,7 +170,8 @@
 	if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
 		return 0;
 	}
-	OUT_BYTE(0x08,IDE_CONTROL_REG);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(0x08,IDE_CONTROL_REG);
 	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
 		return 0;
 	}
@@ -307,6 +309,9 @@
 	unsigned int sectors_left, sectors_avail, nsect;
 	struct request *rq;
 
+	/* reset timeout */
+	drive->timeout = HZ/100;
+	
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
 		ide_error(drive, "promise_read_intr", stat);
 		return;
@@ -361,7 +366,8 @@
 		if (stat & DRQ_STAT)
 			goto read_again;
 		if (stat & BUSY_STAT) {
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
+			drive->timeout = WAIT_CMD;
+			ide_set_handler (drive, &promise_read_intr);
 #ifdef DEBUG_READ
 			printk(KERN_DEBUG "%s: promise_read: waiting for"
 			       "interrupt\n", drive->name);
@@ -390,7 +396,7 @@
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler(drive, &promise_complete_pollfunc, 1);
+			ide_set_handler(drive, &promise_complete_pollfunc);
 			return; /* continue polling... */
 		}
 		hwgroup->poll_timeout = 0;
@@ -419,7 +425,7 @@
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler (drive, &promise_write_pollfunc, 1);
+			ide_set_handler (drive, &promise_write_pollfunc);
 			return; /* continue polling... */
 		}
 		hwgroup->poll_timeout = 0;
@@ -433,7 +439,7 @@
 	 */
 	ide_multwrite(drive, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler(drive, &promise_complete_pollfunc, 1);
+	ide_set_handler(drive, &promise_complete_pollfunc);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
 		drive->name, GET_STAT());
@@ -466,7 +472,7 @@
 	if (rq->nr_sectors > 4) {
 		ide_multwrite(drive, rq->nr_sectors - 4);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &promise_write_pollfunc, 1);
+		ide_set_handler (drive, &promise_write_pollfunc);
 	} else {
 	/*
 	 * There are 4 or fewer sectors to transfer, do them all in one go
@@ -474,7 +480,7 @@
 	 */
 		ide_multwrite(drive, rq->nr_sectors);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler(drive, &promise_complete_pollfunc, 1);
+		ide_set_handler(drive, &promise_complete_pollfunc);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
 			"status = %02x\n", drive->name, GET_STAT());
@@ -517,7 +523,8 @@
 				printk(KERN_DEBUG "%s: read: waiting for "
 				                  "interrupt\n", drive->name);
 #endif
-				ide_set_handler(drive, &promise_read_intr, WAIT_CMD);
+				drive->timeout = WAIT_CMD;
+				ide_set_handler(drive, &promise_read_intr);
 				return;
 			}
 			udelay(1);
diff -u --recursive --new-file v2.3.22/linux/drivers/block/piix.c linux/drivers/block/piix.c
--- v2.3.22/linux/drivers/block/piix.c	Thu Aug  5 18:48:45 1999
+++ linux/drivers/block/piix.c	Mon Oct 18 11:14:22 1999
@@ -1,8 +1,9 @@
 /*
- * linux/drivers/block/piix.c	Version 0.25	July 11, 1999
+ * linux/drivers/block/piix.c	Version 0.27	Sept. 3, 1999
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
+ *  Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com)
+ *  May be copied or modified under the terms of the GNU General Public License
  *
  *  PIO mode setting function for Intel chipsets.  
  *  For use instead of BIOS settings.
@@ -182,30 +183,13 @@
 		}
 	}
 
-	if ((id->dma_ultra & 0x0010) && (ultra)) {
-		goto backspeed;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		goto backspeed;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-backspeed:
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0x0F00;
-			drive->id->dma_ultra |= 0x0404;
-		}
+	if (((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008) || (id->dma_ultra & 0x0004)) && (ultra)) {
 		u_speed = 2 << (drive_number * 4);
 		if (!(reg4a & u_speed)) {
 			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
 		}
 		speed = XFER_UDMA_2;
 	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0x0F00;
-			drive->id->dma_ultra |= 0x0202;
-		}
 		u_speed = 1 << (drive_number * 4);
 		if (!(reg4a & u_speed)) {
 			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
@@ -213,12 +197,6 @@
 		}
 		speed = XFER_UDMA_1;
 	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0x0F00;
-			drive->id->dma_ultra |= 0x0101;
-		}
 		u_speed = 0 << (drive_number * 4);
 		if (!(reg4a & u_speed)) {
 			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
@@ -228,32 +206,14 @@
 	} else if (id->dma_mword & 0x0004) {
 		if (reg4a & a_speed)
 			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		drive->id->dma_ultra &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		if (!((id->dma_mword >> 8) & 4)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0404;
-		}
 		speed = XFER_MW_DMA_2;
 	} else if (id->dma_mword & 0x0002) {
 		if (reg4a & a_speed)
 			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		drive->id->dma_ultra &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		if (!((id->dma_mword >> 8) & 2)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0202;
-		}
 		speed = XFER_MW_DMA_1;
 	} else if (id->dma_1word & 0x0004) {
 		if (reg4a & a_speed)
 			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		drive->id->dma_ultra &= ~0x0F00;
-		drive->id->dma_mword &= ~0x0F00;
-		if (!((id->dma_1word >> 8) & 4)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0404;
-		}
 		speed = XFER_SW_DMA_2;
         } else {
 		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
@@ -264,10 +224,7 @@
 	(void) ide_config_drive_speed(drive, speed);
 
 #if PIIX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d ",
-		drive->name,
-		ide_xfer_verbose(speed),
-		drive_number);
+	printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number);
 	printk("\n");
 #endif /* PIIX_DEBUG_DRIVE_INFO */
 
@@ -291,7 +248,7 @@
 }
 #endif /* CONFIG_BLK_DEV_PIIX_TUNING */
 
-void ide_init_piix (ide_hwif_t *hwif)
+void __init ide_init_piix (ide_hwif_t *hwif)
 {
 	hwif->tuneproc = &piix_tune_drive;
 
diff -u --recursive --new-file v2.3.22/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.22/linux/drivers/block/rd.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/rd.c	Thu Oct 21 13:38:12 1999
@@ -704,8 +704,9 @@
 
 #define OF(args)  args
 
+#ifndef memzero
 #define memzero(s, n)     memset ((s), 0, (n))
-
+#endif
 
 typedef unsigned char  uch;
 typedef unsigned short ush;
diff -u --recursive --new-file v2.3.22/linux/drivers/block/sis5513.c linux/drivers/block/sis5513.c
--- v2.3.22/linux/drivers/block/sis5513.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/sis5513.c	Mon Oct 18 11:14:22 1999
@@ -1,11 +1,11 @@
 /*
- * linux/drivers/block/sis5513.c	Version 0.06	July 11, 1999
+ * linux/drivers/block/sis5513.c	Version 0.07	Sept. 3, 1999
  *
- * Copyright (C) 1999	Andre Hedrick
+ * Copyright (C) 1999	Andre Hedrick (andre@suse.com)
+ * May be copied or modified under the terms of the GNU General Public License
  *
- * drive_number
- *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ * Thanks to SIS Taiwan for direct support and hardware.
+ * Tested and designed on the SiS620/5513 chipset.
  */
 
 #include <linux/types.h>
@@ -27,10 +27,178 @@
 
 #include "ide_modes.h"
 
+#define SIS5513_DEBUG_DRIVE_INFO	0
+
+#define DISPLAY_SIS_TIMINGS
+
 static struct pci_dev *host_dev;
 
-#define SIS5513_DEBUG_DRIVE_INFO	0
+#if 0
+static struct _pio_mode_mapping {
+	byte data_active;
+	byte recovery;
+	byte pio_mode;
+} pio_mode_mapping[] = {
+	{ 8, 12, 0 },
+	{ 6,  7, 1 },
+	{ 4,  4, 2 },
+	{ 3,  3, 3 },
+	{ 3,  1, 4 }
+};
+
+static struct _dma_mode_mapping {
+	byte data_active;
+	byte recovery;
+	byte dma_mode;
+} dma_mode_mapping[] = {
+	{ 8, 8, 0 },
+	{ 3, 2, 1 },
+	{ 3, 1, 2 }
+};
+
+static struct _udma_mode_mapping {
+	byte cycle_time;
+	char * udma_mode;
+} udma_mode_mapping[] = {
+	{ 8, "Mode 0" },
+	{ 6, "Mode 1" },
+	{ 4, "Mode 2" }, 
+	{ 3, "Mode 3" },
+	{ 2, "Mode 4" },
+	{ 0, "Undefined" }
+};
+
+static __inline__ char * find_udma_mode (byte cycle_time)
+{
+	int n;
+	
+	for (n = 0; n <= 4; n++)
+		if (udma_mode_mapping[n].cycle_time <= cycle_time)
+			return udma_mode_mapping[n].udma_mode;
+	return udma_mode_mapping[4].udma_mode;
+}
+#endif
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int sis_get_info(char *, char **, off_t, int, int);
+extern int (*sis_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+struct pci_dev *bmide_dev;
+
+static char *cable_type[] = {
+	"80 pins",
+	"40 pins"
+};
+
+static char *recovery_time [] ={
+	"12 PCICLK", "1 PCICLK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLCK",
+	"6 PCICLK", "7 PCICLCK",
+	"8 PCICLK", "9 PCICLCK",
+	"10 PCICLK", "11 PCICLK",
+	"13 PCICLK", "14 PCICLK",
+	"15 PCICLK", "15 PCICLK"
+};
+
+static char *cycle_time [] = {
+	"Undefined", "2 CLCK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK"
+};
+
+static char *active_time [] = {
+	"8 PCICLK", "1 PCICLCK",
+	"2 PCICLK", "2 PCICLK",
+	"4 PCICLK", "5 PCICLK",
+	"6 PCICLK", "12 PCICLK"
+};
+
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	int rc;
+	char *p = buffer;
+	byte reg,reg1;
+#if 0
+	byte cyc, rec, act;
+#endif
+	u16 reg2, reg3;
+
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	rc = pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	p += sprintf(p, "Channel Status: %s \t \t \t \t %s \n",
+		     (reg & 0x02) ? "On" : "Off",
+		     (reg & 0x04) ? "On" : "Off");
+		     
+	rc = pci_read_config_byte(bmide_dev, 0x09, &reg);
+	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+		     (reg & 0x01) ? "Native" : "Compatible",
+		     (reg & 0x04) ? "Native" : "Compatible");
+		     	     
+	rc = pci_read_config_byte(bmide_dev, 0x48, &reg);
+	p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+		     (reg & 0x10) ? cable_type[1] : cable_type[0],
+		     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+		     
+	rc = pci_read_config_word(bmide_dev, 0x4c, &reg2);
+	rc = pci_read_config_word(bmide_dev, 0x4e, &reg3);
+	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+		     reg2, reg3);
+
+	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
+	p += sprintf(p, "Drvie 0:        Postwrite %s \t \t Postwrite %s\n",
+		     (reg & 0x10) ? "Enabled" : "Disabled",
+		     (reg & 0x40) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+		     (reg & 0x01) ? "Enabled" : "Disabled",
+		     (reg & 0x04) ? "Enabled" : "Disabled");
+		          
+	rc = pci_read_config_byte(bmide_dev, 0x41, &reg);
+	rc = pci_read_config_byte(bmide_dev, 0x45, &reg1);
+	p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+		     (reg & 0x80)  ? "Enabled" : "Disabled",
+		     (reg1 & 0x80) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+		     cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
+	p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
+		     active_time[(reg & 0x07)], active_time[(reg &0x07)] ); 
+
+	rc = pci_read_config_byte(bmide_dev, 0x40, &reg);
+	rc = pci_read_config_byte(bmide_dev, 0x44, &reg1);
+	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+		     recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
+
+
+	rc = pci_read_config_byte(bmide_dev, 0x4b, &reg);	     
+	p += sprintf(p, "Drvie 1:        Postwrite %s \t \t Postwrite %s\n",
+		     (reg & 0x20) ? "Enabled" : "Disabled",
+		     (reg & 0x80) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+		     (reg & 0x02) ? "Enabled" : "Disabled",
+		     (reg & 0x08) ? "Enabled" : "Disabled");
+
+	rc = pci_read_config_byte(bmide_dev, 0x43, &reg);
+	rc = pci_read_config_byte(bmide_dev, 0x47, &reg1);
+	p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+		     (reg & 0x80)  ? "Enabled" : "Disabled",
+		     (reg1 & 0x80) ? "Enabled" : "Disabled");
+	p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+		     cycle_time[(reg & 0x70) >> 4], cycle_time[(reg1 & 0x70) >> 4]);
+	p += sprintf(p, "                Data Active Time   %s \t Data Active Time   %s\n",
+		     active_time[(reg & 0x07)], active_time[(reg &0x07)] ); 
+
+	rc = pci_read_config_byte(bmide_dev, 0x42, &reg);
+	rc = pci_read_config_byte(bmide_dev, 0x46, &reg1);
+	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+		     recovery_time[(reg & 0x0f)], recovery_time[(reg1 & 0x0f)]);
+	return p-buffer;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+byte sis_proc = 0;
 extern char *ide_xfer_verbose (byte xfer_rate);
 
 /*
@@ -79,36 +247,18 @@
 	}
 
 	if ((id->dma_ultra & 0x0010) && (ultra) && (udma_66) && (four_two)) {
-		if (!((id->dma_ultra >> 8) & 16)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x1010;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		if (!(test2 & 0x90)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
 			pci_write_config_byte(dev, drive_pci|0x01, test2|0x90);
 		}
 		speed = XFER_UDMA_4;
 	} else if ((id->dma_ultra & 0x0008) && (ultra) && (udma_66) && (four_two)) {
-		if (!((id->dma_ultra >> 8) & 8)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0808;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		if (!(test2 & 0xA0)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
 			pci_write_config_byte(dev, drive_pci|0x01, test2|0xA0);
 		}
 		speed = XFER_UDMA_3;
 	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		mask = (four_two) ? 0xB0 : 0xA0;
 		if (!(test2 & mask)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
@@ -116,12 +266,6 @@
 		}
 		speed = XFER_UDMA_2;
 	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		mask = (four_two) ? 0xD0 : 0xC0;
 		if (!(test2 & mask)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
@@ -129,58 +273,22 @@
 		}
 		speed = XFER_UDMA_1;
 	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0xFF00;
-			drive->id->dma_ultra |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		if (!(test2 & unmask)) {
 			pci_write_config_byte(dev, drive_pci|0x01, test2 & ~unmask);
 			pci_write_config_byte(dev, drive_pci|0x01, test2|unmask);
 		}
 		speed = XFER_UDMA_0;
 	} else if (id->dma_mword & 0x0004) {
-		if (!((id->dma_mword >> 8) & 4)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0404;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_2;
 	} else if (id->dma_mword & 0x0002) {
-		if (!((id->dma_mword >> 8) & 2)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0202;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_1;
 	} else if (id->dma_mword & 0x0001) {
-		if (!((id->dma_mword >> 8) & 1)) {
-			drive->id->dma_mword &= ~0x0F00;
-			drive->id->dma_mword |= 0x0101;
-			drive->id->dma_1word &= ~0x0F00;
-		}
 		speed = XFER_MW_DMA_0;
 	} else if (id->dma_1word & 0x0004) {
-		if (!((id->dma_1word >> 8) & 4)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0404;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_2;
 	} else if (id->dma_1word & 0x0002) {
-		if (!((id->dma_1word >> 8) & 2)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0202;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_1;
 	} else if (id->dma_1word & 0x0001) {
-		if (!((id->dma_1word >> 8) & 1)) {
-			drive->id->dma_1word &= ~0x0F00;
-			drive->id->dma_1word |= 0x0101;
-			drive->id->dma_mword &= ~0x0F00;
-		}
 		speed = XFER_SW_DMA_0;
         } else {
 		return ((int) ide_dma_off_quietly);
@@ -189,10 +297,7 @@
 	err = ide_config_drive_speed(drive, speed);
 
 #if SIS5513_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n",
-		drive->name,
-		ide_xfer_verbose(speed),
-		drive_number);
+	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number);
 #endif /* SIS5513_DEBUG_DRIVE_INFO */
 
 	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
@@ -333,10 +438,9 @@
 unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
 {
 	struct pci_dev *host;
-	byte latency = 0, reg48h = 0;
+	byte latency = 0;
 
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
-	pci_read_config_byte(dev, 0x48, &reg48h);
 
 	for (host = pci_devices; host; host=host->next) {
 		if (host->vendor == PCI_VENDOR_ID_SI &&
@@ -344,30 +448,18 @@
 			if (latency != 0x10)
 				pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
 			host_dev = host;
-			printk("%s: Chipset Core ATA-66, SiS620\n", name);
-			printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n",
-				name,
-				(reg48h & 0x10) ? "33" : "66",
-				(reg48h & 0x20) ? "33" : "66");
 			break;
 		} else if (host->vendor == PCI_VENDOR_ID_SI &&
 			   host->device == PCI_DEVICE_ID_SI_530) {
 			host_dev = host;
-			printk("%s: Chipset Core ATA-66, SiS530\n", name);
-			printk("%s: Primary ATA-%s, Secondary ATA-%s Cable Detect\n",
-				name,
-				(reg48h & 0x10) ? "33" : "66",
-				(reg48h & 0x20) ? "33" : "66");
 			break;
 		} else if (host->vendor == PCI_VENDOR_ID_SI &&
 			   host->device == PCI_DEVICE_ID_SI_5600) {
 			host_dev = host;
-			printk("SIS5600:%s Chipset Core ATA-33\n", name);
 			break;
 		} else if (host->vendor == PCI_VENDOR_ID_SI &&
 			   host->device == PCI_DEVICE_ID_SI_5597) {
 			host_dev = host;
-			printk("SIS5597:%s Chipset Core ATA-33\n", name);
 			break;
 		}
 	}
@@ -377,18 +469,38 @@
 
 		pci_read_config_byte(dev, 0x52, &reg52h);
 		if (!(reg52h & 0x04))
+			/* set IDE controller to operate in Compabitility mode obly */
 			pci_write_config_byte(dev, 0x52, reg52h|0x04);
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+		sis_proc = 1;
+		bmide_dev = dev;
+		sis_display_info = &sis_get_info;
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
 	}
-
 	return 0;
 }
 
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
+unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
 {
-	byte reg48h = 0;
+	byte reg48h = 0, ata66 = 0;
 	byte mask = hwif->channel ? 0x20 : 0x10;
-
 	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+
+	if (host_dev) {
+		switch(host_dev->device) {
+			case PCI_DEVICE_ID_SI_530:
+			case PCI_DEVICE_ID_SI_620:
+				ata66 = (reg48h & mask) ? 0 : 1;
+			default:
+				break;
+		}
+	}
+        return (ata66);
+}
+
+void __init ide_init_sis5513 (ide_hwif_t *hwif)
+{
+
 	hwif->irq = hwif->channel ? 15 : 14;
 
 	if (!(hwif->dma_base))
@@ -398,20 +510,15 @@
 		switch(host_dev->device) {
 			case PCI_DEVICE_ID_SI_530:
 			case PCI_DEVICE_ID_SI_620:
-				hwif->autodma = 1;
-				hwif->udma_four = (reg48h & mask) ? 0 : 1;
-				hwif->dmaproc = &sis5513_dmaproc;
-				return;
 			case PCI_DEVICE_ID_SI_5600:
 			case PCI_DEVICE_ID_SI_5597:
 				hwif->autodma = 1;
-				hwif->udma_four = 0;
 				hwif->dmaproc = &sis5513_dmaproc;
-				return;
+				break;
 			default:
 				hwif->autodma = 0;
-				hwif->udma_four = 0;
-				return;
+				break;
 		}
 	}
+	return;
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c
--- v2.3.22/linux/drivers/block/sl82c105.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/sl82c105.c	Thu Oct 21 13:38:12 1999
@@ -5,7 +5,7 @@
  *
  * Maintainer unknown.
  *
- * Drive tuning added from Corel Computer's kernel sources
+ * Drive tuning added from Rebel.com's kernel sources
  *  -- Russell King (15/11/98) linux@arm.linux.org.uk
  */
 
diff -u --recursive --new-file v2.3.22/linux/drivers/block/trm290.c linux/drivers/block/trm290.c
--- v2.3.22/linux/drivers/block/trm290.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/trm290.c	Mon Oct 18 11:14:22 1999
@@ -192,7 +192,8 @@
 			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
 			if (drive->media != ide_disk)
 				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+			drive->timeout = WAIT_CMD;
+			ide_set_handler(drive, &ide_dma_intr);
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;
 		case ide_dma_begin:
diff -u --recursive --new-file v2.3.22/linux/drivers/block/via82c586.c linux/drivers/block/via82c586.c
--- v2.3.22/linux/drivers/block/via82c586.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/via82c586.c	Wed Dec 31 16:00:00 1969
@@ -1,600 +0,0 @@
-/*
- * linux/drivers/block/via82c586.c	Version 0.04	July 11, 1999
- *
- *  Copyright (C) 1998 Michel Aubry, Maintainer
- *  Copyright (C) 1998 Andre Hedrick, Maintainer
- *
- *  The VIA MVP-3 is reported OK with UDMA.
- *  The TX Pro III is also reported OK with UDMA.
- *
- *  VIA chips also have a single FIFO, with the same 64 bytes deep
- *  buffer (16 levels of 4 bytes each).
- *
- *  However, VIA chips can have the buffer split either 8:8 levels,
- *  16:0 levels or 0:16 levels between both channels. One could think
- *  of using this feature, as even if no level of FIFO is given to a
- *  given channel, one can for instance always reach ATAPI drives through
- *  it, or, if one channel is unused, configuration defaults to
- *  an even split FIFO levels.
- *  
- *  This feature is available only through a kernel command line :
- *		"splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan".
- *		where:  Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4.
- *
- *  If Chan == 1:
- *	gives all the fifo to channel 0,
- *	sets its threshold to Thr0/4,
- *	and disables any dma access to channel 1.
- *
- *  If chan == 2:
- *	gives all the fifo to channel 1,
- *	sets its threshold to Thr1/4,
- *	and disables any dma access to channel 0.
- *
- *  If chan == 3 or 4:
- *	shares evenly fifo between channels,
- *	gives channel 0 a threshold of Thr0/4,
- *	and channel 1 a threshold of Thr1/4.
- *
- *  Note that by default (if no command line is provided) and if a channel
- *  has been disabled in Bios, all the fifo is given to the active channel,
- *  and its threshold is set to 3/4.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static struct pci_dev *host_dev;
-static struct pci_dev *isa_dev;
-
-#define DISPLAY_VIA_TIMINGS
-
-#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static char *FIFO_str[] = {
-	" 1 ",
-	"3/4",
-	"1/2",
-	"1/4"
-};
-
-static char *control3_str[] = {
-	"No limitation",
-	"64",
-	"128",
-	"192"
-};
-
-static int via_get_info(char *, char **, off_t, int, int);
-extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static char * print_apollo_drive_config (char *buf, struct pci_dev *dev)
-{
-	int rc;
-	unsigned int time;
-	byte tm;
-	char *p = buf;  
- 
-	/* Drive Timing Control */
-	rc = pci_read_config_dword(dev, 0x48, &time);
-	p += sprintf(p, "Act Pls Width:  %02d          %02d           %02d          %02d\n",
-			((time & 0xf0000000)>>28) + 1,
-			((time & 0xf00000)>>20) + 1,
-			((time & 0xf000)>>12) + 1,
-			((time & 0xf0)>>4) + 1 );
-	p += sprintf(p, "Recovery Time:  %02d          %02d           %02d          %02d\n",
-			((time & 0x0f000000)>>24) + 1,
-			((time & 0x0f0000)>>16) + 1,
-			((time & 0x0f00)>>8) + 1,
-			(time & 0x0f) + 1 );
- 
-	/* Address Setup Time */
-	rc = pci_read_config_byte(dev, 0x4C, &tm);
-	p += sprintf(p, "Add. Setup T.:  %01dT          %01dT           %01dT          %01dT\n",
-			((tm & 0xc0)>>6) + 1,
-			((tm & 0x30)>>4) + 1,
-			((tm & 0x0c)>>2) + 1,
-			(tm & 0x03) + 1 );
- 
-	/* UltraDMA33 Extended Timing Control */
- 	rc = pci_read_config_dword(dev, 0x50, &time);
- 	p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n");
- 	p += sprintf(p, "Enable Meth.:    %01d           %01d            %01d           %01d\n",
-			(time & 0x80000000)	? 1 : 0,
-			(time & 0x800000)	? 1 : 0,
-			(time & 0x8000)		? 1 : 0,
-			(time & 0x80)		? 1 : 0 );
- 	p += sprintf(p, "Enable:         %s         %s          %s         %s\n",
-			(time & 0x40000000)	? "yes" : "no ",
-			(time & 0x400000)	? "yes" : "no ",
-			(time & 0x4000)		? "yes" : "no ",
-			(time & 0x40)		? "yes" : "no " );
- 	p += sprintf(p, "Transfer Mode: %s         %s          %s         %s\n",
-			(time & 0x20000000)	? "PIO" : "DMA",
-			(time & 0x200000)	? "PIO" : "DMA",
-			(time & 0x2000)		? "PIO" : "DMA",
-			(time & 0x20)		? "PIO" : "DMA" );
- 	p += sprintf(p, "Cycle Time:     %01dT          %01dT           %01dT          %01dT\n",
-			((time & 0x03000000)>>24) + 2,
-			((time & 0x030000)>>16) + 2,
-			((time & 0x0300)>>8) + 2,
-			(time & 0x03) + 2 );
- 
- 	return (char *)p;
-}
-
-static char * print_apollo_ide_config (char *buf, struct pci_dev *dev)
-{
-	byte time, tmp; 
-	unsigned short size0, size1;
-	int rc;
-	char *p = buf;  
- 
-	rc = pci_read_config_byte(dev, 0x41, &time);
-	p += sprintf(p, "Prefetch Buffer :      %s                     %s\n",
-		(time & 128)	? "on " : "off",
-		(time & 32)	? "on " : "off" );
-	p += sprintf(p, "Post Write Buffer:     %s                     %s\n",
-		(time & 64)	? "on " : "off",
-		(time & 16)	? "on " : "off" );
- 
-	/* FIFO configuration */
-	rc = pci_read_config_byte(dev, 0x43, &time);
-	tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3);
-	p += sprintf(p, "FIFO Conf/Chan. :      %02d                      %02d\n",
-			16 - tmp, tmp);
-	tmp = (time & 0x0F)>>2;
-	p += sprintf(p, "Threshold Prim. :      %s                     %s\n",
-			FIFO_str[tmp],
-			FIFO_str[time & 0x03] );
- 
-	/* chipset Control3 */
-	rc = pci_read_config_byte(dev, 0x46, &time);
-	p += sprintf(p, "Read DMA FIFO flush:   %s                     %s\n",
-			(time & 0x80)	? "on " : "off",
-			(time & 0x40)	? "on " : "off" );
-	p += sprintf(p, "End Sect. FIFO flush:  %s                     %s\n",
-			(time & 0x20)	? "on " : "off",
-			(time & 0x10)	? "on " : "off" );
-	p += sprintf(p, "Max DRDY Pulse Width:  %s %s\n",
-			control3_str[(time & 0x03)],
-			(time & 0x03) ? "PCI clocks" : "" );
- 
-	/* Primary and Secondary sector sizes */
-	rc = pci_read_config_word(dev, 0x60, &size0);
-	rc = pci_read_config_word(dev, 0x68, &size1);
-	p += sprintf(p, "Bytes Per Sector:      %03d                     %03d\n",
-			size0 & 0xfff,
-			size1 & 0xfff );
-
-	return (char *)p;
-}
-
-static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev)
-{
-	byte t;
-	int rc;
-	char *p = buf;  
-	unsigned short c;
-	byte l, l_max;   
- 
-	rc = pci_read_config_word(dev, 0x04, &c);
-	rc = pci_read_config_byte(dev, 0x44, &t);
-	rc = pci_read_config_byte(dev, 0x0d, &l);
-	rc = pci_read_config_byte(dev, 0x3f, &l_max);
-
-	p += sprintf(p, "Command register = 0x%x\n", c);
-	p += sprintf(p, "Master Read  Cycle IRDY %d Wait State\n",
-			(t & 64) >>6 );
-	p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n",
-			(t & 32) >> 5 );
-	p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n",
-			(t & 16) ? "on " : "off" );
-	p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n",
-			(t & 8) ? "on " : "off" );
-	p += sprintf(p, "Latency timer = %d (max. = %d)\n",
-			l, l_max);
-
-	return (char *)p;
-}
- 
-static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev)
-{
-	byte t;
-	int rc;
-	char *p = buf;  
-	rc = pci_read_config_byte(dev, 0x45, &t);
-	p += sprintf(p, "Interrupt Steering Swap: %s\n",
-			(t & 64) ? "on ":"off" );
-
-	return (char *)p;
-}
- 
-static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev,
-						unsigned short n)
-{
-	/*
-	 * at that point we can be sure that register 0x20 of the
-	 * chipset contains the right address...
-	 */
-	unsigned int bibma;
-	int rc;
-	byte c0, c1;    
-	char *p = buf; 
- 
-	rc = pci_read_config_dword(dev, 0x20, &bibma);
-	bibma = (bibma & 0xfff0) ;
- 
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb((unsigned short)bibma + 0x02);
-	c1 = inb((unsigned short)bibma + 0x0a);
- 
-	if (n == 0) {
-        /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/
-		p += sprintf(p, "both channels togth:   %s                     %s\n",
-				(c0&0x80) ? "no" : "yes",
-				(c1&0x80) ? "no" : "yes" );
-	} else {
-        /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/
-		p += sprintf(p, "DMA enabled:    %s         %s          %s         %s\n",
-				(c0&0x20) ? "yes" : "no ",
-				(c0&0x40) ? "yes" : "no ",
-				(c1&0x20) ? "yes" : "no ",
-				(c1&0x40) ? "yes" : "no " );
-	}
- 
-	return (char *)p;
-}
-
-static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
-{
-	/*
-	 * print what /proc/via displays,
-	 * if required from DISPLAY_APOLLO_TIMINGS
-	 */
-	char *p = buffer;
-	/* Parameter of chipset : */
-
-	/* Miscellaneous control 1 */
-	p = print_apollo_chipset_control1(buffer, bmide_dev);
-
-	/* Miscellaneous control 2 */
-	p = print_apollo_chipset_control2(p, bmide_dev);
-	/* Parameters of drives: */
-
-	/* Header */
-	p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n");
-	p = print_apollo_chipset_control3(p, bmide_dev, 0);
-	p = print_apollo_ide_config(p, bmide_dev);
-	p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n");
-	p = print_apollo_chipset_control3(p, bmide_dev, 1);
-	p = print_apollo_drive_config(p, bmide_dev);
- 
-	return p-buffer;	/* hoping it is less than 4K... */
-}
-
-#endif  /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte fifoconfig = 0;
-static byte newfifo = 0;
-
-/* Used to just intialize once Fifo configuration */
-static short int done = 0;
-
-/*
- *  Set VIA Chipset Timings for (U)DMA modes enabled.
- *
- *  VIA Apollo chipset has complete support for
- *  setting up the timing parameters.
- */
-static void set_via_timings (ide_hwif_t *hwif)
-{
-	struct pci_dev  *dev = hwif->pci_dev;
-	byte post  = hwif->channel ? 0x30 : 0xc0;
-	byte flush = hwif->channel ? 0x50 : 0xa0;
-	int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) :
-				   (((newfifo & 0x60) == 0x60) ? 1 : 0);
-	byte via_config = 0;
-	int rc = 0, errors = 0;
-
-	printk("%s: VIA Bus-Master ", hwif->name);
-
-	/*
-	 * setting IDE read prefetch buffer and IDE post write buffer.
-	 * (This feature allows prefetched reads and post writes).
-	 */
-	if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) 
-		errors++;
-
-	if (mask) {
-		if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post)))
-			errors++;
-	} else {
-		if ((rc = pci_write_config_byte(dev, 0x41, via_config | post)))
-			errors++;
-	}
-
-	/*
-	 * setting Channel read and End-of-sector FIFO flush.
-	 * (This feature ensures that FIFO flush is enabled:
-         *  - for read DMA when interrupt asserts the given channel.
-         *  - at the end of each sector for the given channel.)
-	 */
-	if ((rc = pci_read_config_byte(dev, 0x46, &via_config)))
-		errors++;
-
-	if (mask) {
-		if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush)))
-			errors++;
-	} else {
-		if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush)))
-			errors++;
-	}
-
-	if (!hwif->dma_base)
-		printk("Config %s. No DMA Enabled\n",
-			errors ? "ERROR":"Success");
-	else
-		printk("(U)DMA Timing Config %s\n",
-			errors ? "ERROR" : "Success");
-}
-
-/*
- *  Sets VIA 82c586 FIFO configuration:
- *  This chipsets gets a splitable fifo. This can be driven either by command
- *  line option (eg "splitfifo=2,2,3" which asks this driver to switch all the 
- *  16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma 
- *  triggering.
- */
-
-static int via_set_fifoconfig(ide_hwif_t *hwif)
-{
-	byte fifo;
-	unsigned int timings;
-	struct pci_dev  *dev = hwif->pci_dev;
-
-	/* read port configuration */
-	if (pci_read_config_dword(dev, 0x40, &timings))
-		return 1;
-   
-	/* first read actual fifo config: */
-	if (pci_read_config_byte(dev, 0x43, &fifo))
-		return 1;
-
-	/* keep 4 and 7 bit as they seem to differ between chipsets flavors... */
-	newfifo = fifo & 0x90;
-
-	if (fifoconfig) {
-		/* we received a config request from kernel command line: */
-		newfifo |= fifoconfig & 0x6f;
-	} else {
-		/* If ever just one channel is unused, allocate all fifo levels to it
-		 * and give it a 3/4 threshold for (u)dma transfers.
-		 * Otherwise, share it evenly between channels:
-		 */
-		if ((timings & 3) == 2) {
-			/* only primary channel is  enabled
-			 * 16 buf. to prim. chan. thresh=3/4
-			 */
-			newfifo |= 0x06;
-		} else if ((timings & 3) == 1) {
-			/* only secondary channel is enabled!
-			 * 16 buffers to sec. ch. thresh=3/4
-			 */
-			newfifo |= 0x69;
-		} else {
-			/* fifo evenly distributed: */
-			newfifo |= 0x2a;
-		}
-	}
-
-	/* write resulting configuration to chipset: */
-	if (pci_write_config_byte(dev, 0x43, newfifo))
-		return 1;
-
-	/* and then reread it to get the actual one */
-	if (pci_read_config_byte(dev, 0x43, &newfifo))
-		return 1;
-
-	/* print a kernel report: */
-	printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n",
-		((newfifo & 0x60) == 0x60)	? " 0" :
-		((newfifo & 0x60)		? " 8" : "16"),
-		!(newfifo & 0x0c)		? "1" :
-		(!(newfifo & 0x08)		? "3/4" :
-		(newfifo & 0x04)		? "1/4" : "1/2"));
-
-	printk("                          %s Second. buffers, threshold = %s\n",
-		((newfifo & 0x60) == 0x60)	? "16" :
-		((newfifo & 0x60)		? " 8" : " 0"),
-		!(newfifo & 0x03)		? "1" :
-		(!(newfifo & 0x02)		? "3/4" :
-		(newfifo & 0x01)		? "1/4" : "1/2"));
-
-#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
-	bmide_dev = hwif->pci_dev;
-	via_display_info = &via_get_info;
-#endif /* DISPLAY_VIA_TIMINGS &&  CONFIG_PROC_FS*/
-	return 0;
-}
-
-unsigned int __init pci_init_via82c568 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *host;
-	struct pci_dev *isa;
-
-	byte revision = 0;
-
-	for (host = pci_devices; host; host=host->next) {
-		if (host->vendor == PCI_VENDOR_ID_VIA &&
-		    host->device == PCI_DEVICE_ID_VIA_82C585) {
-			host_dev = host;
-			printk("VT 82C585 Apollo VP1/VPX");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
-					isa_dev = isa;
-					pci_read_config_byte(isa_dev, 0x0d, &revision);
-					if (revision >= 0x20)
-						printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-		} else if (host->vendor == PCI_VENDOR_ID_VIA &&
-			   host->device == PCI_DEVICE_ID_VIA_82C595) {
-			host_dev = host;
-			printk("VT 82C595 Apollo VP2");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
-					isa_dev = isa;
-					pci_read_config_byte(isa_dev, 0x0d, &revision);
-					if (revision >= 0x20)
-						printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-		} else if (host->vendor == PCI_VENDOR_ID_VIA &&
-			   host->device == PCI_DEVICE_ID_VIA_82C597_0) {
-			host_dev = host;
-			printk("VT 82C597 Apollo VP3");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
-					isa_dev = isa;
-					pci_read_config_byte(isa_dev, 0x0d, &revision);
-					if (revision >= 0x20)
-						printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-	} else if (host->vendor == PCI_VENDOR_ID_VIA &&
-		   host->device == PCI_DEVICE_ID_VIA_82C598_0) {
-			host_dev = host;
-			printk("VT 82C598 Apollo MVP3");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
-					isa_dev = isa;
-					pci_read_config_byte(isa_dev, 0x0d, &revision);
-					if (revision >= 0x20)
-						printk(" Chipset Core ATA-33");
-					break;
-				} else if (isa->vendor == PCI_VENDOR_ID_VIA &&
-					   isa->device == PCI_DEVICE_ID_VIA_82C596) {
-					isa_dev = isa;
-					printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-	} else if (host->vendor == PCI_VENDOR_ID_VIA &&
-		   host->device == PCI_DEVICE_ID_VIA_82C680) {
-			host_dev = host;
-			printk("VT 82C680 Apollo P6");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C586_1) {
-					isa_dev = isa;
-					pci_read_config_byte(isa_dev, 0x0d, &revision);
-					if (revision >= 0x20)
-						printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-	} else if (host->vendor == PCI_VENDOR_ID_VIA &&
-		   host->device == PCI_DEVICE_ID_VIA_82C691) {
-			host_dev = host;
-			printk("VT 82C691 Apollo Pro");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C596) {
-					isa_dev = isa;
-					printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-	} else if (host->vendor == PCI_VENDOR_ID_VIA &&
-		   host->device == PCI_DEVICE_ID_VIA_82C693) {
-			host_dev = host;
-			printk("VT 82C693 Apollo Pro Plus");
-			for (isa = pci_devices; isa; isa=isa->next) {
-				if (isa->vendor == PCI_VENDOR_ID_VIA &&
-				    isa->device == PCI_DEVICE_ID_VIA_82C596) {
-					isa_dev = isa;
-					printk(" Chipset Core ATA-33");
-					break;
-				}
-			}
-			printk("\n");
-			break;
-		}
-	}
-	return 0;
-}
-
-void __init ide_init_via82c586 (ide_hwif_t *hwif)
-{
-	set_via_timings(hwif);
-}
-
-/*
- *  ide_dmacapable_via82c568(ide_hwif_t *, unsigned long)
- *  checks if channel "channel" of if hwif is dma
- *  capable or not, according to kernel command line,
- *  and the new fifo settings.
- *  It calls "ide_setup_dma" on capable mainboards, and
- *  bypasses the setup if not capable.
- */
-
-void ide_dmacapable_via82c586 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if (!done) {
-		via_set_fifoconfig(hwif);
-		done = 1;
-	}
-
-	/*
-	 * check if any fifo is available for requested port:
-	 */
-	if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) ||
-	    ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) {
-		printk("    %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name);
-	} else {
-		ide_setup_dma(hwif, dmabase, 8);
-	}
-}
diff -u --recursive --new-file v2.3.22/linux/drivers/block/via82cxxx.c linux/drivers/block/via82cxxx.c
--- v2.3.22/linux/drivers/block/via82cxxx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/via82cxxx.c	Mon Oct 18 11:14:22 1999
@@ -0,0 +1,572 @@
+/*
+ * linux/drivers/block/via82cxxx.c	Version 0.05	Sept. 03, 1999
+ *
+ *  Copyright (C) 1998-99 Michel Aubry, Maintainer
+ *  Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@pobox.com)
+ *  Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  The VIA MVP-4 is reported OK with UDMA.
+ *  The VIA MVP-3 is reported OK with UDMA.
+ *  The TX Pro III is also reported OK with UDMA.
+ *
+ *  VIA chips also have a single FIFO, with the same 64 bytes deep
+ *  buffer (16 levels of 4 bytes each).
+ *
+ *  However, VIA chips can have the buffer split either 8:8 levels,
+ *  16:0 levels or 0:16 levels between both channels. One could think
+ *  of using this feature, as even if no level of FIFO is given to a
+ *  given channel, one can for instance always reach ATAPI drives through
+ *  it, or, if one channel is unused, configuration defaults to
+ *  an even split FIFO levels.
+ *  
+ *  This feature is available only through a kernel command line :
+ *		"splitfifo=Chan,Thr0,Thr1" or "splitfifo=Chan".
+ *		where:  Chan =1,2,3 or 4 and Thrx = 1,2,3,or 4.
+ *
+ *  If Chan == 1:
+ *	gives all the fifo to channel 0,
+ *	sets its threshold to Thr0/4,
+ *	and disables any dma access to channel 1.
+ *
+ *  If chan == 2:
+ *	gives all the fifo to channel 1,
+ *	sets its threshold to Thr1/4,
+ *	and disables any dma access to channel 0.
+ *
+ *  If chan == 3 or 4:
+ *	shares evenly fifo between channels,
+ *	gives channel 0 a threshold of Thr0/4,
+ *	and channel 1 a threshold of Thr1/4.
+ *
+ *  Note that by default (if no command line is provided) and if a channel
+ *  has been disabled in Bios, all the fifo is given to the active channel,
+ *  and its threshold is set to 3/4.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+static struct pci_dev *host_dev = NULL;
+static struct pci_dev *isa_dev = NULL;
+
+static const struct {
+	const char *name;
+	unsigned short host_id;
+} ApolloHostChipInfo[] = {
+	{ "VT 82C585 Apollo VP1/VPX",	PCI_DEVICE_ID_VIA_82C585, },
+	{ "VT 82C595 Apollo VP2",	PCI_DEVICE_ID_VIA_82C595, },
+	{ "VT 82C597 Apollo VP3",	PCI_DEVICE_ID_VIA_82C597_0, },
+	{ "VT 82C598 Apollo MVP3",	PCI_DEVICE_ID_VIA_82C598_0, },
+	{ "VT 82C680 Apollo P6",	PCI_DEVICE_ID_VIA_82C680, },
+	{ "VT 82C691 Apollo Pro",	PCI_DEVICE_ID_VIA_82C691, },
+	{ "VT 82C693 Apollo Pro Plus",	PCI_DEVICE_ID_VIA_82C693, },
+	{ "Apollo MVP4",		PCI_DEVICE_ID_VIA_8501_0, },
+};
+
+#define NUM_APOLLO_ISA_CHIP_DEVICES	2
+#define VIA_FLAG_CHECK_REV		0x00000001
+#define VIA_FLAG_ATA_66			0x00000002
+
+static const struct {
+	unsigned short host_id;
+	unsigned short isa_id;
+	unsigned int flags;
+} ApolloISAChipInfo[] = {
+	{ PCI_DEVICE_ID_VIA_82C585,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
+	{ PCI_DEVICE_ID_VIA_82C595,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
+	{ PCI_DEVICE_ID_VIA_82C597_0,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
+	{ PCI_DEVICE_ID_VIA_82C598_0,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
+	{ PCI_DEVICE_ID_VIA_82C598_0,	PCI_DEVICE_ID_VIA_82C596,	0 },
+	{ PCI_DEVICE_ID_VIA_82C680,	PCI_DEVICE_ID_VIA_82C586_1,	VIA_FLAG_CHECK_REV },
+	{ PCI_DEVICE_ID_VIA_82C691,	PCI_DEVICE_ID_VIA_82C596,	0 },
+	{ PCI_DEVICE_ID_VIA_82C693,	PCI_DEVICE_ID_VIA_82C596,	0 },
+	{ PCI_DEVICE_ID_VIA_8501_0,	PCI_DEVICE_ID_VIA_82C686,	VIA_FLAG_ATA_66 },
+};
+
+#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char *FIFO_str[] = {
+	" 1 ",
+	"3/4",
+	"1/2",
+	"1/4"
+};
+
+static char *control3_str[] = {
+	"No limitation",
+	"64",
+	"128",
+	"192"
+};
+
+static int via_get_info(char *, char **, off_t, int, int);
+extern int (*via_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */
+static struct pci_dev *bmide_dev;
+
+static char * print_apollo_drive_config (char *buf, struct pci_dev *dev)
+{
+	int rc;
+	unsigned int time;
+	byte tm;
+	char *p = buf;  
+ 
+	/* Drive Timing Control */
+	rc = pci_read_config_dword(dev, 0x48, &time);
+	p += sprintf(p, "Act Pls Width:  %02d          %02d           %02d          %02d\n",
+			((time & 0xf0000000)>>28) + 1,
+			((time & 0xf00000)>>20) + 1,
+			((time & 0xf000)>>12) + 1,
+			((time & 0xf0)>>4) + 1 );
+	p += sprintf(p, "Recovery Time:  %02d          %02d           %02d          %02d\n",
+			((time & 0x0f000000)>>24) + 1,
+			((time & 0x0f0000)>>16) + 1,
+			((time & 0x0f00)>>8) + 1,
+			(time & 0x0f) + 1 );
+ 
+	/* Address Setup Time */
+	rc = pci_read_config_byte(dev, 0x4C, &tm);
+	p += sprintf(p, "Add. Setup T.:  %01dT          %01dT           %01dT          %01dT\n",
+			((tm & 0xc0)>>6) + 1,
+			((tm & 0x30)>>4) + 1,
+			((tm & 0x0c)>>2) + 1,
+			(tm & 0x03) + 1 );
+ 
+	/* UltraDMA33 Extended Timing Control */
+ 	rc = pci_read_config_dword(dev, 0x50, &time);
+ 	p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n");
+ 	p += sprintf(p, "Enable Meth.:    %01d           %01d            %01d           %01d\n",
+			(time & 0x80000000)	? 1 : 0,
+			(time & 0x800000)	? 1 : 0,
+			(time & 0x8000)		? 1 : 0,
+			(time & 0x80)		? 1 : 0 );
+ 	p += sprintf(p, "Enable:         %s         %s          %s         %s\n",
+			(time & 0x40000000)	? "yes" : "no ",
+			(time & 0x400000)	? "yes" : "no ",
+			(time & 0x4000)		? "yes" : "no ",
+			(time & 0x40)		? "yes" : "no " );
+ 	p += sprintf(p, "Transfer Mode: %s         %s          %s         %s\n",
+			(time & 0x20000000)	? "PIO" : "DMA",
+			(time & 0x200000)	? "PIO" : "DMA",
+			(time & 0x2000)		? "PIO" : "DMA",
+			(time & 0x20)		? "PIO" : "DMA" );
+ 	p += sprintf(p, "Cycle Time:     %01dT          %01dT           %01dT          %01dT\n",
+			((time & 0x03000000)>>24) + 2,
+			((time & 0x030000)>>16) + 2,
+			((time & 0x0300)>>8) + 2,
+			(time & 0x03) + 2 );
+ 
+ 	return (char *)p;
+}
+
+static char * print_apollo_ide_config (char *buf, struct pci_dev *dev)
+{
+	byte time, tmp; 
+	unsigned short size0, size1;
+	int rc;
+	char *p = buf;  
+ 
+	rc = pci_read_config_byte(dev, 0x41, &time);
+	p += sprintf(p, "Prefetch Buffer :      %s                     %s\n",
+		(time & 128)	? "on " : "off",
+		(time & 32)	? "on " : "off" );
+	p += sprintf(p, "Post Write Buffer:     %s                     %s\n",
+		(time & 64)	? "on " : "off",
+		(time & 16)	? "on " : "off" );
+ 
+	/* FIFO configuration */
+	rc = pci_read_config_byte(dev, 0x43, &time);
+	tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3);
+	p += sprintf(p, "FIFO Conf/Chan. :      %02d                      %02d\n",
+			16 - tmp, tmp);
+	tmp = (time & 0x0F)>>2;
+	p += sprintf(p, "Threshold Prim. :      %s                     %s\n",
+			FIFO_str[tmp],
+			FIFO_str[time & 0x03] );
+ 
+	/* chipset Control3 */
+	rc = pci_read_config_byte(dev, 0x46, &time);
+	p += sprintf(p, "Read DMA FIFO flush:   %s                     %s\n",
+			(time & 0x80)	? "on " : "off",
+			(time & 0x40)	? "on " : "off" );
+	p += sprintf(p, "End Sect. FIFO flush:  %s                     %s\n",
+			(time & 0x20)	? "on " : "off",
+			(time & 0x10)	? "on " : "off" );
+	p += sprintf(p, "Max DRDY Pulse Width:  %s %s\n",
+			control3_str[(time & 0x03)],
+			(time & 0x03) ? "PCI clocks" : "" );
+ 
+	/* Primary and Secondary sector sizes */
+	rc = pci_read_config_word(dev, 0x60, &size0);
+	rc = pci_read_config_word(dev, 0x68, &size1);
+	p += sprintf(p, "Bytes Per Sector:      %03d                     %03d\n",
+			size0 & 0xfff,
+			size1 & 0xfff );
+
+	return (char *)p;
+}
+
+static char * print_apollo_chipset_control1 (char *buf, struct pci_dev *dev)
+{
+	byte t;
+	int rc;
+	char *p = buf;  
+	unsigned short c;
+	byte l, l_max;   
+ 
+	rc = pci_read_config_word(dev, 0x04, &c);
+	rc = pci_read_config_byte(dev, 0x44, &t);
+	rc = pci_read_config_byte(dev, 0x0d, &l);
+	rc = pci_read_config_byte(dev, 0x3f, &l_max);
+
+	p += sprintf(p, "Command register = 0x%x\n", c);
+	p += sprintf(p, "Master Read  Cycle IRDY %d Wait State\n",
+			(t & 64) >>6 );
+	p += sprintf(p, "Master Write Cycle IRDY %d Wait State\n",
+			(t & 32) >> 5 );
+	p += sprintf(p, "FIFO Output Data 1/2 Clock Advance: %s\n",
+			(t & 16) ? "on " : "off" );
+	p += sprintf(p, "Bus Master IDE Status Register Read Retry: %s\n",
+			(t & 8) ? "on " : "off" );
+	p += sprintf(p, "Latency timer = %d (max. = %d)\n",
+			l, l_max);
+
+	return (char *)p;
+}
+ 
+static char * print_apollo_chipset_control2 (char *buf, struct pci_dev *dev)
+{
+	byte t;
+	int rc;
+	char *p = buf;  
+	rc = pci_read_config_byte(dev, 0x45, &t);
+	p += sprintf(p, "Interrupt Steering Swap: %s\n",
+			(t & 64) ? "on ":"off" );
+
+	return (char *)p;
+}
+ 
+static char * print_apollo_chipset_control3 (char *buf, struct pci_dev *dev,
+						unsigned short n)
+{
+	/*
+	 * at that point we can be sure that register 0x20 of the
+	 * chipset contains the right address...
+	 */
+	unsigned int bibma;
+	int rc;
+	byte c0, c1;    
+	char *p = buf; 
+ 
+	rc = pci_read_config_dword(dev, 0x20, &bibma);
+	bibma = (bibma & 0xfff0) ;
+ 
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+ 
+	if (n == 0) {
+        /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/
+		p += sprintf(p, "both channels togth:   %s                     %s\n",
+				(c0&0x80) ? "no" : "yes",
+				(c1&0x80) ? "no" : "yes" );
+	} else {
+        /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/
+		p += sprintf(p, "DMA enabled:    %s         %s          %s         %s\n",
+				(c0&0x20) ? "yes" : "no ",
+				(c0&0x40) ? "yes" : "no ",
+				(c1&0x20) ? "yes" : "no ",
+				(c1&0x40) ? "yes" : "no " );
+	}
+ 
+	return (char *)p;
+}
+
+static int via_get_info (char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	/*
+	 * print what /proc/via displays,
+	 * if required from DISPLAY_APOLLO_TIMINGS
+	 */
+	char *p = buffer;
+	/* Parameter of chipset : */
+
+	/* Miscellaneous control 1 */
+	p = print_apollo_chipset_control1(buffer, bmide_dev);
+
+	/* Miscellaneous control 2 */
+	p = print_apollo_chipset_control2(p, bmide_dev);
+	/* Parameters of drives: */
+
+	/* Header */
+	p += sprintf(p, "------------------Primary IDE------------Secondary IDE-----\n");
+	p = print_apollo_chipset_control3(p, bmide_dev, 0);
+	p = print_apollo_ide_config(p, bmide_dev);
+	p += sprintf(p, "--------------drive0------drive1-------drive0------drive1----\n");
+	p = print_apollo_chipset_control3(p, bmide_dev, 1);
+	p = print_apollo_drive_config(p, bmide_dev);
+ 
+	return p-buffer;	/* hoping it is less than 4K... */
+}
+
+#endif  /* defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ *  Used to set Fifo configuration via kernel command line:
+ */
+
+byte via_proc = 0;
+byte fifoconfig = 0;
+static byte newfifo = 0;
+
+/* Used to just intialize once Fifo configuration */
+static short int done = 0;
+
+/*
+ *  Set VIA Chipset Timings for (U)DMA modes enabled.
+ *
+ *  VIA Apollo chipset has complete support for
+ *  setting up the timing parameters.
+ */
+static void set_via_timings (ide_hwif_t *hwif)
+{
+	struct pci_dev  *dev = hwif->pci_dev;
+	byte post  = hwif->channel ? 0x30 : 0xc0;
+	byte flush = hwif->channel ? 0x50 : 0xa0;
+	int mask = hwif->channel ? ((newfifo & 0x60) ? 0 : 1) :
+				   (((newfifo & 0x60) == 0x60) ? 1 : 0);
+	byte via_config = 0;
+	int rc = 0, errors = 0;
+
+	printk("%s: VIA Bus-Master ", hwif->name);
+
+	/*
+	 * setting IDE read prefetch buffer and IDE post write buffer.
+	 * (This feature allows prefetched reads and post writes).
+	 */
+	if ((rc = pci_read_config_byte(dev, 0x41, &via_config))) 
+		errors++;
+
+	if (mask) {
+		if ((rc = pci_write_config_byte(dev, 0x41, via_config & ~post)))
+			errors++;
+	} else {
+		if ((rc = pci_write_config_byte(dev, 0x41, via_config | post)))
+			errors++;
+	}
+
+	/*
+	 * setting Channel read and End-of-sector FIFO flush.
+	 * (This feature ensures that FIFO flush is enabled:
+	 *  - for read DMA when interrupt asserts the given channel.
+	 *  - at the end of each sector for the given channel.)
+	 */
+	if ((rc = pci_read_config_byte(dev, 0x46, &via_config)))
+		errors++;
+
+	if (mask) {
+		if ((rc = pci_write_config_byte(dev, 0x46, via_config & ~flush)))
+			errors++;
+	} else {
+		if ((rc = pci_write_config_byte(dev, 0x46, via_config | flush)))
+			errors++;
+	}
+
+	if (!hwif->dma_base)
+		printk("Config %s. No DMA Enabled\n",
+			errors ? "ERROR":"Success");
+	else
+		printk("(U)DMA Timing Config %s\n",
+			errors ? "ERROR" : "Success");
+}
+
+/*
+ *  Sets VIA 82cxxx FIFO configuration:
+ *  This chipsets gets a splitable fifo. This can be driven either by command
+ *  line option (eg "splitfifo=2,2,3" which asks this driver to switch all the 
+ *  16 fifo levels to the second drive, and give it a threshold of 3 for (u)dma 
+ *  triggering.
+ */
+
+static int via_set_fifoconfig(ide_hwif_t *hwif)
+{
+	byte fifo;
+	unsigned int timings;
+	struct pci_dev  *dev = hwif->pci_dev;
+
+	/* read port configuration */
+	if (pci_read_config_dword(dev, 0x40, &timings))
+		return 1;
+   
+	/* first read actual fifo config: */
+	if (pci_read_config_byte(dev, 0x43, &fifo))
+		return 1;
+
+	/* keep 4 and 7 bit as they seem to differ between chipsets flavors... */
+	newfifo = fifo & 0x90;
+
+	if (fifoconfig) {
+		/* we received a config request from kernel command line: */
+		newfifo |= fifoconfig & 0x6f;
+	} else {
+		/* If ever just one channel is unused, allocate all fifo levels to it
+		 * and give it a 3/4 threshold for (u)dma transfers.
+		 * Otherwise, share it evenly between channels:
+		 */
+		if ((timings & 3) == 2) {
+			/* only primary channel is  enabled
+			 * 16 buf. to prim. chan. thresh=3/4
+			 */
+			newfifo |= 0x06;
+		} else if ((timings & 3) == 1) {
+			/* only secondary channel is enabled!
+			 * 16 buffers to sec. ch. thresh=3/4
+			 */
+			newfifo |= 0x69;
+		} else {
+			/* fifo evenly distributed: */
+			newfifo |= 0x2a;
+		}
+	}
+
+	/* write resulting configuration to chipset: */
+	if (pci_write_config_byte(dev, 0x43, newfifo))
+		return 1;
+
+	/* and then reread it to get the actual one */
+	if (pci_read_config_byte(dev, 0x43, &newfifo))
+		return 1;
+
+	/* print a kernel report: */
+	printk("Split FIFO Configuration: %s Primary buffers, threshold = %s\n",
+		((newfifo & 0x60) == 0x60)	? " 0" :
+		((newfifo & 0x60)		? " 8" : "16"),
+		!(newfifo & 0x0c)		? "1" :
+		(!(newfifo & 0x08)		? "3/4" :
+		(newfifo & 0x04)		? "1/4" : "1/2"));
+
+	printk("                          %s Second. buffers, threshold = %s\n",
+		((newfifo & 0x60) == 0x60)	? "16" :
+		((newfifo & 0x60)		? " 8" : " 0"),
+		!(newfifo & 0x03)		? "1" :
+		(!(newfifo & 0x02)		? "3/4" :
+		(newfifo & 0x01)		? "1/4" : "1/2"));
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+	via_proc = 1;
+	bmide_dev = hwif->pci_dev;
+	via_display_info = &via_get_info;
+#endif /* DISPLAY_VIA_TIMINGS &&  CONFIG_PROC_FS*/
+	return 0;
+}
+
+unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *host;
+	struct pci_dev *isa;
+	int i, j, ata33, ata66;
+
+	byte revision = 0;
+
+	for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) {
+		host = pci_find_device (PCI_VENDOR_ID_VIA,
+					ApolloHostChipInfo[i].host_id,
+					NULL);
+		if (!host)
+			continue;
+
+		host_dev = host;
+		printk(ApolloHostChipInfo[i].name);
+
+		for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) {
+			if (ApolloISAChipInfo[j].host_id !=
+			    ApolloHostChipInfo[i].host_id)
+				continue;
+
+			isa = pci_find_device (PCI_VENDOR_ID_VIA,
+					ApolloISAChipInfo[i].isa_id,
+					NULL);
+			if (!isa)
+				continue;
+
+			isa_dev = isa;
+
+			ata33 = 1;
+			ata66 = 0;
+
+			if (ApolloISAChipInfo[i].flags & VIA_FLAG_CHECK_REV) {
+				pci_read_config_byte(isa_dev, 0x0d, &revision);
+				ata33 = (revision >= 0x20) ? 1 : 0;
+			} else if (ApolloISAChipInfo[i].flags & VIA_FLAG_ATA_66) {
+				ata33 = 0;
+				ata66 = 1;
+			}
+
+			if (ata33 | ata66)
+				printk(" Chipset Core ATA-%s", ata66 ? "66" : "33");
+		}
+		printk("\n");
+	}
+
+	return 0;
+}
+
+unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif)
+{
+	/* (Jeff Garzik) FIXME!!! for MVP4 */
+	return 0;
+}
+
+void __init ide_init_via82cxxx (ide_hwif_t *hwif)
+{
+	set_via_timings(hwif);
+}
+
+/*
+ *  ide_dmacapable_via82c568(ide_hwif_t *, unsigned long)
+ *  checks if channel "channel" of if hwif is dma
+ *  capable or not, according to kernel command line,
+ *  and the new fifo settings.
+ *  It calls "ide_setup_dma" on capable mainboards, and
+ *  bypasses the setup if not capable.
+ */
+
+void ide_dmacapable_via82cxxx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (!done) {
+		via_set_fifoconfig(hwif);
+		done = 1;
+	}
+
+	/*
+	 * check if any fifo is available for requested port:
+	 */
+	if (((hwif->channel == 0) && ((newfifo & 0x60) == 0x60)) ||
+	    ((hwif->channel == 1) && ((newfifo & 0x60) == 0x00))) {
+		printk("    %s: VP_IDE Bus-Master DMA disabled (FIFO setting)\n", hwif->name);
+	} else {
+		ide_setup_dma(hwif, dmabase, 8);
+	}
+}
diff -u --recursive --new-file v2.3.22/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.22/linux/drivers/cdrom/cdrom.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/cdrom/cdrom.c	Tue Oct 19 13:47:40 1999
@@ -177,10 +177,15 @@
   for ide-cd to handle multisession discs.
   -- Export cdrom_mode_sense and cdrom_mode_select.
   -- init_cdrom_command() for setting up a cgc command.
+  
+  3.05 Sep 23, 1999 - Jens Axboe <axboe@image.dk>
+  -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually
+  impossible to send the drive data in a sensible way.
+  
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 3.04"
-#define VERSION "Id: cdrom.c 3.04 1999/09/14"
+#define REVISION "Revision: 3.05"
+#define VERSION "Id: cdrom.c 3.05 1999/09/23"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -213,6 +218,7 @@
 #include <linux/cdrom.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
 #include <asm/fcntl.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
@@ -316,7 +322,7 @@
 	if (cdo->open == NULL || cdo->release == NULL)
 		return -2;
 	if ( !banner_printed ) {
-		printk(KERN_INFO "Uniform CDROM driver " REVISION "\n");
+		printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
 		banner_printed = 1;
 #ifdef CONFIG_SYSCTL
 		cdrom_sysctl_register();
@@ -404,6 +410,8 @@
 	return cdi;
 }
 
+static int cdrom_setup_writemode(struct cdrom_device_info *cdi);
+
 /* We use the open-option O_NONBLOCK to indicate that the
  * purpose of opening is only for subsequent ioctl() calls; no device
  * integrity checks are performed.
@@ -415,22 +423,31 @@
 static
 int cdrom_open(struct inode *ip, struct file *fp)
 {
+	struct cdrom_device_info *cdi;
 	kdev_t dev = ip->i_rdev;
-	struct cdrom_device_info *cdi = cdrom_find_device(dev);
-	int purpose = !!(fp->f_flags & O_NONBLOCK);
-	int ret=0;
+	int ret;
 
 	cdinfo(CD_OPEN, "entering cdrom_open\n"); 
-	if (cdi == NULL)
+	if ((cdi = cdrom_find_device(dev)) == NULL)
 		return -ENODEV;
-	if (fp->f_mode & FMODE_WRITE)
-		return -EROFS;
-	purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
-	if (purpose)
-		ret = cdi->ops->open(cdi, purpose);
+
+	/* just CD-RW for now. DVD-RW will come soon, CD-R and DVD-R
+	 * need to be handled differently. */
+	if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_CD_RW))
+			return -EROFS;
+
+	/* if this was a O_NONBLOCK open and we should honor the flags,
+	 * do a quick open without drive/disc integrity checks. */
+	if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS))
+		ret = cdi->ops->open(cdi, 1);
 	else
 		ret = open_for_data(cdi);
+
 	if (!ret) cdi->use_count++;
+
+	if (fp->f_mode & FMODE_WRITE && !cdi->write.writeable)
+		cdi->write.writeable = !cdrom_setup_writemode(cdi);
+
 	cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count);
 	/* Do this on open.  Don't wait for mount, because they might
 	    not be mounting, but opening with O_NONBLOCK */
@@ -525,7 +542,7 @@
 	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
 			cdo->lock_door(cdi, 1);
 			cdinfo(CD_OPEN, "door locked.\n");
-	}	
+	}
 	cdinfo(CD_OPEN, "device opened successfully.\n"); 
 	return ret;
 
@@ -616,7 +633,7 @@
 	if (cdi->use_count > 0) cdi->use_count--;
 	if (cdi->use_count == 0)
 		cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
-	if (cdi->use_count == 0 &&      /* last process that closes dev*/
+	if (cdi->use_count == 0 &&
 	    cdo->capability & CDC_LOCK && !keeplocked) {
 		cdinfo(CD_CLOSE, "Unlocking door!\n");
 		cdo->lock_door(cdi, 0);
@@ -1701,8 +1718,8 @@
 		     unsigned long arg)
 {		
 	struct cdrom_device_ops *cdo = cdi->ops;
-	kdev_t dev = cdi->dev;
 	struct cdrom_generic_command cgc;
+	kdev_t dev = cdi->dev;
 	char buffer[32];
 	int ret = 0;
 
@@ -1919,7 +1936,7 @@
 
 	case CDROMSTART:
 	case CDROMSTOP: {
-		cdinfo(CD_DO_IOCTL, "entering audio ioctl (start/stop)\n"); 
+		cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); 
 		cgc.cmd[0] = GPCMD_START_STOP_UNIT;
 		cgc.cmd[1] = 1;
 		cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
@@ -1928,7 +1945,7 @@
 
 	case CDROMPAUSE:
 	case CDROMRESUME: {
-		cdinfo(CD_DO_IOCTL, "entering audio ioctl (pause/resume)\n"); 
+		cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 
 		cgc.cmd[0] = GPCMD_PAUSE_RESUME;
 		cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
 		return cdo->generic_packet(cdi, &cgc);
@@ -1938,7 +1955,7 @@
 		dvd_struct s;
 		if (!CDROM_CAN(CDC_DVD))
 			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering dvd_read_struct\n"); 
+		cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); 
 		IOCTL_IN(arg, dvd_struct, s);
 		if ((ret = dvd_read_struct(cdi, &s)))
 			return ret;
@@ -1950,7 +1967,7 @@
 		dvd_authinfo ai;
 		if (!CDROM_CAN(CDC_DVD))
 			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering dvd_auth\n"); 
+		cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); 
 		IOCTL_IN(arg, dvd_authinfo, ai);
 		if ((ret = dvd_do_auth (cdi, &ai)))
 			return ret;
@@ -1959,26 +1976,58 @@
 		}
 
 	case CDROM_SEND_PACKET: {
+		__u8 *userbuf, copy = 0;
 		if (!CDROM_CAN(CDC_GENERIC_PACKET))
 			return -ENOSYS;
-		cdinfo(CD_DO_IOCTL, "entering send_packet\n"); 
+		cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n"); 
 		IOCTL_IN(arg, struct cdrom_generic_command, cgc);
-		cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
+		copy = !!cgc.buflen;
+		userbuf = cgc.buffer;
+		cgc.buffer = NULL;
+		if (userbuf != NULL && copy) {
+			/* usually commands just copy data one way, i.e.
+			 * we send a buffer to the drive and the command
+			 * specifies whether the drive will read or
+			 * write to that buffer. usually the buffers
+			 * are very small, so we don't loose that much
+			 * by doing a redundant copy each time. */
+			if (!access_ok(VERIFY_WRITE, userbuf, cgc.buflen)) {
+				printk("can't get write perms\n");
+				return -EFAULT;
+			}
+			if (!access_ok(VERIFY_READ, userbuf, cgc.buflen)) {
+				printk("can't get read perms\n");
+				return -EFAULT;
+			}
+		}
+		/* reasonable limits */
+		if (cgc.buflen < 0 || cgc.buflen > 131072) {
+			printk("invalid size given\n");
+			return -EINVAL;
+		}
+		if (copy) {
+			cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
+			if (cgc.buffer == NULL)
+				return -ENOMEM;
+			__copy_from_user(cgc.buffer, userbuf, cgc.buflen);
+		}
 		ret = cdo->generic_packet(cdi, &cgc);
-		if (copy_to_user((void*)arg, cgc.buffer, cgc.buflen))
-			ret = -EFAULT;
+		if (copy && !ret)
+			__copy_to_user(userbuf, cgc.buffer, cgc.buflen);
 		kfree(cgc.buffer);
 		return ret;
 		}
 	case CDROM_NEXT_WRITABLE: {
-		long next;
+		long next = 0;
+		cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); 
 		if ((ret = cdrom_get_next_writable(dev, &next)))
 			return ret;
 		IOCTL_OUT(arg, long, next);
 		return 0;
 		}
 	case CDROM_LAST_WRITTEN: {
-		long last;
+		long last = 0;
+		cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); 
 		if ((ret = cdrom_get_last_written(dev, &last)))
 			return ret;
 		IOCTL_OUT(arg, long, last);
@@ -2038,10 +2087,10 @@
 	track_information ti;
 	__u32 last_track;
 	int ret = -1;
-	
+
 	if (!CDROM_CAN(CDC_GENERIC_PACKET))
 		goto use_toc;
-	
+
 	if ((ret = cdrom_get_disc_info(dev, &di)))
 		goto use_toc;
 
@@ -2089,7 +2138,7 @@
 	track_information ti;
 	__u16 last_track;
 	int ret = -1;
-	
+
 	if (!CDROM_CAN(CDC_GENERIC_PACKET))
 		goto use_last_written;
 
@@ -2125,6 +2174,99 @@
 	}
 }
 
+/* return the buffer size of writeable drives */
+static int cdrom_read_buffer_capacity(struct cdrom_device_info *cdi)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+	struct cdrom_generic_command cgc;
+	struct {
+		unsigned int pad;
+		unsigned int buffer_size;
+		unsigned int buffer_free;
+	} buf;
+	int ret;
+
+	init_cdrom_command(&cgc, &buf, 12);
+	cgc.cmd[0] = 0x5c;
+	cgc.cmd[8] = 12;
+
+	if ((ret = cdo->generic_packet(cdi, &cgc)))
+		return ret;
+	
+	return be32_to_cpu(buf.buffer_size);
+}
+
+/* return 0 if succesful and the disc can be considered writeable. */
+static int cdrom_setup_writemode(struct cdrom_device_info *cdi)
+{
+	struct cdrom_generic_command cgc;
+	write_param_page wp;
+	disc_information di;
+	track_information ti;
+	int ret, last_track;
+
+	memset(&di, 0, sizeof(disc_information));
+	memset(&ti, 0, sizeof(track_information));
+	memset(&wp, 0, sizeof(write_param_page));
+	memset(&cdi->write, 0, sizeof(struct cdrom_write_settings));
+
+	if ((ret = cdrom_get_disc_info(cdi->dev, &di)))
+		return ret;
+
+	last_track = (di.last_track_msb << 8) | di.last_track_lsb;
+	if ((ret = cdrom_get_track_info(cdi->dev, last_track, 1, &ti)))
+		return ret;
+
+	/* if the media is erasable, then it is either CD-RW or
+	 * DVD-RW - use fixed packets for those. non-erasable media
+	 * indicated CD-R or DVD-R media, use varible sized packets for
+	 * those (where the packet size is a bit less than the buffer
+	 * capacity of the drive. */
+	if (di.erasable) {
+		cdi->write.fpacket = 1;
+		/* FIXME: DVD-RW is 16, should get the packet size instead */
+		cdi->write.packet_size = 32;
+	} else {
+		int buf_size;		
+		cdi->write.fpacket = 0;
+		buf_size = cdrom_read_buffer_capacity(cdi);
+		buf_size -= 100*1024;
+		cdi->write.packet_size = buf_size / CD_FRAMESIZE;
+	}
+
+	init_cdrom_command(&cgc, &wp, 0x3c);
+	if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_WRITE_PARMS_PAGE, 0)))
+		return ret;
+
+	/* sanity checks */
+	if ((ti.damage && !ti.nwa_v) || ti.blank) {
+		cdinfo(CD_WARNING, "can't write to this disc\n"); 
+		return 1;
+	}
+
+	/* NWA is only for CD-R and DVD-R. -RW media is randomly
+	 * writeable once it has been formatted. */
+	cdi->write.nwa = ti.nwa_v ? be32_to_cpu(ti.next_writable) : 0;
+
+	wp.fp			= cdi->write.fpacket ? 1 : 0;
+	wp.track_mode		= 0;
+	wp.write_type		= 0;
+	wp.data_block_type 	= 8;
+	wp.session_format 	= 0;
+	wp.multi_session	= 3;
+	wp.audio_pause		= cpu_to_be16(0x96);
+	wp.packet_size		= cdi->write.fpacket ? cpu_to_be32(cdi->write.packet_size) : 0;
+	wp.track_mode		= 5; /* should be ok with both CD and DVD */
+
+	if ((ret = cdrom_mode_select(cdi, &cgc)))
+		return ret;
+
+	cdinfo(CD_WARNING, "%s: writeable with %lu block %s packets\n",
+				cdi->name, cdi->write.packet_size,
+				cdi->write.fpacket ? "fixed" : "variable");
+	return 0;
+}
+
 EXPORT_SYMBOL(cdrom_get_next_writable);
 EXPORT_SYMBOL(cdrom_get_last_written);
 EXPORT_SYMBOL(cdrom_count_tracks);
@@ -2384,22 +2526,22 @@
 
 	initialized = 1;
 }
+#endif /* endif CONFIG_SYSCTL */
+
 
 #ifdef MODULE
 static void cdrom_sysctl_unregister(void)
 {
+#ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(cdrom_sysctl_header);
+#endif
 }
-#endif /* endif MODULE */
-#endif /* endif CONFIG_SYSCTL */
-
-#ifdef MODULE
 
 int init_module(void)
 {
 #ifdef CONFIG_SYSCTL
 	cdrom_sysctl_register();
-#endif /* CONFIG_SYSCTL */ 
+#endif
 	return 0;
 }
 
@@ -2410,5 +2552,5 @@
 	cdrom_sysctl_unregister();
 #endif /* CONFIG_SYSCTL */ 
 }
-
 #endif /* endif MODULE */
+
diff -u --recursive --new-file v2.3.22/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.22/linux/drivers/char/Config.in	Fri Oct 15 15:25:13 1999
+++ linux/drivers/char/Config.in	Fri Oct 15 23:37:34 1999
@@ -10,15 +10,15 @@
 fi
 tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
 if [ "$CONFIG_SERIAL" = "y" ]; then
-   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
 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 on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
-   bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
-   bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
+   bool '  Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
+   bool '  Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+   bool '  Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
+   bool '  Support special multiport boards' CONFIG_SERIAL_MULTIPORT
+   bool '  Support the Bell Technologies HUB6 card' CONFIG_HUB6
 fi
 bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
 if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
@@ -86,31 +86,31 @@
 if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
   bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
   if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
-    comment '   Edit configuration parameters in ./include/linux/tpqic02.h!'
+    comment '  Edit configuration parameters in ./include/linux/tpqic02.h!'
   else
-    comment '   Setting runtime QIC-02 configuration is done with qic02conf'
-    comment '   from the tpqic02-support package.  It is available at'
-    comment '   metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
+    comment '  Setting runtime QIC-02 configuration is done with qic02conf'
+    comment '  from the tpqic02-support package.  It is available at'
+    comment '  metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
   fi
   dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV
-  dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
+  dep_tristate '  Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
 fi
 
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
   mainmenu_option next_comment
   comment 'Watchdog Cards'
-  bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
-  tristate '   WDT Watchdog timer' CONFIG_WDT
+  bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+  tristate '  WDT Watchdog timer' CONFIG_WDT
   if [ "$CONFIG_WDT" != "n" ]; then
-     bool '       WDT501 features' CONFIG_WDT_501
+     bool '    WDT501 features' CONFIG_WDT_501
      if [ "$CONFIG_WDT_501" = "y" ]; then
-         bool '       Fan Tachometer' CONFIG_WDT_501_FAN
+         bool '      Fan Tachometer' CONFIG_WDT_501_FAN
      fi
   fi
-  tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
-  tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
-  tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+  tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG
+  tristate '  Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
+  tristate '  Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
   endmenu
 fi
 
diff -u --recursive --new-file v2.3.22/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.22/linux/drivers/char/Makefile	Fri Sep 10 23:57:29 1999
+++ linux/drivers/char/Makefile	Mon Oct 18 11:26:31 1999
@@ -117,7 +117,7 @@
 endif
 
 ifeq ($(CONFIG_COMPUTONE),y)
-L_OBJS += ip2.o ip2main.o
+O_OBJS += ip2.o ip2main.o
 else
   ifeq ($(CONFIG_COMPUTONE),m)
   M_OBJS += ip2.o ip2main.o
@@ -165,7 +165,7 @@
 endif
 
 ifeq ($(CONFIG_SX),y)
-L_OBJS += sx.o generic_serial.o
+O_OBJS += sx.o generic_serial.o
 else
   ifeq ($(CONFIG_SX),m)
   M_OBJS += sx.o
diff -u --recursive --new-file v2.3.22/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.3.22/linux/drivers/char/console.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/char/console.c	Tue Oct 19 10:22:20 1999
@@ -94,6 +94,7 @@
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
 #endif
+#include <linux/bootmem.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -2286,7 +2287,7 @@
 struct tty_driver console_driver;
 static int console_refcount;
 
-unsigned long __init con_init(unsigned long kmem_start)
+void __init con_init(void)
 {
 	const char *display_desc = NULL;
 	unsigned int currcons = 0;
@@ -2295,7 +2296,7 @@
 		display_desc = conswitchp->con_startup();
 	if (!display_desc) {
 		fg_console = 0;
-		return kmem_start;
+		return;
 	}
 
 	memset(&console_driver, 0, sizeof(struct tty_driver));
@@ -2336,19 +2337,18 @@
 		timer_active |= 1<<BLANK_TIMER;
 	}
 
-	/* Unfortunately, kmalloc is not running yet */
-	/* Due to kmalloc roundup allocating statically is more efficient -
-	   so provide MIN_NR_CONSOLES for people with very little memory */
+	/*
+	 * kmalloc is not running yet - we use the bootmem allocator.
+	 */
 	for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
 		int j, k ;
 
-		vc_cons[currcons].d = (struct vc_data *) kmem_start;
-		kmem_start += sizeof(struct vc_data);
-		vt_cons[currcons] = (struct vt_struct *) kmem_start;
-		kmem_start += sizeof(struct vt_struct);
+		vc_cons[currcons].d = (struct vc_data *)
+				alloc_bootmem(sizeof(struct vc_data));
+		vt_cons[currcons] = (struct vt_struct *)
+				alloc_bootmem(sizeof(struct vt_struct));
 		visual_init(currcons, 1);
-		screenbuf = (unsigned short *) kmem_start;
-		kmem_start += screenbuf_size;
+		screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
 		kmalloced = 0;
 		vc_init(currcons, video_num_lines, video_num_columns, 
 			currcons || !sw->con_save_screen);
@@ -2376,8 +2376,6 @@
 #endif
 
 	init_bh(CONSOLE_BH, console_bh);
-	
-	return kmem_start;
 }
 
 #ifndef VT_SINGLE_DRIVER
diff -u --recursive --new-file v2.3.22/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.3.22/linux/drivers/char/istallion.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/char/istallion.c	Mon Oct 18 11:26:31 1999
@@ -34,6 +34,7 @@
 #include <linux/serial.h>
 #include <linux/cdk.h>
 #include <linux/comstats.h>
+#include <linux/version.h>
 #include <linux/istallion.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
diff -u --recursive --new-file v2.3.22/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.22/linux/drivers/char/mem.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/char/mem.c	Thu Oct 21 13:38:12 1999
@@ -158,6 +158,9 @@
 		prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S;
 #elif defined(__mips__)
 	prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
+#elif defined(__arm__) && defined(CONFIG_CPU_32)
+	/* Turn off caching for all I/O areas */
+	prot &= ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE);
 #endif
 
 	return prot;
diff -u --recursive --new-file v2.3.22/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.3.22/linux/drivers/char/n_tty.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/char/n_tty.c	Tue Oct 19 10:22:20 1999
@@ -811,7 +811,7 @@
 
 	if (!tty->read_buf) {
 		tty->read_buf = (unsigned char *)
-			get_free_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+			get_zeroed_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
 		if (!tty->read_buf)
 			return -ENOMEM;
 	}
diff -u --recursive --new-file v2.3.22/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.3.22/linux/drivers/char/pcxx.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/char/pcxx.c	Mon Oct 18 11:26:31 1999
@@ -1589,8 +1589,8 @@
 			ch->blocked_open = 0;
 			ch->callout_termios = pcxe_callout.init_termios;
 			ch->normal_termios = pcxe_driver.init_termios;
-			init_waitqueue_head(ch->open_wait);
-			init_waitqueue_head(ch->close_wait);
+			init_waitqueue_head(&ch->open_wait);
+			init_waitqueue_head(&ch->close_wait);
 			ch->asyncflags = 0;
 		}
 
diff -u --recursive --new-file v2.3.22/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c
--- v2.3.22/linux/drivers/char/radio-cadet.c	Mon Jul  5 20:07:02 1999
+++ linux/drivers/char/radio-cadet.c	Mon Oct 18 11:26:31 1999
@@ -39,6 +39,7 @@
 static __u8 rdsin=0,rdsout=0,rdsstat=0;
 static unsigned char rdsbuf[RDS_BUFFER];
 static int cadet_lock=0;
+static int cadet_probe(void);
 
 /*
  * Signal Strength Threshold Values
diff -u --recursive --new-file v2.3.22/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.22/linux/drivers/char/serial.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/char/serial.c	Tue Oct 19 10:22:20 1999
@@ -1127,7 +1127,7 @@
 	unsigned short ICP;
 #endif
 
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
@@ -2974,7 +2974,7 @@
 #endif
 
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			return -ENOMEM;
 		}
@@ -4359,10 +4359,9 @@
 /*
  *	Register console.
  */
-long __init serial_console_init(long kmem_start, long kmem_end)
+void __init serial_console_init(void)
 {
 	register_console(&sercons);
-	return kmem_start;
 }
 #endif
 
diff -u --recursive --new-file v2.3.22/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.3.22/linux/drivers/char/stallion.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/char/stallion.c	Mon Oct 18 11:26:31 1999
@@ -28,6 +28,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/version.h> /* for linux/stallion.h */
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/tty_flip.h>
diff -u --recursive --new-file v2.3.22/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.22/linux/drivers/char/tty_io.c	Mon Oct 11 15:38:14 1999
+++ linux/drivers/char/tty_io.c	Tue Oct 19 10:22:20 1999
@@ -129,7 +129,7 @@
 extern int sx_init (void);
 #endif
 #ifdef CONFIG_8xx
-extern long console_8xx_init(long, long);
+extern console_8xx_init(void);
 extern int rs_8xx_init(void);
 #endif /* CONFIG_8xx */
 
@@ -798,7 +798,7 @@
 	tp = o_tp = NULL;
 	ltp = o_ltp = NULL;
 
-	tty = (struct tty_struct*) get_free_page(GFP_KERNEL);
+	tty = (struct tty_struct*) get_zeroed_page(GFP_KERNEL);
 	if(!tty)
 		goto fail_no_mem;
 	initialize_tty_struct(tty);
@@ -824,7 +824,7 @@
 	}
 
 	if (driver->type == TTY_DRIVER_TYPE_PTY) {
-		o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+		o_tty = (struct tty_struct *) get_zeroed_page(GFP_KERNEL);
 		if (!o_tty)
 			goto free_mem_out;
 		initialize_tty_struct(o_tty);
@@ -2062,7 +2062,7 @@
  * Just do some early initializations, and do the complex setup
  * later.
  */
-long __init console_init(long kmem_start, long kmem_end)
+void __init console_init(void)
 {
 	/* Setup the default TTY line discipline. */
 	memset(ldiscs, 0, sizeof(ldiscs));
@@ -2085,16 +2085,15 @@
 	 * inform about problems etc..
 	 */
 #ifdef CONFIG_VT
-	kmem_start = con_init(kmem_start);
+	con_init();
 #endif
 #ifdef CONFIG_SERIAL_CONSOLE
 #ifdef CONFIG_8xx
-	kmem_start = console_8xx_init(kmem_start, kmem_end);
+	console_8xx_init();
 #else 	
-	kmem_start = serial_console_init(kmem_start, kmem_end);
+	serial_console_init();
 #endif /* CONFIG_8xx */
 #endif
-	return kmem_start;
 }
 
 static struct tty_driver dev_tty_driver, dev_syscons_driver;
@@ -2109,7 +2108,7 @@
  * Ok, now we can initialize the rest of the tty devices and can count
  * on memory allocations, interrupts etc..
  */
-int __init tty_init(void)
+void __init tty_init(void)
 {
 	if (sizeof(struct tty_struct) > PAGE_SIZE)
 		panic("size of tty structure > PAGE_SIZE!");
@@ -2220,5 +2219,4 @@
 #ifdef CONFIG_VT
 	vcs_init();
 #endif
-	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.3.22/linux/drivers/char/vt.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/vt.c	Thu Oct 21 13:38:12 1999
@@ -61,7 +61,7 @@
  */
 unsigned char keyboard_type = KB_101;
 
-#ifndef __alpha__
+#if !defined(__alpha__) && !defined(__arm__)
 asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
 #endif
 
@@ -89,7 +89,8 @@
  */
 
 #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
-    || (defined(__mips__) && !defined(CONFIG_SGI))
+    || (defined(__mips__) && !defined(CONFIG_SGI)) \
+    || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE))
 
 static void
 kd_nosound(unsigned long ignored)
@@ -470,7 +471,7 @@
 		ucval = keyboard_type;
 		goto setchar;
 
-#ifndef __alpha__
+#if !defined(__alpha__) && !defined(__arm__)
 		/*
 		 * These cannot be implemented on any machine that implements
 		 * ioperm() in user level (such as Alpha PCs).
diff -u --recursive --new-file v2.3.22/linux/drivers/i2o/Config.in linux/drivers/i2o/Config.in
--- v2.3.22/linux/drivers/i2o/Config.in	Mon Oct  4 15:49:29 1999
+++ linux/drivers/i2o/Config.in	Mon Oct 18 11:26:31 1999
@@ -5,7 +5,9 @@
 
 dep_tristate '  I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O
 dep_tristate '  I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O
-dep_tristate '  I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
+if [ "$CONFIG_NET" = "y" ]; then
+   dep_tristate '  I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O
+fi
 dep_tristate '  I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O $CONFIG_SCSI
 dep_tristate '  I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O
 
diff -u --recursive --new-file v2.3.22/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.22/linux/drivers/macintosh/macserial.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/macintosh/macserial.c	Wed Oct 20 22:13:21 1999
@@ -5,6 +5,10 @@
  *
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
+ *
+ * $Id: macserial.c,v 1.24.2.3 1999/09/10 02:05:58 paulus Exp $
  */
 
 #include <linux/config.h>
@@ -26,6 +30,7 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
+#include <linux/slab.h>
 
 #include <asm/init.h>
 #include <asm/io.h>
@@ -41,6 +46,7 @@
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#include <asm/dbdma.h>
 
 #include "macserial.h"
 
@@ -52,6 +58,8 @@
 };
 #endif
 
+#define SUPPORT_SERIAL_DMA
+
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -127,6 +135,13 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int set_scc_power(struct mac_serial * info, int state);
 static int setup_scc(struct mac_serial * info);
+static void dbdma_reset(volatile struct dbdma_regs *dma);
+static void dbdma_flush(volatile struct dbdma_regs *dma);
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void dma_init(struct mac_serial * info);
+static void rxdma_start(struct mac_serial * info, int current);
+static void rxdma_to_tty(struct mac_serial * info);
 
 static struct tty_struct *serial_table[NUM_CHANNELS];
 static struct termios *serial_termios[NUM_CHANNELS];
@@ -288,6 +303,39 @@
 }
 
 /*
+ * Reset a Descriptor-Based DMA channel.
+ */
+static void dbdma_reset(volatile struct dbdma_regs *dma)
+{
+	int i;
+
+	out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
+
+	/*
+	 * Yes this looks peculiar, but apparently it needs to be this
+	 * way on some machines.  (We need to make sure the DBDMA
+	 * engine has actually got the write above and responded
+	 * to it. - paulus)
+	 */
+	for (i = 200; i > 0; --i)
+		if (ld_le32(&dma->control) & RUN)
+			udelay(1);
+}
+
+/*
+ * Tells a DBDMA channel to stop and write any buffered data
+ * it might have to memory.
+ */
+static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
+{
+	int i = 0;
+
+	out_le32(&dma->control, (FLUSH << 16) | FLUSH);
+	while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
+		udelay(1);
+}
+
+/*
  * ----------------------------------------------------------------------
  *
  * Here starts the interrupt handling routines.  All of the following
@@ -310,6 +358,22 @@
 	mark_bh(MACSERIAL_BH);
 }
 
+/* Work out the flag value for a z8530 status value. */
+static _INLINE_ int stat_to_flag(int stat)
+{
+	int flag;
+
+	if (stat & Rx_OVR) {
+		flag = TTY_OVERRUN;
+	} else if (stat & FRM_ERR) {
+		flag = TTY_FRAME;
+	} else if (stat & PAR_ERR) {
+		flag = TTY_PARITY;
+	} else
+		flag = 0;
+	return flag;
+}
+
 static _INLINE_ void receive_chars(struct mac_serial *info,
 				   struct pt_regs *regs)
 {
@@ -347,14 +411,7 @@
 			if (flip_max_cnt < tty->flip.count)
 				flip_max_cnt = tty->flip.count;
 		}
-		if (stat & Rx_OVR) {
-			flag = TTY_OVERRUN;
-		} else if (stat & FRM_ERR) {
-			flag = TTY_FRAME;
-		} else if (stat & PAR_ERR) {
-			flag = TTY_PARITY;
-		} else
-			flag = 0;
+		flag = stat_to_flag(stat);
 		if (flag)
 			/* reset the error indication */
 			write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -450,6 +507,32 @@
 	info->read_reg_zero = status;
 }
 
+static _INLINE_ void receive_special_dma(struct mac_serial *info)
+{
+	unsigned char stat, flag;
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	int where = RX_BUF_SIZE;
+
+	spin_lock(&info->rx_dma_lock);
+	if ((ld_le32(&rd->status) & ACTIVE) != 0)
+		dbdma_flush(rd);
+	if (in_le32(&rd->cmdptr)
+	    == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
+		where -= in_le16(&info->rx->res_count);
+	where--;
+	
+	stat = read_zsreg(info->zs_channel, R1);
+
+	flag = stat_to_flag(stat);
+	if (flag) {
+		info->rx_flag_buf[info->rx_cbuf][where] = flag;
+		/* reset the error indication */
+		write_zsreg(info->zs_channel, 0, ERR_RES);
+	}
+
+	spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * This is the serial driver's generic interrupt routine
  */
@@ -459,6 +542,12 @@
 	unsigned char zs_intreg;
 	int shift;
 
+	if (!(info->flags & ZILOG_INITIALIZED)) {
+		printk("rs_interrupt: irq %d, port not initialized\n", irq);
+		disable_irq(irq);
+		return;
+	}
+
 	/* NOTE: The read register 3, which holds the irq status,
 	 *       does so for both channels on each chip.  Although
 	 *       the status value itself must be read from the A
@@ -475,19 +564,21 @@
 	for (;;) {
 		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
 #ifdef SERIAL_DEBUG_INTR
-		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg);
+		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
+		       irq, (int)zs_intreg);
 #endif	
 
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
-		if (!(info->flags & ZILOG_INITIALIZED)) {
-			printk("rs_interrupt: irq %d, port not initialized\n", irq);
-			break;
+		if (zs_intreg & CHBRxIP) {
+			/* If we are doing DMA, we only ask for interrupts
+			   on characters with errors or special conditions. */
+			if (info->dma_initted)
+				receive_special_dma(info);
+			else
+				receive_chars(info, regs);
 		}
-
-		if (zs_intreg & CHBRxIP)
-			receive_chars(info, regs);
 		if (zs_intreg & CHBTxIP)
 			transmit_chars(info);
 		if (zs_intreg & CHBEXT)
@@ -495,6 +586,39 @@
 	}
 }
 
+/* Transmit DMA interrupt - not used at present */
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+/*
+ * Receive DMA interrupt.
+ */
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mac_serial *info = (struct mac_serial *) dev_id;
+	volatile struct dbdma_cmd *cd;
+
+	if (!info->dma_initted)
+		return;
+	spin_lock(&info->rx_dma_lock);
+	/* First, confirm that this interrupt is, indeed, coming */
+	/* from Rx DMA */
+	cd = info->rx_cmds[info->rx_cbuf] + 2;
+	if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
+		spin_unlock(&info->rx_dma_lock);
+		return;
+	}
+	if (info->rx_fbuf != RX_NO_FBUF) {
+		info->rx_cbuf = info->rx_fbuf;
+		if (++info->rx_fbuf == info->rx_nbuf)
+			info->rx_fbuf = 0;
+		if (info->rx_fbuf == info->rx_ubuf)
+			info->rx_fbuf = RX_NO_FBUF;
+	}
+	spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * -------------------------------------------------------------------
  * Here ends the serial interrupt routines.
@@ -590,10 +714,6 @@
 	}
 }
 
-static void rs_timer(void)
-{
-}
-
 static int startup(struct mac_serial * info, int can_sleep)
 {
 	int delay;
@@ -629,6 +749,10 @@
 
 	info->flags |= ZILOG_INITIALIZED;
 	enable_irq(info->irq);
+	if (info->dma_initted) {
+//		enable_irq(info->tx_dma_irq);
+		enable_irq(info->rx_dma_irq);
+	}
 
 	if (delay) {
 		if (can_sleep) {
@@ -642,6 +766,187 @@
 	return 0;
 }
 
+static _INLINE_ void rxdma_start(struct mac_serial * info, int current)
+{
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	volatile struct dbdma_cmd *cd = info->rx_cmds[current];
+
+//printk(KERN_DEBUG "SCC: rxdma_start\n");
+
+	st_le32(&rd->cmdptr, virt_to_bus(cd));
+	out_le32(&rd->control, (RUN << 16) | RUN);
+}
+
+static void rxdma_to_tty(struct mac_serial *info)
+{
+	struct tty_struct	*tty = info->tty;
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	unsigned long flags;
+	int residue, available, space, do_queue;
+
+	if (!tty)
+		return;
+
+	do_queue = 0;
+	spin_lock_irqsave(&info->rx_dma_lock, flags);
+more:
+	space = TTY_FLIPBUF_SIZE - tty->flip.count;
+	if (!space) {
+		do_queue++;
+		goto out;
+	}
+	residue = 0;
+	if (info->rx_ubuf == info->rx_cbuf) {
+		if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+			dbdma_flush(rd);
+			if (in_le32(&rd->cmdptr)
+			    == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
+				residue = in_le16(&info->rx->res_count);
+		}
+	}
+	available = RX_BUF_SIZE - residue - info->rx_done_bytes;
+	if (available > space)
+		available = space;
+	if (available) {
+		memcpy(tty->flip.char_buf_ptr,
+		       info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       available);
+		memcpy(tty->flip.flag_buf_ptr,
+		       info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       available);
+		tty->flip.char_buf_ptr += available;
+		tty->flip.count += available;
+		tty->flip.flag_buf_ptr += available;
+		memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       0, available);
+		info->rx_done_bytes += available;
+		do_queue++;
+	}
+	if (info->rx_done_bytes == RX_BUF_SIZE) {
+		volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
+
+		if (info->rx_ubuf == info->rx_cbuf)
+			goto out;
+		/* mark rx_char_buf[rx_ubuf] free */
+		st_le16(&cd->command, DBDMA_NOP);
+		cd++;
+		st_le32(&cd->cmd_dep, 0);
+		st_le32((unsigned int *)&cd->res_count, 0);
+		cd++;
+		st_le16(&cd->xfer_status, 0);
+
+		if (info->rx_fbuf == RX_NO_FBUF) {
+			info->rx_fbuf = info->rx_ubuf;
+			if (!(ld_le32(&rd->status) & ACTIVE)) {
+				dbdma_reset(&info->rx->dma);
+				rxdma_start(info, info->rx_ubuf);
+				info->rx_cbuf = info->rx_ubuf;
+			}
+		}
+		info->rx_done_bytes = 0;
+		if (++info->rx_ubuf == info->rx_nbuf)
+			info->rx_ubuf = 0;
+		if (info->rx_fbuf == info->rx_ubuf)
+			info->rx_fbuf = RX_NO_FBUF;
+		goto more;
+	}
+out:
+	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+	if (do_queue)
+		queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static void poll_rxdma(void *private_)
+{
+	struct mac_serial	*info = (struct mac_serial *) private_;
+	unsigned long flags;
+
+	rxdma_to_tty(info);
+	spin_lock_irqsave(&info->rx_dma_lock, flags);
+	mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
+	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+}
+
+static void dma_init(struct mac_serial * info)
+{
+	int i, size;
+	volatile struct dbdma_cmd *cd;
+	unsigned char *p;
+
+//printk(KERN_DEBUG "SCC: dma_init\n");
+
+	info->rx_nbuf = 8;
+
+	/* various mem set up */
+	size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
+		+ (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
+		   + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
+		* info->rx_nbuf;
+	info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
+	if (info->dma_priv == NULL)
+		return;
+	memset(info->dma_priv, 0, size);
+
+	info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
+	info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
+	info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
+	p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
+	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+		info->rx_char_buf[i] = p;
+	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+		info->rx_flag_buf[i] = p;
+
+	/* a bit of DMA programming */
+	cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
+	st_le16(&cd->command, DBDMA_NOP);
+	cd++;
+	st_le16(&cd->req_count, RX_BUF_SIZE);
+	st_le16(&cd->command, INPUT_MORE);
+	st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
+	cd++;
+	st_le16(&cd->req_count, 4);
+	st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+	st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+	st_le32(&cd->cmd_dep, DBDMA_STOP);
+	for (i = 1; i < info->rx_nbuf; i++) {
+		info->rx_cmds[i] = ++cd;
+		st_le16(&cd->command, DBDMA_NOP);
+		cd++;
+		st_le16(&cd->req_count, RX_BUF_SIZE);
+		st_le16(&cd->command, INPUT_MORE);
+		st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
+		cd++;
+		st_le16(&cd->req_count, 4);
+		st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+		st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+		st_le32(&cd->cmd_dep, DBDMA_STOP);
+	}
+	cd++;
+	st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
+	st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
+
+	/* setup DMA to our liking */
+	dbdma_reset(&info->rx->dma);
+	st_le32(&info->rx->dma.intr_sel, 0x10001);
+	st_le32(&info->rx->dma.br_sel, 0x10001);
+	out_le32(&info->rx->dma.wait_sel, 0x10001);
+
+	/* set various flags */
+	info->rx_ubuf = 0;
+	info->rx_cbuf = 0;
+	info->rx_fbuf = info->rx_ubuf + 1;
+	if (info->rx_fbuf == info->rx_nbuf)
+		info->rx_fbuf = RX_NO_FBUF;
+	info->rx_done_bytes = 0;
+
+	/* setup polling */
+	init_timer(&info->poll_dma_timer);
+	info->poll_dma_timer.function = (void *)&poll_rxdma;
+	info->poll_dma_timer.data = (unsigned long)info;
+
+	info->dma_initted = 1;
+}
+
 static int setup_scc(struct mac_serial * info)
 {
 	unsigned long flags;
@@ -667,6 +972,12 @@
 	info->xmit_fifo_size = 1;
 
 	/*
+	 * Reset DMAs
+	 */
+	if (info->has_dma)
+		dma_init(info);
+
+	/*
 	 * Clear the interrupt registers.
 	 */
 	write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -680,7 +991,23 @@
 	/*
 	 * Finally, enable sequencing and interrupts
 	 */
-	info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	if (!info->dma_initted) {
+		/* interrupt on ext/status changes, all received chars,
+		   transmit ready */
+		info->curregs[1] = (info->curregs[1] & ~0x18)
+				| (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	} else {
+		/* interrupt on ext/status changes, W/Req pin is
+		   receive DMA request */
+		info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
+				| (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		/* enable W/Req pin */
+		info->curregs[1] |= WT_RDY_ENAB;
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		/* enable interrupts on transmit ready and receive errors */
+		info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
+	}
 	info->pendregs[1] = info->curregs[1];
 	info->curregs[3] |= (RxENABLE | Rx8);
 	info->pendregs[3] = info->curregs[3];
@@ -706,6 +1033,14 @@
 
 	restore_flags(flags);
 
+	if (info->dma_initted) {
+		spin_lock_irqsave(&info->rx_dma_lock, flags);
+		rxdma_start(info, 0);
+		info->poll_dma_timer.expires = RX_DMA_TIMER;
+		add_timer(&info->poll_dma_timer);
+		spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+	}
+
 	return 0;
 }
 
@@ -727,7 +1062,14 @@
 	
 		return;
 	}
-	
+
+	if (info->has_dma) {
+		del_timer(&info->poll_dma_timer);
+		dbdma_reset(info->tx_dma);
+		dbdma_reset(&info->rx->dma);
+		disable_irq(info->tx_dma_irq);
+		disable_irq(info->rx_dma_irq);
+	}
 	disable_irq(info->irq);
 
 	info->pendregs[1] = info->curregs[1] = 0;
@@ -753,6 +1095,12 @@
 		info->xmit_buf = 0;
 	}
 
+	if (info->has_dma && info->dma_priv) {
+		kfree(info->dma_priv);
+		info->dma_priv = NULL;
+		info->dma_initted = 0;
+	}
+
 	memset(info->curregs, 0, sizeof(info->curregs));
 	memset(info->curregs, 0, sizeof(info->pendregs));
 
@@ -795,7 +1143,7 @@
 			feature_set(info->dev_node, FEATURE_Modem_Reset);
 	   		mdelay(5);
 			feature_clear(info->dev_node, FEATURE_Modem_Reset);
-			delay = 1000;	/* wait for 1s before using */
+			delay = 2500;	/* wait for 2.5s before using */
 		}
 #ifdef CONFIG_PMAC_PBOOK
 		if (info->is_pwbk_ir)
@@ -1050,7 +1398,6 @@
 	if (!tty || !info->xmit_buf || !tmp_buf)
 		return 0;
 
-	save_flags(flags);
 	if (from_user) {
 		down(&tmp_buf_sem);
 		while (1) {
@@ -1066,6 +1413,7 @@
 					ret = -EFAULT;
 				break;
 			}
+			save_flags(flags);
 			cli();
 			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				       SERIAL_XMIT_SIZE - info->xmit_head));
@@ -1081,6 +1429,7 @@
 		up(&tmp_buf_sem);
 	} else {
 		while (1) {
+			save_flags(flags);
 			cli();		
 			c = MIN(count,
 				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
@@ -1102,7 +1451,6 @@
 	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
 	    && !info->tx_active)
 		transmit_chars(info);
-	restore_flags(flags);
 	return ret;
 }
 
@@ -1131,12 +1479,13 @@
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
 				
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
-	cli();
+	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1156,7 +1505,6 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
 	
 	printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1193,7 +1541,6 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
 	
 	printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1471,6 +1818,7 @@
 	save_flags(flags); cli();
 	
 	if (tty_hung_up_p(filp)) {
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1496,6 +1844,7 @@
 		info->count = 0;
 	}
 	if (info->count) {
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1516,8 +1865,12 @@
 	printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
 #endif
 	tty->closing = 1;
-	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
+		restore_flags(flags);
 		tty_wait_until_sent(tty, info->closing_wait);
+		save_flags(flags); cli();
+	}
+
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receiver and receive interrupts.
@@ -1537,7 +1890,9 @@
 #ifdef SERIAL_DEBUG_OPEN
 		printk("waiting end of Rx...\n");
 #endif
+		restore_flags(flags);
 		rs_wait_until_sent(tty, info->timeout);
+		save_flags(flags); cli();
 	}
 
 	shutdown(info);
@@ -1563,6 +1918,7 @@
 	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
 			 ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1772,14 +2128,19 @@
 	int 			retval, line;
 	unsigned long		page;
 
+	MOD_INC_USE_COUNT;
 	line = MINOR(tty->device) - tty->driver.minor_start;
-	if ((line < 0) || (line >= zs_channels_found))
+	if ((line < 0) || (line >= zs_channels_found)) {
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
+	}
 	info = zs_soft + line;
 
 #ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
+	if (info->kgdb_channel) {
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
+	}
 #endif
 	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
@@ -1862,7 +2223,58 @@
 
 static void show_serial_version(void)
 {
-	printk("PowerMac Z8530 serial driver version 1.01\n");
+	printk("PowerMac Z8530 serial driver version 2.0\n");
+}
+
+/*
+ * Initialize one channel, both the mac_serial and mac_zschannel
+ * structs.  We use the dev_node field of the mac_serial struct.
+ */
+static void
+chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
+	  struct mac_zschannel *zs_chan_a)
+{
+	struct device_node *ch = zss->dev_node;
+	char *conn;
+	int len;
+
+	zss->irq = ch->intrs[0].line;
+	zss->has_dma = 0;
+#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
+	if (ch->n_addrs == 3 && ch->n_intrs == 3)
+		zss->has_dma = 1;
+#endif
+	zss->dma_initted = 0;
+
+	zs_chan->control = (volatile unsigned char *)
+		ioremap(ch->addrs[0].address, 0x1000);
+	zs_chan->data = zs_chan->control + 0x10;
+	spin_lock_init(&zs_chan->lock);
+	zs_chan->parent = zss;
+	zss->zs_channel = zs_chan;
+	zss->zs_chan_a = zs_chan_a;
+
+	/* setup misc varariables */
+	zss->kgdb_channel = 0;
+	zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+
+	/* XXX tested only with wallstreet PowerBook,
+	   should do no harm anyway */
+	conn = get_property(ch, "AAPL,connector", &len);
+	zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+
+	if (zss->has_dma) {
+		zss->dma_priv = NULL;
+		/* it seems that the last two addresses are the
+		   DMA controllers */
+		zss->tx_dma = (volatile struct dbdma_regs *)
+			ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
+		zss->rx = (volatile struct mac_dma *)
+			ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
+		zss->tx_dma_irq = ch->intrs[1].line;
+		zss->rx_dma_irq = ch->intrs[2].line;
+		spin_lock_init(&zss->rx_dma_lock);
+	}
 }
 
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
@@ -1871,51 +2283,63 @@
 {
 	struct device_node *dev, *ch;
 	struct mac_serial **pp;
-	int n, lenp;
-	char *conn;
+	int n, chip, nchan;
+	struct mac_zschannel *zs_chan;
+	int chan_a_index;
 
 	n = 0;
 	pp = &zs_chain;
+	zs_chan = zs_channels;
 	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+		nchan = 0;
+		chip = n;
 		if (n >= NUM_CHANNELS) {
 			printk("Sorry, can't use %s: no more channels\n",
 			       dev->full_name);
 			continue;
 		}
+		chan_a_index = 0;
 		for (ch = dev->child; ch != 0; ch = ch->sibling) {
+			if (nchan >= 2) {
+				printk(KERN_WARNING "SCC: Only 2 channels per "
+					"chip are supported\n");
+				break;
+			}
 			if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
 				printk("Can't use %s: %d addrs %d intrs\n",
 				      ch->full_name, ch->n_addrs, ch->n_intrs);
 				continue;
 			}
-			zs_channels[n].control = (volatile unsigned char *)
-				ioremap(ch->addrs[0].address, 0x1000);
-			zs_channels[n].data = zs_channels[n].control + 0x10;
-			spin_lock_init(&zs_channels[n].lock);
-			zs_soft[n].zs_channel = &zs_channels[n];
-			zs_soft[n].dev_node = ch;
-			zs_soft[n].irq = ch->intrs[0].line;
-			zs_soft[n].zs_channel->parent = &zs_soft[n];
-			zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
-
-			/* XXX tested only with wallstreet PowerBook,
-			   should do no harm anyway */
-			conn = get_property(ch, "AAPL,connector", &lenp);
-			zs_soft[n].is_pwbk_ir =
-				conn && (strcmp(conn, "infrared") == 0);
-
-			/* XXX this assumes the prom puts chan A before B */
-			if (n & 1)
-				zs_soft[n].zs_chan_a = &zs_channels[n-1];
-			else
-				zs_soft[n].zs_chan_a = &zs_channels[n];
 
+			/* The channel with the higher address
+			   will be the A side. */
+			if (nchan > 0 &&
+			    ch->addrs[0].address
+			    > zs_soft[n-1].dev_node->addrs[0].address)
+				chan_a_index = 1;
+
+			/* minimal initialization for now */
+			zs_soft[n].dev_node = ch;
 			*pp = &zs_soft[n];
 			pp = &zs_soft[n].zs_next;
+			++nchan;
 			++n;
 		}
+		if (nchan == 0)
+			continue;
+
+		/* set up A side */
+		chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan);
+		++zs_chan;
+
+		/* set up B side, if it exists */
+		if (nchan > 1)
+			chan_init(&zs_soft[chip + 1 - chan_a_index],
+				  zs_chan, zs_chan - 1);
+		++zs_chan;
 	}
 	*pp = 0;
+
 	zs_channels_found = n;
 #ifdef CONFIG_PMAC_PBOOK
 	if (n)
@@ -1932,8 +2356,6 @@
 
 	/* Setup base handler, and timer table. */
 	init_bh(MACSERIAL_BH, do_serial_bh);
-	timer_table[RS_TIMER].fn = rs_timer;
-	timer_table[RS_TIMER].expires = 0;
 
 	/* Find out how many Z8530 SCCs we have */
 	if (zs_chain == 0)
@@ -1945,6 +2367,18 @@
 	/* Register the interrupt handler for each one */
 	save_flags(flags); cli();
 	for (i = 0; i < zs_channels_found; ++i) {
+		if (zs_soft[i].has_dma) {
+			if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
+					"SCC-txdma", &zs_soft[i]))
+				printk(KERN_ERR "macserial: can't get irq %d\n",
+				       zs_soft[i].tx_dma_irq);
+			disable_irq(zs_soft[i].tx_dma_irq);
+			if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
+					"SCC-rxdma", &zs_soft[i]))
+				printk(KERN_ERR "macserial: can't get irq %d\n",
+				       zs_soft[i].rx_dma_irq);
+			disable_irq(zs_soft[i].rx_dma_irq);
+		}
 		if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
 				"SCC", &zs_soft[i]))
 			printk(KERN_ERR "macserial: can't get irq %d\n",
@@ -2083,6 +2517,7 @@
 		/* By default, disable the port */
 		set_scc_power(info, 0);
  	}
+	tmp_buf = 0;
 
 	return 0;
 }
@@ -2103,11 +2538,26 @@
 	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
 		set_scc_power(info, 0);
 	save_flags(flags); cli();
-	for (i = 0; i < zs_channels_found; ++i)
+	for (i = 0; i < zs_channels_found; ++i) {
 		free_irq(zs_soft[i].irq, &zs_soft[i]);
+		if (zs_soft[i].has_dma) {
+			free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
+			free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
+		}
+	}
 	restore_flags(flags);
 	tty_unregister_driver(&callout_driver);
 	tty_unregister_driver(&serial_driver);
+
+	if (tmp_buf) {
+		free_page((unsigned long) tmp_buf);
+		tmp_buf = 0;
+	}
+
+#ifdef CONFIG_PMAC_PBOOK
+	if (zs_channels_found)
+		pmu_unregister_sleep_notifier(&serial_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
 }
 #endif /* MODULE */
 
@@ -2224,6 +2674,8 @@
 	if (zs_chain == 0)
 		return -1;
 
+	set_scc_power(info, 1);
+
 	/* Reset the channel */
 	write_zsreg(info->zs_channel, R9, CHRA);
 
@@ -2467,14 +2919,13 @@
 	if (zs_chain == 0)
 		probe_sccs();
 
-	set_scc_power(&zs_soft[n], 1);
+	set_scc_power(&zs_soft[tty_num], 1);
 	
 	zs_kgdbchan = zs_soft[tty_num].zs_channel;
 	zs_soft[tty_num].change_needed = 0;
 	zs_soft[tty_num].clk_divisor = 16;
 	zs_soft[tty_num].zs_baud = 38400;
 	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-	zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
 
 	/* Turn on transmitter/receiver at 8-bits/char */
         kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
diff -u --recursive --new-file v2.3.22/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- v2.3.22/linux/drivers/macintosh/macserial.h	Sat Oct  9 11:47:50 1999
+++ linux/drivers/macintosh/macserial.h	Wed Oct 20 22:13:21 1999
@@ -92,6 +92,13 @@
 	struct mac_serial*	parent;
 };
 
+struct mac_dma {
+	volatile struct dbdma_regs	dma;
+	volatile unsigned short		res_count;
+	volatile unsigned short		command;
+	volatile unsigned int		buf_addr;
+};
+
 struct mac_serial {
 	struct mac_serial *zs_next;	/* For IRQ servicing chain */
 	struct mac_zschannel *zs_channel; /* Channel registers */
@@ -156,6 +163,28 @@
 	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
+
+	volatile struct dbdma_regs *tx_dma;
+	int			tx_dma_irq;
+	volatile struct dbdma_cmd *tx_cmds;
+	volatile struct mac_dma *rx;
+	int 			rx_dma_irq;
+	volatile struct dbdma_cmd **rx_cmds;
+	unsigned char		**rx_char_buf;
+	unsigned char		**rx_flag_buf;
+#define	RX_BUF_SIZE	256
+	int			rx_nbuf;
+	int			rx_done_bytes;
+	int			rx_ubuf;
+	int			rx_fbuf;
+#define	RX_NO_FBUF	(-1)
+	int			rx_cbuf;
+	spinlock_t		rx_dma_lock;
+	int			has_dma;
+	int			dma_initted;
+	void			*dma_priv;
+	struct timer_list	poll_dma_timer;
+#define RX_DMA_TIMER	(jiffies + 10*HZ/1000)
 };
 
 
@@ -226,9 +255,9 @@
 #define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
 #define	INT_ERR_Rx	0x18	/* Int on error only */
 
-#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
-#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
-#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+#define	WT_RDY_RT	0x20	/* W/Req reflects recv if 1, xmit if 0 */
+#define	WT_FN_RDYFN	0x40	/* W/Req pin is DMA request if 1, wait if 0 */
+#define	WT_RDY_ENAB	0x80	/* Enable W/Req pin */
 
 /* Write Register #2 (Interrupt Vector) */
 
@@ -286,6 +315,9 @@
 
 /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 
+/* Write Register 7' (Some enhanced feature control) */
+#define	ENEXREAD	0x40	/* Enable read of some write registers */
+
 /* Write Register 8 (transmit buffer) */
 
 /* Write Register 9 (Master interrupt control) */
@@ -346,7 +378,9 @@
 #define	SNRZI	0xe0	/* Set NRZI mode */
 
 /* Write Register 15 (external/status interrupt control) */
+#define	EN85C30	1	/* Enable some 85c30-enhanced registers */
 #define	ZCIE	2	/* Zero count IE */
+#define	ENSTFIFO 4	/* Enable status FIFO (SDLC) */
 #define	DCDIE	8	/* DCD IE */
 #define	SYNCIE	0x10	/* Sync/hunt IE */
 #define	CTSIE	0x20	/* CTS IE */
@@ -382,6 +416,15 @@
 #define	END_FR		0x80	/* End of Frame (SDLC) */
 
 /* Read Register 2 (channel b only) - Interrupt vector */
+#define	CHB_Tx_EMPTY	0x00
+#define	CHB_EXT_STAT	0x02
+#define	CHB_Rx_AVAIL	0x04
+#define	CHB_SPECIAL	0x06
+#define	CHA_Tx_EMPTY	0x08
+#define	CHA_EXT_STAT	0x0a
+#define	CHA_Rx_AVAIL	0x0c
+#define	CHA_SPECIAL	0x0e
+#define	STATUS_MASK	0x06
 
 /* Read Register 3 (interrupt pending register) ch a only */
 #define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
diff -u --recursive --new-file v2.3.22/linux/drivers/misc/acpi.c linux/drivers/misc/acpi.c
--- v2.3.22/linux/drivers/misc/acpi.c	Fri Oct 15 15:25:13 1999
+++ linux/drivers/misc/acpi.c	Wed Oct 20 17:57:23 1999
@@ -246,18 +246,18 @@
 	struct acpi_table *rsdt;
 	u32 *rsdt_entry;
 	int rsdt_entry_count;
-	u8 *i;
+	unsigned long i;
 
 	// search BIOS memory for RSDP
 	for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) {
-		rsdp = (struct acpi_rsdp *) i;
-		if (readl(rsdp->signature) == ACPI_RSDP1_SIG
-		    && readl(rsdp->signature + 1) == ACPI_RSDP2_SIG) {
+		rsdp = (struct acpi_rsdp *) phys_to_virt(i);
+		if (rsdp->signature[0] == ACPI_RSDP1_SIG &&
+		    rsdp->signature[1] == ACPI_RSDP2_SIG) {
 			char oem[7];
 			int j;
 
 			// strip trailing space and print OEM identifier
-			memcpy_fromio(oem, rsdp->oem, 6);
+			memcpy(oem, rsdp->oem, 6);
 			oem[6] = '\0';
 			for (j = 5;
 			     j > 0 && (oem[j] == '\0' || oem[j] == ' ');
@@ -275,7 +275,7 @@
 		return -ENODEV;
 	}
 	// fetch RSDT from RSDP
-	rsdt = acpi_map_table(readl(&rsdp->rsdt));
+	rsdt = acpi_map_table(rsdp->rsdt);
 	if (!rsdt || rsdt->signature != ACPI_RSDT_SIG) {
 		printk(KERN_ERR "ACPI: no RSDT found\n");
 		acpi_unmap_table(rsdt);
diff -u --recursive --new-file v2.3.22/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.22/linux/drivers/net/Makefile	Fri Oct 15 15:25:13 1999
+++ linux/drivers/net/Makefile	Wed Oct 20 21:33:12 1999
@@ -27,10 +27,10 @@
 
 ifeq ($(CONFIG_PCMCIA),y)
   SUB_DIRS += pcmcia
-  MOD_SUB_DIRS += pcmcia
+  MOD_IN_SUB_DIRS += pcmcia
 else
   ifeq ($(CONFIG_PCMCIA),m)
-    MOD_SUB_DIRS += pcmcia
+    MOD_IN_SUB_DIRS += pcmcia
   endif
 endif
 
@@ -825,14 +825,6 @@
 else
   ifeq ($(CONFIG_ARIADNE2),m)
   M_OBJS += ariadne2.o
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_PCMCIA_PCNET),y)
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_PCMCIA_PCNET),m)
   CONFIG_8390_MODULE = y
   endif
 endif
diff -u --recursive --new-file v2.3.22/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.22/linux/drivers/net/eepro100.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/eepro100.c	Tue Oct 19 10:22:20 1999
@@ -1495,7 +1495,7 @@
 			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
 			skb->dev = dev;
 			skb_reserve(skb, sizeof(struct RxFD));
-			rxf->rx_buf_addr = virt_to_le32bus(skb->tail);
+			rxf->rx_buf_addr = virt_to_bus(skb->tail);
 		} else {
 			rxf = sp->rx_ringp[entry];
 		}
diff -u --recursive --new-file v2.3.22/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c
--- v2.3.22/linux/drivers/net/hamradio/baycom_par.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/hamradio/baycom_par.c	Mon Oct 18 11:26:31 1999
@@ -572,7 +572,7 @@
 
 static int __init baycom_par_setup(char *str)
 {
-        static unsigned __initdata nr_dev = 0;
+        static unsigned nr_dev = 0;
 	int ints[2];
 
         if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.3.22/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c
--- v2.3.22/linux/drivers/net/hamradio/soundmodem/sm.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/hamradio/soundmodem/sm.c	Mon Oct 18 11:26:31 1999
@@ -726,7 +726,7 @@
 
 static int __init sm_setup(char *str)
 {
-	static unsigned __initdata nr_dev = 0;
+	static unsigned nr_dev = 0;
 	int ints[8];
 
 	if (nr_dev >= NR_PORTS)
diff -u --recursive --new-file v2.3.22/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- v2.3.22/linux/drivers/net/irda/w83977af_ir.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/irda/w83977af_ir.c	Thu Oct 21 13:38:12 1999
@@ -10,16 +10,16 @@
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
- *     Copyright (c) 1998 Corel Computer Corp.
+ *     Copyright (c) 1998-1999 Rebel.com
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Paul VanderSpek nor Corel Computer Corp. admit liability
- *     nor provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
+ *     Neither Paul VanderSpek nor Rebel.com admit liability nor provide
+ *     warranty for any of this software. This material is provided "AS-IS"
+ *     and at no charge.
  *     
  *     If you find bugs in this file, its very likely that the same bug
  *     will also be in pc87108.c since the implementations is quite
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/3c574_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/3c574_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,1494 @@
+/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
+
+	Written 1993-1998 by
+	Donald Becker, becker@cesdis.gsfc.nasa.gov, (driver core) and
+	David Hinds, dhinds@allegro.stanford.edu (derived from his PC card code).
+
+	This software may be used and distributed according to the terms of
+	the GNU Public License, incorporated herein by reference.
+
+	This driver derives from Donald Becker's 3c509 core, which has the
+	following copyright:
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.
+
+*/
+
+/* Driver author info must always be in the binary.  Version too.. */
+static const char *tc574_version =
+"3c574_cs.c v1.08 9/24/98 Donald Becker/David Hinds, becker@cesdis.gsfc.nasa.gov.\n";
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
+Adapter.
+
+II. Board-specific settings
+
+None -- PC cards are autoconfigured.
+
+III. Driver operation
+
+The 3c574 uses a Boomerang-style interface, without the bus-master capability.
+See the Boomerang driver and documentation for most details.
+
+IV. Notes and chip documentation.
+
+Two added registers are used to enhance PIO performance, RunnerRdCtrl and
+RunnerWrCtrl.  These are 11 bit down-counters that are preloaded with the
+count of word (16 bits) reads or writes the driver is about to do to the Rx
+or Tx FIFO.  The chip is then able to hide the internal-PCI-bus to PC-card
+translation latency by buffering the I/O operations with an 8 word FIFO.
+Note: No other chip accesses are permitted when this buffer is used.
+
+A second enhancement is that both attribute and common memory space
+0x0800-0x0fff can translated to the PIO FIFO.  Thus memory operations (faster
+with *some* PCcard bridges) may be used instead of I/O operations.
+This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
+
+Some slow PC card bridges work better if they never see a WAIT signal.
+This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
+Only do this after testing that it is reliable and improves performance.
+
+The upper five bits of RunnerRdCtrl are used to window into PCcard
+configuration space registers.  Window 0 is the regular Boomerang/Odie
+register set, 1-5 are various PC card control registers, and 16-31 are
+the (reversed!) CIS table.
+
+A final note: writing the InternalConfig register in window 3 with an
+invalid ramWidth is Very Bad.
+
+V. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.national.com/pf/DP/DP83840.html
+
+Thanks to Terry Murphy of 3Com for providing development information for
+earlier 3Com products.
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+/* A few values that may be tweaked. */
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(full_duplex, "i");
+#ifdef BROKEN_FEATURES
+MODULE_PARM(use_fifo_buffer, "i");
+MODULE_PARM(use_memory_ops, "i");
+MODULE_PARM(no_wait, "i");
+#endif
+
+/* Now-standard PC card module parameters. */
+static u_int irq_mask = 0xdeb8;			/* IRQ3,4,5,7,9,10,11,12,14,15 */
+static int irq_list[4] = { -1 };
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((800*HZ)/1000)
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 64;
+
+/* Force full duplex modes? */
+static int full_duplex = 0;
+
+#ifdef BROKEN_FEATURES
+/* Performance features: best left disabled. */
+/* Set to buffer all Tx/RxFIFO accesses. */
+static int use_fifo_buffer = 0;
+/* Set iff memory ops are faster than I/O ops. */
+static int use_memory_ops = 0;
+/* Set iff disabling the WAIT signal is reliable and faster. */
+static int no_wait = 0;
+#endif
+
+/* To minimize the size of the driver source and make the driver more
+   readable not all constants are symbolically defined.
+   You'll need the manual if you want to understand driver details anyway. */
+/* Offsets from base I/O address. */
+#define EL3_DATA	0x00
+#define EL3_CMD		0x0e
+#define EL3_STATUS	0x0e
+
+#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable. */
+enum el3_cmds {
+	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
+	TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+	SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
+	StatsDisable = 22<<11, StopCoax = 23<<11,
+};
+
+enum elxl_status {
+	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+	IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
+
+enum Window0 {
+	Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */
+	IntrStatus=0x0E,		/* Valid in all windows. */
+};
+/* These assumes the larger EEPROM. */
+enum Win0_EEPROM_cmds {
+	EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300,
+	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
+	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
+};
+
+/* Register window 1 offsets, the window used in normal operation.
+   On the "Odie" this window is always mapped at offsets 0x10-0x1f.
+   Except for TxFree, which is overlapped by RunnerWrCtrl. */
+enum Window1 {
+	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
+	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
+	TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */
+	RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c,
+};
+
+enum Window3 {			/* Window 3: MAC/config bits. */
+	Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
+};
+union wn3_config {
+	int i;
+	struct w3_config_fields {
+		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
+		int pad8:8;
+		unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+		int pad24:7;
+	} u;
+};
+
+enum Window4 {		/* Window 4: Xcvr/media bits. */
+	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
+};
+
+#define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
+
+struct el3_private {
+	dev_node_t node;
+	struct net_device_stats stats;
+	u16 advertising, partner;			/* NWay media advertisement */
+	unsigned char phys[2];				/* MII device addresses. */
+	unsigned int
+	  autoselect:1, default_media:3;	/* Read from the EEPROM/Wn3_Config. */
+	/* for transceiver monitoring */
+	struct timer_list media;
+	u_short media_status;
+	u_short fast_poll;
+	u_long last_irq;
+};
+
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+   This only set with the original DP83840 on older 3c905 boards, so the extra
+   code size of a per-interface flag is not worthwhile. */
+static char mii_preamble_required = 0;
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"3c574_cs.c 1.000 1998/1/8 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/* Index of functions. */
+
+static void tc574_config(dev_link_t *link);
+static void tc574_release(u_long arg);
+static int tc574_event(event_t event, int priority,
+					   event_callback_args_t *args);
+
+static void mdio_sync(ioaddr_t ioaddr, int bits);
+static int mdio_read(ioaddr_t ioaddr, int phy_id, int location);
+static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value);
+static u_short read_eeprom(ioaddr_t ioaddr, int index);
+static void wait_for_completion(struct net_device *dev, int cmd);
+
+static void tc574_reset(struct net_device *dev);
+static void media_check(u_long arg);
+static int el3_open(struct net_device *dev);
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void update_stats(ioaddr_t addr, struct net_device *dev);
+static struct net_device_stats *el3_get_stats(struct net_device *dev);
+static int el3_rx(struct net_device *dev, int worklimit);
+static int el3_close(struct net_device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif
+static void set_rx_mode(struct net_device *dev);
+
+static dev_info_t dev_info = "3c574_cs";
+
+static dev_link_t *tc574_attach(void);
+static void tc574_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+static void flush_stale_links(void)
+{
+	dev_link_t *link, *next;
+	for (link = dev_list; link; link = next) {
+		next = link->next;
+	    if (link->state & DEV_STALE_LINK)
+			tc574_detach(link);
+    }
+}
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+#if CS_RELEASE_CODE < 0x2911
+    CardServices(ReportError, dev_info, (void *)func, (void *)ret);
+#else
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+#endif
+}
+
+/*
+   We never need to do anything when a tc574 device is "initialized"
+   by the net software, because we only register already-found cards.
+*/
+
+static int tc574_init(struct net_device *dev)
+{
+	return 0;
+}
+
+/*
+	tc574_attach() creates an "instance" of the driver, allocating
+	local data structures for one device.  The device is registered
+	with Card Services.
+*/
+
+static dev_link_t *tc574_attach(void)
+{
+	client_reg_t client_reg;
+	dev_link_t *link;
+	struct net_device *dev;
+	int i, ret;
+
+	DEBUG(0, "3c574_attach()\n");
+	flush_stale_links();
+
+	/* Create the PC card device object. */
+	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+	memset(link, 0, sizeof(struct dev_link_t));
+	link->release.function = &tc574_release;
+	link->release.data = (u_long)link;
+	link->io.NumPorts1 = 32;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	link->io.IOAddrLines = 5;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = &el3_interrupt;
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.ConfigIndex = 1;
+	link->conf.Present = PRESENT_OPTION;
+
+	/* Create the network device object. */
+	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	memset(dev, 0, sizeof(struct net_device));
+
+	/* Make up a Odie-specific data structure. */
+	dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct el3_private));
+
+	/* The EL3-specific entries in the device structure. */
+	dev->hard_start_xmit = &el3_start_xmit;
+	dev->get_stats = &el3_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+	dev->do_ioctl = &private_ioctl;
+#endif
+	dev->set_multicast_list = &set_rx_mode;
+	ether_setup(dev);
+	dev->name = ((struct el3_private *)dev->priv)->node.dev_name;
+	dev->init = &tc574_init;
+	dev->open = &el3_open;
+	dev->stop = &el3_close;
+	dev->tbusy = 1;
+
+	link->priv = dev;
+#if CS_RELEASE_CODE > 0x2911
+	link->irq.Instance = dev;
+#endif
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+			CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+				CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &tc574_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		tc574_detach(link);
+		return NULL;
+	}
+
+	return link;
+} /* tc574_attach */
+
+/*
+
+	This deletes a driver "instance".  The device is de-registered
+	with Card Services.  If it has been released, all local data
+	structures are freed.  Otherwise, the structures will be freed
+	when the device is released.
+
+*/
+
+static void tc574_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+	long flags;
+
+	DEBUG(0, "3c574_detach(0x%p)\n", link);
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link) break;
+	if (*linkp == NULL)
+	return;
+
+	save_flags(flags);
+	cli();
+	if (link->state & DEV_RELEASE_PENDING) {
+		del_timer(&link->release);
+		link->state &= ~DEV_RELEASE_PENDING;
+	}
+	restore_flags(flags);
+
+	if (link->state & DEV_CONFIG) {
+		tc574_release((u_long)link);
+		if (link->state & DEV_STALE_CONFIG) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
+
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+	if (link->priv) {
+		struct net_device *dev = link->priv;
+		if (link->dev != NULL)
+			unregister_netdev(dev);
+		if (dev->priv)
+			kfree(dev->priv);
+		kfree(link->priv);
+	}
+	kfree(link);
+
+} /* tc574_detach */
+
+/*
+	tc574_config() is scheduled to run after a CARD_INSERTION event
+	is received, to configure the PCMCIA socket, and to make the
+	ethernet device available to the system.
+*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void tc574_config(dev_link_t *link)
+{
+	client_handle_t handle;
+	struct net_device *dev;
+	struct el3_private *lp;
+	tuple_t tuple;
+	cisparse_t parse;
+	u_short buf[32];
+	int last_fn, last_ret, i, j;
+	ioaddr_t ioaddr;
+	u16 *phys_addr;
+	char *cardname;
+
+	handle = link->handle;
+	dev = link->priv;
+	phys_addr = (u16 *)dev->dev_addr;
+
+	DEBUG(0, "3c574_config(0x%p)\n", link);
+
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = 64;
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	for (i = j = 0; j < 0x400; j += 0x20) {
+		link->io.BasePort1 = j ^ 0x300;
+		i = CardServices(RequestIO, link->handle, &link->io);
+		if (i == CS_SUCCESS) break;
+	}
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+	CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+	dev->mem_start = 0;
+#ifdef BROKEN_FEATURES
+	if (use_memory_ops) {
+		win_req_t req;
+		memreq_t mem;
+		req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM |
+			WIN_ENABLE | WIN_USE_WAIT;
+		req.Base = 0;
+		req.Size = 0x1000;
+		req.AccessSpeed = 0;
+		link->win = (window_handle_t)link->handle;
+		i = CardServices(RequestWindow, &link->win, &req);
+		if (i == CS_SUCCESS) {
+			mem.Page = mem.CardOffset = 0;
+			CardServices(MapMemPage, link->win, &mem);
+			dev->mem_start = (long)(ioremap(req.Base, 0x1000)) + 0x800;
+		} else
+			cs_error(link->handle, RequestWindow, i);
+	}
+#endif
+
+	dev->irq = link->irq.AssignedIRQ;
+	dev->base_addr = link->io.BasePort1;
+
+	dev->tbusy = 0;
+	if (register_netdev(dev) != 0) {
+		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
+		goto failed;
+	}
+
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	ioaddr = dev->base_addr;
+	lp = (struct el3_private *)dev->priv;
+	link->dev = &lp->node;
+
+	/* The 3c574 normally uses an EEPROM for configuration info, including
+	   the hardware address.  The future products may include a modem chip
+	   and put the address in the CIS. */
+	tuple.DesiredTuple = 0x88;
+	if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
+		CardServices(GetTupleData, handle, &tuple);
+		for (i = 0; i < 3; i++)
+			phys_addr[i] = htons(buf[i]);
+	} else {
+		EL3WINDOW(0);
+		for (i = 0; i < 3; i++)
+			phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
+		if (phys_addr[0] == 0x6060) {
+			printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"
+				   "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+			goto failed;
+		}
+	}
+	tuple.DesiredTuple = CISTPL_VERS_1;
+	if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS &&
+		CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS &&
+		CardServices(ParseTuple, handle, &tuple, &parse) == CS_SUCCESS) {
+		cardname = parse.version_1.str + parse.version_1.ofs[1];
+	} else
+		cardname = "3Com 3c574";
+
+	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
+		   dev->name, cardname, dev->base_addr, dev->irq);
+
+	for (i = 0; i < 6; i++)
+		printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
+
+	if (dev->mem_start)
+		printk(KERN_INFO"  Acceleration window at memory base %#lx.\n",
+			   dev->mem_start);
+
+	{
+		u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		union wn3_config config;
+		outw(2<<11, ioaddr + RunnerRdCtrl);
+		mcr = inb(ioaddr + 2);
+		outw(0<<11, ioaddr + RunnerRdCtrl);
+		printk(KERN_INFO "  ASIC rev %d,", mcr>>3);
+		EL3WINDOW(3);
+		config.i = inl(ioaddr + Wn3_Config);
+		printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
+			   8 << config.u.ram_size, ram_split[config.u.ram_split],
+			   config.u.autoselect ? "autoselect " : "");
+		lp->default_media = config.u.xcvr;
+		lp->autoselect = config.u.autoselect;
+	}
+
+	{
+		int phy, phy_idx = 0;
+		
+		/* Roadrunner only: Turn on the MII transceiver */
+		outw(0x8040, ioaddr + Wn3_Options);
+		udelay(1000);
+		outw(0xc040, ioaddr + Wn3_Options);
+		wait_for_completion(dev, TxReset);
+		wait_for_completion(dev, RxReset);
+		udelay(1000);
+		outw(0x8040, ioaddr + Wn3_Options);
+		
+		EL3WINDOW(4);
+		for (phy = 1; phy <= 32 && phy_idx < sizeof(lp->phys); phy++) {
+			int mii_status;
+			mdio_sync(ioaddr, 32);
+			mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
+			if (mii_status != 0xffff) {
+				lp->phys[phy_idx++] = phy & 0x1f;
+				DEBUG(0, "  MII transceiver at index %d, status %x.\n",
+					  phy, mii_status);
+				if ((mii_status & 0x0040) == 0)
+					mii_preamble_required = 1;
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_NOTICE "  No MII transceivers found!\n");
+			goto failed;
+		}
+		i = mdio_read(ioaddr, lp->phys[0], 16) | 0x40;
+		mdio_write(ioaddr, lp->phys[0], 16, i);
+		lp->advertising = mdio_read(ioaddr, lp->phys[0], 4);
+		if (full_duplex) {
+			/* Only advertise the FD media types. */
+			lp->advertising &= ~0x02a0;
+			mdio_write(ioaddr, lp->phys[0], 4, lp->advertising);
+		}
+	}
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+failed:
+	tc574_release((u_long)link);
+	return;
+
+} /* tc574_config */
+
+/*
+	After a card is removed, tc574_release() will unregister the net
+	device, and release the PCMCIA configuration.  If the device is
+	still open, this will be postponed until it is closed.
+*/
+
+static void tc574_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	struct net_device *dev = link->priv;
+
+	DEBUG(0, "3c574_release(0x%p)\n", link);
+
+	if (link->open) {
+		DEBUG(1, "3c574_cs: release postponed, '%s' still open\n",
+			  link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+	if (link->win) {
+		iounmap((void *)(dev->mem_start - 0x800));
+		CardServices(ReleaseWindow, link->win);
+	}
+
+	link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* tc574_release */
+
+/*
+	The card status event handler.  Mostly, this schedules other
+	stuff to run after an event is received.  A CARD_REMOVAL event
+	also sets some flags to discourage the net drivers from trying
+	to talk to the card any more.
+*/
+
+static int tc574_event(event_t event, int priority,
+					   event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	struct net_device *dev = link->priv;
+
+	DEBUG(1, "3c574_event(0x%06x)\n", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			dev->tbusy = 1; dev->start = 0;
+			link->release.expires = jiffies + HZ/20;
+			add_timer(&link->release);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		tc574_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG) {
+			if (link->open) {
+				dev->tbusy = 1; dev->start = 0;
+			}
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+			if (link->open) {
+				tc574_reset(dev);
+				dev->tbusy = 0; dev->start = 1;
+			}
+		}
+		break;
+	}
+	return 0;
+} /* tc574_event */
+
+static void dump_status(struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+	EL3WINDOW(1);
+    printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
+		   "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
+		   inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
+		   inw(ioaddr+TxFree));
+	EL3WINDOW(4);
+    printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
+		   " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
+		   inw(ioaddr+0x08), inw(ioaddr+0x0a));
+	EL3WINDOW(1);
+}
+
+/*
+  Use this for commands that may take time to finish
+*/
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+    int i = 1500;
+    outw(cmd, dev->base_addr + EL3_CMD);
+    while (--i > 0)
+		if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
+    if (i == 0)
+		printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
+			   dev->name, cmd);
+}
+
+/* Read a word from the EEPROM using the regular EEPROM access register.
+   Assume that we are in register window zero.
+ */
+static u_short read_eeprom(ioaddr_t ioaddr, int index)
+{
+	int timer;
+	outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
+	/* Pause for at least 162 usec for the read to take place. */
+	for (timer = 1620; timer >= 0; timer--) {
+		if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+			break;
+	}
+	return inw(ioaddr + Wn0EepromData);
+}
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details.
+   The maxium data clock rate is 2.5 Mhz.  The timing is easily met by the
+   slow PC card interface. */
+
+#define MDIO_SHIFT_CLK	0x01
+#define MDIO_DIR_WRITE	0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ	0x02
+#define MDIO_ENB_IN		0x00
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(ioaddr_t ioaddr, int bits)
+{
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (-- bits >= 0) {
+		outw(MDIO_DATA_WRITE1, mdio_addr);
+		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+	}
+}
+
+static int mdio_read(ioaddr_t ioaddr, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	unsigned int retval = 0;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the read command bits out. */
+	for (i = 14; i >= 0; i--) {
+		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value)
+{
+	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int i;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+	}
+	/* Leave the interface idle. */
+	for (i = 1; i >= 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	}
+
+	return;
+}
+
+/* Reset and restore all of the 3c574 registers. */
+static void tc574_reset(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	int i, ioaddr = dev->base_addr;
+
+	wait_for_completion(dev, TotalReset|0x10);
+
+#ifdef BROKEN_FEATURES
+	/* Set the PIO ctrl bits in the PC card LAN COR using Runner window 1. */
+	if (dev->mem_start || no_wait) {
+		u8 lan_cor;
+		outw(1<<11, ioaddr + RunnerRdCtrl);
+		lan_cor = inw(ioaddr) & ~0x30;
+		if (dev->mem_start)		/* Iff use_memory_ops worked! */
+			lan_cor |= 0x10;
+		if (no_wait)
+			lan_cor |= 0x20;
+		outw(lan_cor, ioaddr);
+	}
+#endif
+	/* Clear any transactions in progress. */
+	outw(0, ioaddr + RunnerWrCtrl);
+	outw(0, ioaddr + RunnerRdCtrl);
+
+	/* Set the station address and mask. */
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+	for (; i < 12; i+=2)
+		outw(0, ioaddr + i);
+
+	/* Reset config options */
+	EL3WINDOW(3);
+	outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+	outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,
+		 ioaddr + Wn3_Config);
+	
+	/* Roadrunner only: Turn on the MII transceiver. */
+	outw(0x8040, ioaddr + Wn3_Options);
+	udelay(1000);
+	outw(0xc040, ioaddr + Wn3_Options);
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
+	udelay(1000);
+	outw(0x8040, ioaddr + Wn3_Options);
+
+	/* Switch to the stats window, and clear all stats by reading. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	EL3WINDOW(6);
+	for (i = 0; i < 10; i++)
+		inb(ioaddr + i);
+	inw(ioaddr + 10);
+	inw(ioaddr + 12);
+
+	EL3WINDOW(4);
+	/* New: On the Vortex/Odie we must also clear the BadSSD counter.. */
+	inb(ioaddr + 12);
+	/* .. enable any extra statistics bits.. */
+	outw(0x0040, ioaddr + Wn4_NetDiag);
+	/* .. re-sync MII and re-fill what NWay is advertising. */
+	mdio_sync(ioaddr, 32);
+	mdio_write(ioaddr, lp->phys[0], 4, lp->advertising);
+
+	/* Switch to register set 1 for normal use, just for TxFree. */
+	EL3WINDOW(1);
+
+	set_rx_mode(dev);
+	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+	/* Allow status bits to be seen. */
+	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+	/* Ack all pending events, and set active indicator mask. */
+	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+		 ioaddr + EL3_CMD);
+	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+		 | AdapterFailure | RxEarly, ioaddr + EL3_CMD);
+}
+
+static int el3_open(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	dev_link_t *link;
+
+	for (link = dev_list; link; link = link->next)
+		if (link->priv == dev) break;
+	if (!DEV_OK(link))
+		return -ENODEV;
+	
+	link->open++;
+	MOD_INC_USE_COUNT;
+	dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+	
+	tc574_reset(dev);
+	lp->media.function = &media_check;
+	lp->media.data = (u_long)dev;
+	lp->media.expires = jiffies + HZ;
+	add_timer(&lp->media);
+	
+	DEBUG(2, "%s: opened, status %4.4x.\n",
+		  dev->name, inw(dev->base_addr + EL3_STATUS));
+	
+	return 0;					/* Always succeed */
+}
+
+static void el3_tx_timeout(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	
+	printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
+	dump_status(dev);
+	lp->stats.tx_errors++;
+	dev->trans_start = jiffies;
+	/* Issue TX_RESET and TX_START commands. */
+	wait_for_completion(dev, TxReset);
+	outw(TxEnable, ioaddr + EL3_CMD);
+	dev->tbusy = 0;
+}
+
+static void pop_tx_status(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+    
+    /* Clear the Tx status stack. */
+    for (i = 32; i > 0; i--) {
+		u_char tx_status = inb(ioaddr + TxStatus);
+		if (!(tx_status & 0x84)) break;
+		/* reset transmitter on jabber error or underrun */
+		if (tx_status & 0x30)
+			wait_for_completion(dev, TxReset);
+		if (tx_status & 0x38) {
+			DEBUG(1, "%s: transmit error: status 0x%02x\n",
+				  dev->name, tx_status);
+			outw(TxEnable, ioaddr + EL3_CMD);
+			lp->stats.tx_aborted_errors++;
+		}
+		outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
+    }
+}
+
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+#ifdef BROKEN_FEATURES
+	long flags = 0;
+#endif
+
+	/* Transmitter timeout, serious problems. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		el3_tx_timeout(dev);
+	}
+
+	DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
+		  "status %4.4x.\n", dev->name, (long)skb->len,
+		  inw(ioaddr + EL3_STATUS));
+
+#ifdef BROKEN_FEATURES
+	if (use_fifo_buffer) {
+		/* Avoid other accesses to the chip while RunnerWrCtrl is non-zero. */
+		save_flags(flags);
+		cli();
+		outw((((skb->len + 7)>>2)<<1), ioaddr + RunnerWrCtrl);
+		DEBUG(0, "TxFree %x, tx length %x, RunnerWrCtrl is %4.4x.\n",
+			  inw(ioaddr+TxFree), skb->len, inw(ioaddr+RunnerWrCtrl));
+	}
+
+	/* Put out the doubleword header... */
+	/* ... and the packet rounded to a doubleword. */
+	if (dev->mem_start) {
+		writew(skb->len, (void *)dev->mem_start);
+		writew(0, (void *)dev->mem_start);
+		copy_to_pc((void*)dev->mem_start, skb->data, (skb->len+3)&~3);
+	} else {
+		outw(skb->len, ioaddr + TX_FIFO);
+		outw(0, ioaddr + TX_FIFO);
+		outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
+	}
+
+	if (use_fifo_buffer) {
+		DEBUG(0, " RunnerWr/RdCtrl is %4.4x/%4.4x, TxFree %x.\n",
+			  inw(ioaddr + RunnerWrCtrl), inw(ioaddr + RunnerRdCtrl),
+			  inw(ioaddr + TxFree));
+		restore_flags(flags);
+	}
+#else
+	outw(skb->len, ioaddr + TX_FIFO);
+	outw(0, ioaddr + TX_FIFO);
+	outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
+#endif
+
+	dev->trans_start = jiffies;
+
+	/* TxFree appears only in Window 1, not offset 0x1c. */
+	if (inw(ioaddr + TxFree) > 1536) {
+		dev->tbusy = 0;
+	} else
+		/* Interrupt us when the FIFO has room for max-sized packet. 
+		   The threshold is in units of dwords. */
+		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+
+	dev_kfree_skb (skb);
+	pop_tx_status(dev);
+
+	return 0;
+}
+
+/* The EL3 interrupt handler. */
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct el3_private *lp;
+	ioaddr_t ioaddr, status;
+	int work_budget = max_interrupt_work;
+
+	if ((dev == NULL) || !dev->start)
+		return;
+	lp = (struct el3_private *)dev->priv;
+	ioaddr = dev->base_addr;
+
+#ifdef PCMCIA_DEBUG
+	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+		printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
+			   dev->name);
+		return;
+	}
+	DEBUG(3, "%s: interrupt, status %4.4x.\n",
+		  dev->name, inw(ioaddr + EL3_STATUS));
+#endif
+
+	while ((status = inw(ioaddr + EL3_STATUS)) &
+		   (IntLatch | RxComplete | RxEarly | StatsFull)) {
+		if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) {
+			DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
+			break;
+		}
+
+		if (status & RxComplete)
+			work_budget = el3_rx(dev, work_budget);
+
+		if (status & TxAvailable) {
+			DEBUG(3, "  TX room bit was handled.\n");
+			/* There's room in the FIFO for a full-sized packet. */
+			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+
+		if (status & TxComplete)
+			pop_tx_status(dev);
+
+		if (status & (AdapterFailure | RxEarly | StatsFull)) {
+			/* Handle all uncommon interrupts. */
+			if (status & StatsFull)
+				update_stats(ioaddr, dev);
+			if (status & RxEarly) {
+				work_budget = el3_rx(dev, work_budget);
+				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+			}
+			if (status & AdapterFailure) {
+				u16 fifo_diag;
+				EL3WINDOW(4);
+				fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+				EL3WINDOW(1);
+				printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
+					   " register %04x.\n", dev->name, fifo_diag);
+				if (fifo_diag & 0x0400) {
+					/* Tx overrun */
+					wait_for_completion(dev, TxReset);
+					outw(TxEnable, ioaddr + EL3_CMD);
+				}
+				if (fifo_diag & 0x2000) {
+					/* Rx underrun */
+					wait_for_completion(dev, RxReset);
+					set_rx_mode(dev);
+					outw(RxEnable, ioaddr + EL3_CMD);
+				}
+				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+			}
+		}
+
+		if (--work_budget < 0) {
+			DEBUG(0, "%s: Too much work in interrupt, "
+				  "status %4.4x.\n", dev->name, status);
+			/* Clear all interrupts */
+			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+			break;
+		}
+		/* Acknowledge the IRQ. */
+		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+	}
+
+#ifdef PCMCIA_DEBUG
+	DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
+		  dev->name, inw(ioaddr + EL3_STATUS));
+	dev->interrupt = 0;
+#endif
+	return;
+}
+
+/*
+    This timer serves two purposes: to check for missed interrupts
+	(and as a last resort, poll the NIC for events), and to monitor
+	the MII, reporting changes in cable status.
+*/
+static void media_check(u_long arg)
+{
+    struct net_device *dev = (struct net_device *)(arg);
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_long flags;
+	u_short /* cable, */ media, partner;
+	
+    if (dev->start == 0) goto reschedule;
+	
+    /* Check for pending interrupt with expired latency timer: with
+       this, we can limp along even if the interrupt is blocked */
+    if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
+		(inb(ioaddr + Timer) == 0xff)) {
+		if (!lp->fast_poll)
+			printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+		el3_interrupt(dev->irq, dev, NULL);
+		lp->fast_poll = HZ;
+    }
+    if (lp->fast_poll) {
+		lp->fast_poll--;
+		lp->media.expires = jiffies + 2;
+		add_timer(&lp->media);
+		return;
+    }
+
+	save_flags(flags);
+	cli();
+	EL3WINDOW(4);
+	media = mdio_read(ioaddr, lp->phys[0], 1);
+	partner = mdio_read(ioaddr, lp->phys[0], 5);
+	EL3WINDOW(1);
+	restore_flags(flags);
+
+	if (media != lp->media_status) {
+		if ((media ^ lp->media_status) & 0x0004)
+			printk(KERN_INFO "%s: %s link beat\n", dev->name,
+				   (lp->media_status & 0x0004) ? "lost" : "found");
+		if ((media ^ lp->media_status) & 0x0020) {
+			lp->partner = 0;
+			if (lp->media_status & 0x0020) {
+				printk(KERN_INFO "%s: autonegotiation restarted\n",
+					   dev->name);
+			} else if (partner) {
+				partner &= lp->advertising;
+				lp->partner = partner;
+				printk(KERN_INFO "%s: autonegotiation complete: "
+					   "%sbaseT-%cD selected\n", dev->name,
+					   ((partner & 0x0180) ? "100" : "10"),
+					   ((partner & 0x0140) ? 'F' : 'H'));
+			} else {
+				printk(KERN_INFO "%s: link partner did not autonegotiate\n",
+					   dev->name);
+			}
+
+			EL3WINDOW(3);
+			outb((partner & 0x0140 ? 0x20 : 0) |
+				 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+			EL3WINDOW(1);
+
+		}
+		if (media & 0x0010)
+			printk(KERN_INFO "%s: remote fault detected\n",
+				   dev->name);
+		if (media & 0x0002)
+			printk(KERN_INFO "%s: jabber detected\n", dev->name);
+		lp->media_status = media;
+	}
+
+reschedule:
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+}
+
+static struct net_device_stats *el3_get_stats(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+
+	if (dev->start)
+		update_stats(dev->base_addr, dev);
+	return &lp->stats;
+}
+
+/*  Update statistics.
+	Suprisingly this need not be run single-threaded, but it effectively is.
+	The counters clear when read, so the adds must merely be atomic.
+ */
+static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	u8 upper_cnt;
+
+	DEBUG(2, "%s: updating the statistics.\n", dev->name);
+
+	if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
+		return;
+
+	/* Unlike the 3c509 we need not turn off stats updates while reading. */
+	/* Switch to the stats window, and read everything. */
+	EL3WINDOW(6);
+	lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);
+	lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+	/* Multiple collisions. */	   	inb(ioaddr + 2);
+	lp->stats.collisions		+= inb(ioaddr + 3);
+	lp->stats.tx_window_errors	+= inb(ioaddr + 4);
+	lp->stats.rx_fifo_errors	+= inb(ioaddr + 5);
+	lp->stats.tx_packets		+= inb(ioaddr + 6);
+	upper_cnt = inb(ioaddr + 9);
+	lp->stats.tx_packets		+= (upper_cnt&0x30) << 4;
+	/* Rx packets   */			inb(ioaddr + 7);
+	/* Tx deferrals */			inb(ioaddr + 8);
+	lp->stats.rx_bytes += inw(ioaddr + 10);
+	lp->stats.tx_bytes += inw(ioaddr + 12);
+
+	/* With Vortex and later we must also clear the BadSSD counter. */
+	EL3WINDOW(4);
+	inb(ioaddr + 12);
+
+	EL3WINDOW(1);
+}
+
+static int el3_rx(struct net_device *dev, int worklimit)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	short rx_status;
+	
+	DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+    while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
+		   (--worklimit >= 0)) {
+		if (rx_status & 0x4000) { /* Error, update stats. */
+			short error = rx_status & 0x3800;
+			lp->stats.rx_errors++;
+			switch (error) {
+			case 0x0000:		lp->stats.rx_over_errors++; break;
+			case 0x0800:		lp->stats.rx_length_errors++; break;
+			case 0x1000:		lp->stats.rx_frame_errors++; break;
+			case 0x1800:		lp->stats.rx_length_errors++; break;
+			case 0x2000:		lp->stats.rx_frame_errors++; break;
+			case 0x2800:		lp->stats.rx_crc_errors++; break;
+			}
+		} else {
+			short pkt_len = rx_status & 0x7ff;
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(pkt_len+5);
+
+			DEBUG(3, "  Receiving packet size %d status %4.4x.\n",
+				  pkt_len, rx_status);
+			if (skb != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);
+
+#ifdef BROKEN_FEATURES
+				if (use_fifo_buffer) {
+					outw(((pkt_len+3)>>2)<<1, ioaddr + RunnerRdCtrl);
+					DEBUG(0,"Start Rx %x -- RunnerRdCtrl is %4.4x.\n",
+						  pkt_len, inw(ioaddr + RunnerRdCtrl));
+				}
+				if (dev->mem_start) {
+					copy_from_pc(skb_put(skb, pkt_len),
+								 (void*)dev->mem_start, (pkt_len+3)&~3);
+				} else {
+					insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+							((pkt_len+3)>>2));
+				}
+				if (use_fifo_buffer) {
+					DEBUG(0," RunnerRdCtrl is now %4.4x.\n",
+						  inw(ioaddr + RunnerRdCtrl));
+					outw(0, ioaddr + RunnerRdCtrl);
+					DEBUG(0, " Rx packet with data %2.2x:%2.2x:%2.2x\n",
+						  skb->head[0], skb->head[1], skb->head[2]);
+				}
+#else
+				insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+						((pkt_len+3)>>2));
+#endif
+
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+				lp->stats.rx_packets++;
+			} else {
+				DEBUG(1, "%s: couldn't allocate a sk_buff of"
+					  " size %d.\n", dev->name, pkt_len);
+				lp->stats.rx_dropped++;
+			}
+		}
+		wait_for_completion(dev, RxDiscard);
+	}
+
+	return worklimit;
+}
+
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct el3_private *vp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = vp->phys[0] & 0x1f;
+
+	DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+		  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+		  data[0], data[1], data[2], data[3]);
+
+    switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = phy;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		{
+			int saved_window;
+			long flags;
+
+			save_flags(flags);
+			cli();
+			saved_window = inw(ioaddr + EL3_CMD) >> 13;
+			EL3WINDOW(4);
+			data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+			EL3WINDOW(saved_window);
+			restore_flags(flags);
+			return 0;
+		}
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		{
+			int saved_window;
+			long flags;
+
+			if (!suser())
+				return -EPERM;
+			save_flags(flags);
+			cli();
+			saved_window = inw(ioaddr + EL3_CMD) >> 13;
+			EL3WINDOW(4);
+			mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			EL3WINDOW(saved_window);
+			restore_flags(flags);
+			return 0;
+		}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
+/* The Odie chip has a 64 bin multicast filter, but the bit layout is not
+   documented.  Until it is we revert to receiving all multicast frames when
+   any multicast reception is desired.
+   Note: My other drivers emit a log message whenever promiscuous mode is
+   entered to help detect password sniffers.  This is less desirable on
+   typical PC card machines, so we omit the message.
+   */
+
+static void set_rx_mode(struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+
+	if (dev->flags & IFF_PROMISC)
+		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
+			 ioaddr + EL3_CMD);
+	else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
+		outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	else
+		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+}
+
+static int el3_close(struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+	dev_link_t *link;
+
+	for (link = dev_list; link; link = link->next)
+		if (link->priv == dev) break;
+	if (link == NULL)
+		return -ENODEV;
+
+	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+	
+	if (DEV_OK(link)) {
+		/* Turn off statistics ASAP.  We update lp->stats below. */
+		outw(StatsDisable, ioaddr + EL3_CMD);
+		
+		/* Disable the receiver and transmitter. */
+		outw(RxDisable, ioaddr + EL3_CMD);
+		outw(TxDisable, ioaddr + EL3_CMD);
+		
+		/* Note: Switching to window 0 may disable the IRQ. */
+		EL3WINDOW(0);
+		
+		update_stats(ioaddr, dev);
+	}
+
+	link->open--;
+	dev->start = 0;
+	del_timer(&((struct el3_private *)dev->priv)->media);
+	if (link->state & DEV_STALE_CONFIG) {
+		link->release.expires = jiffies + HZ/20;
+		link->state |= DEV_RELEASE_PENDING;
+		add_timer(&link->release);
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int __init init_3c574_cs(void)
+{
+	servinfo_t serv;
+
+	/* Always emit the version, before any failure. */
+	printk(KERN_INFO"%s", tc574_version);
+	DEBUG(0, "%s\n", version);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "3c574_cs: Card Services release "
+			   "does not match!\n");
+		return -1;
+	}
+	register_pccard_driver(&dev_info, &tc574_attach, &tc574_detach);
+	return 0;
+}
+
+static void __exit exit_3c574_cs(void)
+{
+	DEBUG(0, "3c574_cs: unloading\n");
+	unregister_pccard_driver(&dev_info);
+	while (dev_list != NULL)
+		tc574_detach(dev_list);
+}
+
+module_init(init_3c574_cs);
+module_exit(exit_3c574_cs);
+
+/*
+ * Local variables:
+ *  compile-command: "make 3c574_cs.o"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/3c589_cs.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/pcmcia/3c589_cs.c	Wed Oct 20 21:33:12 1999
@@ -4,7 +4,7 @@
     
     Copyright (C) 1999 David A. Hinds -- dhinds@hyper.stanford.edu
 
-    3c589_cs.c 1.134 1999/09/15 15:33:09
+    3c589_cs.c 1.135 1999/10/07 20:14:54
 
     The network driver code is based on Donald Becker's 3c589 code:
     
@@ -115,7 +115,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"3c589_cs.c 1.134 1999/09/15 15:33:09 (David Hinds)";
+"3c589_cs.c 1.135 1999/10/07 20:14:54 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -142,14 +142,14 @@
 static int tc589_event(event_t event, int priority,
 		       event_callback_args_t *args);
 
-static ushort read_eeprom(short ioaddr, int index);
+static u_short read_eeprom(ioaddr_t ioaddr, int index);
 static void tc589_reset(struct net_device *dev);
 static void media_check(u_long arg);
 static int el3_config(struct net_device *dev, struct ifmap *map);
 static int el3_open(struct net_device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void update_stats(int addr, struct net_device *dev);
+static void update_stats(ioaddr_t addr, struct net_device *dev);
 static struct net_device_stats *el3_get_stats(struct net_device *dev);
 static int el3_rx(struct net_device *dev);
 static int el3_close(struct net_device *dev);
@@ -355,14 +355,14 @@
     struct net_device *dev;
     tuple_t tuple;
     cisparse_t parse;
-    u_short buf[32];
+    u_short buf[32], *phys_addr;
     int last_fn, last_ret, i, j, multi = 0;
-    short ioaddr, *phys_addr;
+    ioaddr_t ioaddr;
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
     
     handle = link->handle;
     dev = link->priv;
-    phys_addr = (short *)dev->dev_addr;
+    phys_addr = (u_short *)dev->dev_addr;
 
     DEBUG(0, "3c589_config(0x%p)\n", link);
 
@@ -571,7 +571,7 @@
   Read a word from the EEPROM using the regular EEPROM access register.
   Assume that we are in register window zero.
 */
-static ushort read_eeprom(short ioaddr, int index)
+static u_short read_eeprom(ioaddr_t ioaddr, int index)
 {
     int i;
     outw(EEPROM_READ + index, ioaddr + 10);
@@ -589,7 +589,7 @@
 static void tc589_set_xcvr(struct net_device *dev, int if_port)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
-    ushort ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     
     EL3WINDOW(0);
     switch (if_port) {
@@ -611,7 +611,7 @@
 
 static void dump_status(struct net_device *dev)
 {
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     EL3WINDOW(1);
     printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
 	   "%02x  tx free %04x\n", inw(ioaddr+EL3_STATUS),
@@ -627,7 +627,7 @@
 /* Reset and restore all of the 3c589 registers. */
 static void tc589_reset(struct net_device *dev)
 {
-    ushort ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     int i;
     
     EL3WINDOW(0);
@@ -709,7 +709,7 @@
 static void el3_tx_timeout(struct net_device *dev)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     
     printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
     dump_status(dev);
@@ -724,7 +724,7 @@
 static void pop_tx_status(struct net_device *dev)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     int i;
     
     /* Clear the Tx status stack. */
@@ -747,7 +747,7 @@
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
 
     /* Transmitter timeout, serious problems. */
     if (dev->tbusy) {
@@ -791,7 +791,7 @@
 {
     struct net_device *dev = (struct net_device *)dev_id;
     struct el3_private *lp;
-    int ioaddr, status;
+    ioaddr_t ioaddr, status;
     int i = 0;
     
     if ((dev == NULL) || !dev->start)
@@ -885,7 +885,7 @@
 {
     struct net_device *dev = (struct net_device *)(arg);
     struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     u_short media, errs;
     u_long flags;
 
@@ -984,7 +984,7 @@
   operation, and it's simpler for the rest of the driver to assume that
   window 1 is always valid rather than use a special window-state variable.
 */
-static void update_stats(int ioaddr, struct net_device *dev)
+static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
     
@@ -1013,7 +1013,7 @@
 static int el3_rx(struct net_device *dev)
 {
     struct el3_private *lp = (struct el3_private *)dev->priv;
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     int worklimit = 32;
     short rx_status;
     
@@ -1073,7 +1073,7 @@
  */
 static void set_multicast_list(struct net_device *dev)
 {
-    short ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     dev_link_t *link;
     for (link = dev_list; link; link = link->next)
 	if (link->priv == dev) break;
@@ -1099,7 +1099,7 @@
 
 static int el3_close(struct net_device *dev)
 {
-    int ioaddr = dev->base_addr;
+    ioaddr_t ioaddr = dev->base_addr;
     dev_link_t *link;
 
     for (link = dev_list; link; link = link->next)
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.3.22/linux/drivers/net/pcmcia/Config.in	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/pcmcia/Config.in	Thu Oct 21 12:34:59 1999
@@ -3,13 +3,34 @@
 #
 
 mainmenu_option next_comment
-comment 'PCMCIA network devices'
+comment 'PCMCIA network device support'
 
-dep_tristate 'PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...)' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA
-dep_tristate '3Com 3c589 PCMCIA card' CONFIG_PCMCIA_3C589 $CONFIG_PCMCIA
-dep_tristate 'Aviator/Raytheon 2.4MHz wireless' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
+bool 'PCMCIA network device support' CONFIG_NET_PCMCIA
+if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
+   dep_tristate '  3Com 3c589 PCMCIA support' CONFIG_PCMCIA_3C589 $CONFIG_PCMCIA
+   dep_tristate '  3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA
+   dep_tristate '  Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA
+   dep_tristate '  NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA
+   dep_tristate '  New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA
+   dep_tristate '  SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
+   dep_tristate '  Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
 
-if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" ]; then
+   # if [ "$CONFIG_CARDBUS" = "y" ]; then
+      # dep_tristate '  3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 $CONFIG_PCMCIA
+      # dep_tristate '  DEC Tulip CardBus support' CONFIG_PCMCIA_TULIP $CONFIG_PCMCIA
+      # dep_tristate '  SMC EPIC CardBus support' CONFIG_PCMCIA_EPIC100 $CONFIG_PCMCIA
+   # fi
+
+   dep_tristate '  Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
+   dep_tristate '  Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
+   dep_tristate '  AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
+fi
+
+if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \
+     "$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \
+     "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \
+     "$CONFIG_PCMCIA_XIRC2PS" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o \
+     "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" ]; then
    define_bool CONFIG_PCMCIA_NETCARD y
 fi
 
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.3.22/linux/drivers/net/pcmcia/Makefile	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/pcmcia/Makefile	Wed Oct 20 21:33:12 1999
@@ -13,22 +13,81 @@
 M_OBJS   :=
 MOD_LIST_NAME := PCMCIA_MODULES
 
+#CFLAGS_3c575_cb.o = -DCARDBUS
+#CFLAGS_tulip_cb.o = -DCARDBUS
+
+ifeq ($(CONFIG_PCMCIA_3C589),y)
+  O_OBJS += 3c589_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_3C589),m)
+    M_OBJS += 3c589_cs.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCMCIA_3C574),y)
+  O_OBJS += 3c574_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_3C574),m)
+    M_OBJS += 3c574_cs.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCMCIA_FMVJ18X),y)
+  O_OBJS += fmvj18x_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_FMVJ18X),m)
+    M_OBJS += fmvj18x_cs.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCMCIA_NMCLAN),y)
+  O_OBJS += nmclan_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_NMCLAN),m)
+    M_OBJS += nmclan_cs.o
+  endif
+endif
+
 ifeq ($(CONFIG_PCMCIA_PCNET),y)
   O_OBJS += pcnet_cs.o
 else
   ifeq ($(CONFIG_PCMCIA_PCNET),m)
-    MX_OBJS += pcnet_cs.o
+    M_OBJS += pcnet_cs.o
   endif
 endif
 
-ifeq ($(CONFIG_PCMCIA_3C589),y)
-  O_OBJS += 3c589_cs.o
+ifeq ($(CONFIG_PCMCIA_SMC91C92),y)
+  O_OBJS += smc91c92_cs.o
 else
-  ifeq ($(CONFIG_PCMCIA_3C589),m)
-    MX_OBJS += 3c589_cs.o
+  ifeq ($(CONFIG_PCMCIA_SMC91C92),m)
+    M_OBJS += smc91c92_cs.o
   endif
 endif
 
+#ifeq ($(CONFIG_PCMCIA_3C575),y)
+#  O_OBJS += 3c575_cb.o
+#else
+#  ifeq ($(CONFIG_PCMCIA_3C575),m)
+#    M_OBJS += 3c575_cb.o
+#  endif
+#endif
+
+#ifeq ($(CONFIG_PCMCIA_TULIP),y)
+#  O_OBJS += tulip_cb.o
+#else
+#  ifeq ($(CONFIG_PCMCIA_TULIP),m)
+#    M_OBJS += tulip_cb.o
+#  endif
+#endif
+
+#ifeq ($(CONFIG_PCMCIA_EPIC100),y)
+#  O_OBJS += epic100_cb.o
+#else
+#  ifeq ($(CONFIG_PCMCIA_EPIC100),m)
+#    M_OBJS += epic100_cb.o
+#  endif
+#endif
+
 ifeq ($(CONFIG_PCMCIA_RAYCS),y)
   OX_OBJS += ray_cs.o
 else
@@ -37,4 +96,23 @@
   endif
 endif
 
+ifeq ($(CONFIG_PCMCIA_NETWAVE),y)
+  OX_OBJS += netwave_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_NETWAVE),m)
+  M_OBJS += netwave_cs.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCMCIA_WAVELAN),y)
+  OX_OBJS += wavelan_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_WAVELAN),m)
+  M_OBJS += wavelan_cs.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
+
+#epic100_cb.o: ../epic100.c
+#	$(CC) $(CFLAGS) -DCARDBUS -c -o $@ ../epic100.c
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/fmvj18x_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,1205 @@
+/*======================================================================
+    fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp
+
+    A fmvj18x (and its compatibles) PCMCIA client driver
+
+    Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp
+
+    TDK LAK-CD021 and CONTEC C-NET(PC)C support added by 
+    Nobuhiro Katayama, kata-n@po.iijnet.or.jp
+
+    The PCMCIA client code is based on code written by David Hinds.
+    Network code is based on the "FMV-18x driver" by Yutaka TAMIYA
+    but is actually largely Donald Becker's AT1700 driver, which
+    carries the following attribution:
+
+    Written 1993-94 by Donald Becker.
+
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.
+    
+    This software may be used and distributed according to the terms
+    of the GNU Public License, incorporated herein by reference.
+    
+    The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+    Center of Excellence in Space Data and Information Sciences
+    Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*
+   For debugging this driver you may need more information.
+   To enable printing registers or status, set 'fmvj18x_debug=#' option .
+ */
+#ifdef FMVJ18X_DEBUG
+static int fmvj18x_debug = FMVJ18X_DEBUG;
+#else
+static int fmvj18x_debug = 2;
+#endif /* FMVJ18X_DEBUG */
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* SRAM configuration */
+/* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
+static int sram_config = 0;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(sram_config, "i");
+
+/*====================================================================*/
+/* 
+   driver version infomation 
+ */
+#ifdef PCMCIA_DEBUG
+static char *version =
+ "fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp";
+#endif
+
+/*====================================================================*/
+/*
+    PCMCIA event handlers
+ */
+static void fmvj18x_config(dev_link_t *link);
+static void fmvj18x_release(u_long arg);
+static int fmvj18x_event(event_t event, int priority,
+			  event_callback_args_t *args);
+static int fmvj18x_init(struct net_device *dev);
+static dev_link_t *fmvj18x_attach(void);
+static void fmvj18x_detach(dev_link_t *);
+
+/*
+    LAN controler(MBH86960A) specific routines
+ */
+static int fjn_config(struct net_device *dev, struct ifmap *map);
+static int fjn_open(struct net_device *dev);
+static int fjn_close(struct net_device *dev);
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void fjn_rx(struct net_device *dev);
+static void fjn_reset(struct net_device *dev);
+static struct net_device_stats *fjn_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+
+static dev_info_t dev_info = "fmvj18x_cs";
+static dev_link_t *dev_list = NULL;
+
+/*
+    card type
+ */
+typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501 } cardtype_t;
+
+/*
+    driver specific data structure
+*/
+typedef struct local_info_t {
+    dev_node_t node;
+    struct net_device_stats stats;
+    long open_time;
+    uint tx_started:1;
+    uint tx_queue;
+    u_short tx_queue_len;
+    cardtype_t cardtype;
+    u_short sent;
+    u_char mc_filter[8];
+} local_info_t;
+
+#define MC_FILTERBREAK 64
+
+/*====================================================================*/
+/* 
+    ioport offset from the base address 
+ */
+#define TX_STATUS               0 /* transmit status register */
+#define RX_STATUS               1 /* receive status register */
+#define TX_INTR                 2 /* transmit interrupt mask register */
+#define RX_INTR                 3 /* receive interrupt mask register */
+#define TX_MODE                 4 /* transmit mode register */
+#define RX_MODE                 5 /* receive mode register */
+#define CONFIG_0                6 /* configuration register 0 */
+#define CONFIG_1                7 /* configuration register 1 */
+
+#define NODE_ID                 8 /* node ID register            (bank 0) */
+#define MAR_ADR                 8 /* multicast address registers (bank 1) */
+
+#define DATAPORT                8 /* buffer mem port registers   (bank 2) */
+#define TX_START               10 /* transmit start register */
+#define COL_CTRL               11 /* 16 collision control register */
+#define BMPR12                 12 /* reserved */
+#define BMPR13                 13 /* reserved */
+#define RX_SKIP                14 /* skip received packet register */
+
+#define LAN_CTRL               16 /* LAN card control register */
+
+#define MAC_ID               0x1a /* hardware address */
+
+/* 
+    control bits 
+ */
+#define ENA_TMT_OK           0x80
+#define ENA_TMT_REC          0x20
+#define ENA_COL              0x04
+#define ENA_16_COL           0x02
+#define ENA_TBUS_ERR         0x01
+
+#define ENA_PKT_RDY          0x80
+#define ENA_BUS_ERR          0x40
+#define ENA_LEN_ERR          0x08
+#define ENA_ALG_ERR          0x04
+#define ENA_CRC_ERR          0x02
+#define ENA_OVR_FLO          0x01
+
+/* flags */
+#define F_TMT_RDY            0x80 /* can accept new packet */
+#define F_NET_BSY            0x40 /* carrier is detected */
+#define F_TMT_OK             0x20 /* send packet successfully */
+#define F_SRT_PKT            0x10 /* short packet error */
+#define F_COL_ERR            0x04 /* collision error */
+#define F_16_COL             0x02 /* 16 collision error */
+#define F_TBUS_ERR           0x01 /* bus read error */
+
+#define F_PKT_RDY            0x80 /* packet(s) in buffer */
+#define F_BUS_ERR            0x40 /* bus read error */
+#define F_LEN_ERR            0x08 /* short packet */
+#define F_ALG_ERR            0x04 /* frame error */
+#define F_CRC_ERR            0x02 /* CRC error */
+#define F_OVR_FLO            0x01 /* overflow error */
+
+#define F_BUF_EMP            0x40 /* receive buffer is empty */
+
+#define F_SKP_PKT            0x05 /* drop packet in buffer */
+
+/* default bitmaps */
+#define D_TX_INTR  ( ENA_TMT_OK )
+#define D_RX_INTR  ( ENA_PKT_RDY | ENA_LEN_ERR \
+		   | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
+#define TX_STAT_M  ( F_TMT_RDY )
+#define RX_STAT_M  ( F_PKT_RDY | F_LEN_ERR \
+                   | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
+
+/* commands */
+#define D_TX_MODE            0x06 /* no tests, detect carrier */
+#define ID_MATCHED           0x02 /* (RX_MODE) */
+#define RECV_ALL             0x03 /* (RX_MODE) */
+#define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
+#define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
+#define CONFIG0_RST          0xda /* Data Link Controler off (CONFIG_0) */
+#define CONFIG0_RST_1        0xde /* Data Link Controler off (CONFIG_0) */
+#define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
+#define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
+#define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
+#define CHIP_OFF             0x80 /* contrl chip power off (CONFIG_1) */
+#define DO_TX                0x80 /* do transmit packet */
+#define SEND_PKT             0x81 /* send a packet */
+#define AUTO_MODE            0x07 /* Auto skip packet on 16 col detected */
+#define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
+#define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
+#define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
+#define INTR_OFF             0x0d /* LAN controler ignores interrupts */
+#define INTR_ON              0x1d /* LAN controler will catch interrupts */
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    fmvj18x_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *fmvj18x_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    int i, ret;
+    
+    DEBUG(0, "fmvj18x_attach()\n");
+    flush_stale_links();
+
+    /* Initialize the dev_link_t structure */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+
+    link->release.function = &fmvj18x_release;
+    link->release.data = (u_long)link;
+
+    /* The io structure describes IO port mapping */
+    link->io.NumPorts1 = 32;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 5;
+
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &fjn_interrupt;
+    
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* Make up a FMVJ18x specific data structure */
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev, 0, sizeof(struct net_device));
+    dev->priv = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    memset(dev->priv, 0, sizeof(local_info_t));
+
+    /* The FMVJ18x specific entries in the device structure. */
+    dev->hard_start_xmit = &fjn_start_xmit;
+    dev->set_config = &fjn_config;
+    dev->get_stats = &fjn_get_stats;
+    dev->set_multicast_list = &set_rx_mode;
+    ether_setup(dev);
+    dev->name = ((local_info_t *)dev->priv)->node.dev_name;
+    dev->init = &fmvj18x_init;
+    dev->open = &fjn_open;
+    dev->stop = &fjn_close;
+    dev->tbusy = 0xFF;
+    link->priv = link->irq.Instance = dev;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &fmvj18x_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	fmvj18x_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* fmvj18x_attach */
+
+/*====================================================================*/
+
+static void fmvj18x_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    long flags;
+    
+    DEBUG(0, "fmvj18x_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+    
+    if (link->state & DEV_CONFIG) {
+	fmvj18x_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev != NULL)
+	    unregister_netdev(dev);
+	if (dev->priv) 
+	    kfree(dev->priv);
+	kfree(dev);
+    }
+    kfree(link);
+    
+} /* fmvj18x_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void fmvj18x_config(dev_link_t *link)
+{
+    client_handle_t handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    struct net_device *dev;
+    u_short buf[32];
+    int i, last_fn, last_ret;
+    ioaddr_t ioaddr;
+    cardtype_t cardtype;
+    char *card_name = "unknown";
+    u_char *node_id;
+    
+    handle = link->handle;
+    dev =link->priv;
+
+    DEBUG(0, "fmvj18x_config(0x%p)\n", link);
+
+    /*
+       This reads the card's CONFIG tuple to find its configuration
+       registers.
+    */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = (u_char *)buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    link->conf.ConfigBase = parse.config.base; 
+    link->conf.Present = parse.config.rmask[0];
+
+    tuple.DesiredTuple = CISTPL_FUNCE;
+    tuple.TupleOffset = 0;
+    if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
+	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigIndex = parse.cftable_entry.index;
+	tuple.DesiredTuple = CISTPL_MANFID;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+
+	switch (le16_to_cpu(buf[0])) {
+	case MANFID_TDK:
+	    cardtype = TDK;
+	    break;
+	case MANFID_CONTEC:
+	    cardtype = CONTEC;
+	    break;
+	case MANFID_FUJITSU:
+	    if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10302)
+		cardtype = MBH10302;
+	    else if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304)
+		cardtype = MBH10304;
+	    else
+		cardtype = LA501;
+	    break;
+	default:
+	    cardtype = MBH10304;
+	}
+    } else {
+	/* old type card */
+	cardtype = MBH10302;
+	link->conf.ConfigIndex = 1;
+    }
+    CS_CHECK(RequestIO, link->handle, &link->io);
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    dev->tbusy = 0;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
+	goto failed;
+    }
+
+    ioaddr = dev->base_addr;
+
+    /* Power On chip and select bank 0 */
+    outb(BANK_0, ioaddr + CONFIG_1);
+    /* Reset controler */
+    if( sram_config == 0 ) 
+	outb(CONFIG0_RST, ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
+    
+    /* Set hardware address */
+    switch (cardtype) {
+    case MBH10304:
+    case TDK:
+    case LA501:
+    case CONTEC:
+	tuple.DesiredTuple = CISTPL_FUNCE;
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetTupleData, handle, &tuple);
+	if (cardtype == MBH10304) {
+	    /* MBH10304's CIS_FUNCE is corrupted */
+	    node_id = &(tuple.TupleData[5]);
+	    card_name = "FMV-J182";
+	} else {
+	    while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) {
+		CS_CHECK(GetNextTuple, handle, &tuple) ;
+		CS_CHECK(GetTupleData, handle, &tuple) ;
+	    }
+	    node_id = &(tuple.TupleData[2]);
+	    if( cardtype == TDK ) {
+		card_name = "TDK LAK-CD021";
+	    } else if( cardtype == LA501 ) {
+		card_name = "LA501";
+	    } else {
+		card_name = "C-NET(PC)C";
+	    }
+	}
+	/* Read MACID from CIS */
+	for (i = 0; i < 6; i++)
+	    dev->dev_addr[i] = node_id[i];
+	break;
+    case MBH10302:
+    default:
+	/* Read MACID from register */
+	for (i = 0; i < 6; i++) 
+	    dev->dev_addr[i] = inb(ioaddr + MAC_ID + i);
+	card_name = "FMV-J181";
+	break;
+    }
+
+    link->dev = &((local_info_t *)dev->priv)->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    ((struct local_info_t *)dev->priv)->cardtype = cardtype ;
+    /* print current configuration */
+    printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", 
+	   dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 
+	   dev->base_addr, dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    return;
+    
+cs_failed:
+    /* All Card Services errors end up here */
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    fmvj18x_release((u_long)link);
+
+} /* fmvj18x_config */
+ 
+/*====================================================================*/
+
+static void fmvj18x_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "fmvj18x_release(0x%p)\n", link);
+
+    /*
+       If the device is currently in use, we won't release until it
+       is actually closed.
+    */
+    if (link->open) {
+	DEBUG(1, "fmvj18x_cs: release postponed, '%s' "
+	      "still open\n", link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    /* Don't bother checking to see if these succeed or not */
+    CardServices(ReleaseWindow, link->win);
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    
+} /* fmvj18x_release */
+
+/*====================================================================*/
+
+static int fmvj18x_event(event_t event, int priority,
+			  event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+
+    DEBUG(1, "fmvj18x_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    dev->tbusy = 0xFF; 
+	    dev->start = 0;
+	    link->release.expires = jiffies + HZ/20;
+	    add_timer(&link->release);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	fmvj18x_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open) {
+		dev->tbusy = 0xFF; 
+		dev->start = 0;
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		dev->tbusy = 0;
+		dev->start = 1;
+		fjn_reset(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* fmvj18x_event */
+
+static int fmvj18x_init(struct net_device *dev)
+{
+    return 0;
+} /* fmvj18x_init */
+
+/*====================================================================*/
+
+static int __init init_fmvj18x_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "fmvj18x: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &fmvj18x_attach, &fmvj18x_detach);
+    return 0;
+}
+
+static void __exit exit_fmvj18x_cs(void)
+{
+    DEBUG(0, "fmvj18x_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	fmvj18x_detach(dev_list);
+}
+
+module_init(init_fmvj18x_cs);
+module_exit(exit_fmvj18x_cs);
+
+/*====================================================================*/
+
+static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    ioaddr_t ioaddr;
+    local_info_t *lp;
+    unsigned short tx_stat, rx_stat;
+
+    if (dev == NULL) {
+        printk(KERN_NOTICE "fjn_interrupt(): irq %d for "
+	       "unknown device.\n", irq);
+        return;
+    }
+    if (dev->interrupt) {
+        printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
+	       dev->name);
+        return;
+    }
+    dev->interrupt = 1;
+    lp = (struct local_info_t *)dev->priv;
+    ioaddr = dev->base_addr;
+
+    /* avoid multiple interrupts */
+    outw(0x0000, ioaddr + TX_INTR);
+
+    /* wait for a while */
+    udelay(1);
+
+    /* get status */
+    tx_stat = inb(ioaddr + TX_STATUS);
+    rx_stat = inb(ioaddr + RX_STATUS);
+
+    /* clear status */
+    outb(tx_stat, ioaddr + TX_STATUS);
+    outb(rx_stat, ioaddr + RX_STATUS);
+    
+    if (fmvj18x_debug > 4) {
+        printk(KERN_DEBUG "%s: interrupt, rx_status %02x.\n",
+	       dev->name, rx_stat);
+        printk(KERN_DEBUG "               tx_status %02x.\n",
+	       tx_stat);
+    }
+    
+    if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
+	/* there is packet(s) in rx buffer */
+	fjn_rx(dev);
+    }
+    if (tx_stat & F_TMT_RDY) {
+	lp->stats.tx_packets += lp->sent ;
+        lp->sent = 0 ;
+	if (lp->tx_queue) {
+	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
+	    lp->sent = lp->tx_queue ;
+	    lp->tx_queue = 0;
+	    lp->tx_queue_len = 0;
+	    dev->trans_start = jiffies;
+	    dev->tbusy = 0;
+	    mark_bh(NET_BH);	/* Inform upper layers. */
+	} else {
+	    lp->tx_started = 0;
+	    dev->tbusy = 0;
+	    mark_bh(NET_BH);	/* Inform upper layers. */
+	}
+    }
+    if (fmvj18x_debug > 4) {
+        printk(KERN_DEBUG "%s: exiting interrupt,\n", dev->name);
+        printk(KERN_DEBUG "    tx_status %02x, rx_status %02x.\n",
+	       tx_stat, rx_stat);
+    }
+
+    dev->interrupt = 0;
+    outb(D_TX_INTR, ioaddr + TX_INTR);
+    outb(D_RX_INTR, ioaddr + RX_INTR);
+
+    return;
+} /* fjn_interrupt */
+
+/*====================================================================*/
+
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    if (dev->tbusy) {
+	/* If we get here, some higher level has decided we are broken.
+	   There should really be a "kick me" function call instead. */
+	int tickssofar = jiffies - dev->trans_start;
+	if (tickssofar < 10)
+	    return 1;
+	printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+	       dev->name, htons(inw(ioaddr + TX_STATUS)),
+	       inb(ioaddr + TX_STATUS) & F_TMT_RDY
+	       ? "IRQ conflict" : "network cable problem");
+	printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+	       "%04x %04x %04x %04x %04x.\n",
+	       dev->name, htons(inw(ioaddr + 0)),
+	       htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
+	       htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
+	       htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
+	       htons(inw(ioaddr +14)));
+	lp->stats.tx_errors++;
+	/* ToDo: We should try to restart the adaptor... */
+	cli();
+
+	fjn_reset(dev);
+
+	lp->tx_started = 0;
+	lp->tx_queue = 0;
+	lp->tx_queue_len = 0;
+	lp->sent = 0;
+	lp->open_time = jiffies;
+	dev->interrupt = 0;
+	dev->tbusy = 0;
+	dev->start = 1;
+    
+	sti();
+    }
+
+    /* Block a timer-based transmit from overlapping.  This could better be
+       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+	printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name);
+    else {
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char *buf = skb->data;
+
+	if (length > ETH_FRAME_LEN) {
+	    if (fmvj18x_debug)
+		printk(KERN_NOTICE "%s: Attempting to send a large packet"
+		       " (%d bytes).\n", dev->name, length);
+	    return 1;
+	}
+
+	if (fmvj18x_debug > 4)
+	    printk(KERN_DEBUG "%s: Transmitting a packet of length %lu.\n",
+		   dev->name, (unsigned long)skb->len);
+	lp->stats.tx_bytes += skb->len;
+
+	/* Disable both interrupts. */
+	outw(0x0000, ioaddr + TX_INTR);
+
+	/* wait for a while */
+	udelay(1);
+
+	outw(length, ioaddr + DATAPORT);
+	outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+	lp->tx_queue++;
+	lp->tx_queue_len += ((length+3) & ~1);
+
+	if (lp->tx_started == 0) {
+	    /* If the Tx is idle, always trigger a transmit. */
+	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
+	    lp->sent = lp->tx_queue ;
+	    lp->tx_queue = 0;
+	    lp->tx_queue_len = 0;
+	    dev->trans_start = jiffies;
+	    lp->tx_started = 1;
+	    dev->tbusy = 0;
+	} else {
+	    if( sram_config == 0 ) {
+		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
+		    /* Yes, there is room for one more packet. */
+		    dev->tbusy = 0;
+	    } else {
+		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
+						lp->tx_queue < 127 )
+		    /* Yes, there is room for one more packet. */
+		    dev->tbusy = 0;
+	    }
+	}
+
+	/* Re-enable interrupts */
+	outb(D_TX_INTR, ioaddr + TX_INTR);
+	outb(D_RX_INTR, ioaddr + RX_INTR);
+    }
+    dev_kfree_skb (skb);
+
+    return 0;
+} /* fjn_start_xmit */
+
+/*====================================================================*/
+
+static void fjn_reset(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+
+    if (fmvj18x_debug > 4) {
+	printk(KERN_DEBUG "fjn_reset(%s) called.\n",dev->name);
+    }
+
+    /* Power On chip and select bank 0 */
+    outb(BANK_0, ioaddr + CONFIG_1);
+    /* Reset buffers */
+    if( sram_config == 0 ) 
+	outb(CONFIG0_RST, ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
+
+    /* Set Tx modes */
+    outb(D_TX_MODE, ioaddr + TX_MODE);
+    /* set Rx modes */
+    outb(ID_MATCHED, ioaddr + RX_MODE);
+
+    /* Set hardware address */
+    for (i = 0; i < 6; i++) 
+        outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
+
+    if (fmvj18x_debug > 4) {
+	printk(KERN_DEBUG "node id: ");
+	for (i = 0; i < 6; i++) 
+	    printk("%02X ",inb(ioaddr + NODE_ID + i));
+	printk("\n");
+    }
+    /* Switch to bank 1 */
+    outb(BANK_1, ioaddr + CONFIG_1);
+
+    /* set the multicast table to accept none. */
+    for (i = 0; i < 6; i++) 
+        outb(0x00, ioaddr + MAR_ADR + i);
+
+    /* Switch to bank 2 (runtime mode) */
+    outb(BANK_2, ioaddr + CONFIG_1);
+
+    /* set 16col ctrl bits */
+    if( lp->cardtype == TDK ) 
+        outb(TDK_AUTO_MODE, ioaddr + COL_CTRL);
+    else
+        outb(AUTO_MODE, ioaddr + COL_CTRL);
+
+    /* clear Reserved Regs */
+    outb(0x00, ioaddr + BMPR12);
+    outb(0x00, ioaddr + BMPR13);
+
+    /* reset Skip packet reg. */
+    outb(0x01, ioaddr + RX_SKIP);
+
+    /* Enable Tx and Rx */
+    if( sram_config == 0 )
+	outb(CONFIG0_DFL, ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_DFL_1, ioaddr + CONFIG_0);
+
+    /* Init receive pointer ? */
+    inw(ioaddr + DATAPORT);
+    inw(ioaddr + DATAPORT);
+
+    /* Clear all status */
+    outb(0xff, ioaddr + TX_STATUS);
+    outb(0xff, ioaddr + RX_STATUS);
+
+    if( lp->cardtype != TDK ) 
+    		outb(INTR_OFF, ioaddr + LAN_CTRL);
+
+    /* Turn on Rx interrupts */
+    outb(D_TX_INTR, ioaddr + TX_INTR);
+    outb(D_RX_INTR, ioaddr + RX_INTR);
+
+    /* Turn on interrupts from LAN card controler */
+    if( lp->cardtype != TDK ) 
+		outb(INTR_ON, ioaddr + LAN_CTRL);
+} /* fjn_reset */
+
+/*====================================================================*/
+
+static void fjn_rx(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
+
+    if (fmvj18x_debug > 4)
+        printk(KERN_DEBUG "%s: in rx_packet(), rx_status %02x.\n",
+               dev->name, inb(ioaddr + RX_STATUS));
+
+    while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
+	u_short status = inw(ioaddr + DATAPORT);
+
+	if (fmvj18x_debug > 4)
+	    printk(KERN_DEBUG "%s: Rxing packet mode %02x status %04x.\n",
+		   dev->name, inb(ioaddr + RX_MODE), status);
+#ifndef final_version
+	if (status == 0) {
+	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
+	    break;
+	}
+#endif
+	if ((status & 0xF0) != 0x20) {	/* There was an error. */
+	    lp->stats.rx_errors++;
+	    if (status & F_LEN_ERR) lp->stats.rx_length_errors++;
+	    if (status & F_ALG_ERR) lp->stats.rx_frame_errors++;
+	    if (status & F_CRC_ERR) lp->stats.rx_crc_errors++;
+	    if (status & F_OVR_FLO) lp->stats.rx_over_errors++;
+	} else {
+	    u_short pkt_len = inw(ioaddr + DATAPORT);
+	    /* Malloc up new buffer. */
+	    struct sk_buff *skb;
+
+	    if (pkt_len > 1550) {
+		printk(KERN_NOTICE "%s: The FMV-18x claimed a very "
+		       "large packet, size %d.\n", dev->name, pkt_len);
+		outb(F_SKP_PKT, ioaddr + RX_SKIP);
+		lp->stats.rx_errors++;
+		break;
+	    }
+	    skb = dev_alloc_skb(pkt_len+2);
+	    if (skb == NULL) {
+		printk(KERN_NOTICE "%s: Memory squeeze, dropping "
+		       "packet (len %d).\n", dev->name, pkt_len);
+		outb(F_SKP_PKT, ioaddr + RX_SKIP);
+		lp->stats.rx_dropped++;
+		break;
+	    }
+	    skb->dev = dev;
+
+	    skb_reserve(skb, 2);
+	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
+		    (pkt_len + 1) >> 1);
+	    skb->protocol = eth_type_trans(skb, dev);
+
+	    if (fmvj18x_debug > 5) {
+		int i;
+		printk(KERN_DEBUG "%s: Rxed packet of length %d: ",
+		       dev->name, pkt_len);
+		for (i = 0; i < 14; i++)
+		    printk(" %02x", skb->data[i]);
+		printk(".\n");
+	    }
+
+	    netif_rx(skb);
+	    lp->stats.rx_packets++;
+	    lp->stats.rx_bytes += skb->len;
+	}
+	if (--boguscount <= 0)
+	    break;
+    }
+
+    /* If any worth-while packets have been received, dev_rint()
+	   has done a mark_bh(NET_BH) for us and will work on them
+	   when we get to the bottom-half routine. */
+/*
+    if( lp->cardtype != TDK ) {
+	int i;
+	for (i = 0; i < 20; i++) {
+	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
+		break;
+	    (void)inw(ioaddr + DATAPORT);  /+ dummy status read +/
+	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
+	}
+
+	if (fmvj18x_debug > 5 && i > 0)
+	    printk(KERN_DEBUG "%s: Exint Rx packet with mode %02x after"
+		   " %d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
+    }
+*/
+
+    return;
+} /* fjn_rx */
+
+/*====================================================================*/
+
+static int fjn_config(struct net_device *dev, struct ifmap *map){
+    return 0;
+} /* fjn_config */
+
+static int fjn_open(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    dev_link_t *link;
+
+    if (fmvj18x_debug > 4)
+        printk(KERN_DEBUG "fjn_open('%s').\n", dev->name);
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (!DEV_OK(link))
+	return -ENODEV;
+    
+    link->open++;
+    
+    fjn_reset(dev);
+    
+    lp->tx_started = 0;
+    lp->tx_queue = 0;
+    lp->tx_queue_len = 0;
+    lp->open_time = jiffies;
+    dev->interrupt = 0;
+    dev->tbusy = 0;
+    dev->start = 1;
+    
+    MOD_INC_USE_COUNT;
+
+    return 0;
+} /* fjn_open */
+
+/*====================================================================*/
+
+static int fjn_close(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    dev_link_t *link;
+
+    if (fmvj18x_debug > 4)
+        printk(KERN_DEBUG "fjn_open('%s').\n", dev->name);
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (link == NULL)
+	return -ENODEV;
+    
+    if (fmvj18x_debug > 2)
+	printk(KERN_DEBUG "%s: shutting down ethercard.\n", dev->name);
+
+    ((struct local_info_t *)dev->priv)->open_time = 0;
+
+    dev->tbusy = 1;
+    dev->start = 0;
+
+    /* Set configuration register 0 to disable Tx and Rx. */
+    if( sram_config == 0 ) 
+	outb(CONFIG0_RST ,ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
+
+    /* Update the statistics -- ToDo. */
+
+    /* Power-down the chip.  Green, green, green! */
+    outb(CHIP_OFF ,ioaddr + CONFIG_1);
+
+    /* Set the ethernet adaptor disable IRQ */
+    if( lp->cardtype != TDK ) 
+    		outb(INTR_OFF, ioaddr + LAN_CTRL);
+
+    link->open--;
+    dev->start = 0;
+    if (link->state & DEV_STALE_CONFIG) {
+	link->release.expires = jiffies + HZ/20;
+	link->state |= DEV_RELEASE_PENDING;
+	add_timer(&link->release);
+    }
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* fjn_close */
+
+/*====================================================================*/
+
+static struct net_device_stats *fjn_get_stats(struct net_device *dev)
+{
+    local_info_t *lp = (local_info_t *)dev->priv;
+    return &lp->stats;
+} /* fjn_get_stats */
+
+/*====================================================================*/
+
+/*
+  Set the multicast/promiscuous mode for this adaptor.
+*/
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+    unsigned int crc = 0xffffffff;	/* Initial value. */
+    while(--length >= 0) {
+	unsigned char current_octet = *data++;
+	int bit;
+	for (bit = 8; --bit >= 0; current_octet >>= 1) {
+	    if ((crc ^ current_octet) & 1) {
+		crc >>= 1;
+		crc ^= ethernet_polynomial_le;
+	    } else
+		crc >>= 1;
+	}
+    }
+    return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    unsigned char mc_filter[8];		 /* Multicast hash filter */
+    long flags;
+    int i;
+    
+    if (dev->flags & IFF_PROMISC) {
+	/* Unconditionally log net taps. */
+	printk("%s: Promiscuous mode enabled.\n", dev->name);
+	memset(mc_filter, 0xff, sizeof(mc_filter));
+	outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
+    } else if (dev->mc_count > MC_FILTERBREAK
+	       ||  (dev->flags & IFF_ALLMULTI)) {
+	/* Too many to filter perfectly -- accept all multicasts. */
+	memset(mc_filter, 0xff, sizeof(mc_filter));
+	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
+    } else if (dev->mc_count == 0) {
+	memset(mc_filter, 0x00, sizeof(mc_filter));
+	outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
+    } else {
+	struct dev_mc_list *mclist;
+	int i;
+	
+	memset(mc_filter, 0, sizeof(mc_filter));
+	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+	     i++, mclist = mclist->next)
+	    set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+		    mc_filter);
+    }
+    
+    save_flags(flags);
+    cli();
+    if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
+	int saved_bank = inb(ioaddr + CONFIG_1);
+	/* Switch to bank 1 and set the multicast table. */
+	outb(0xe4, ioaddr + CONFIG_1);
+	for (i = 0; i < 8; i++)
+	    outb(mc_filter[i], ioaddr + 8 + i);
+	memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
+	outb(saved_bank, ioaddr + CONFIG_1);
+    }
+    restore_flags(flags);
+}
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/i82593.h linux/drivers/net/pcmcia/i82593.h
--- v2.3.22/linux/drivers/net/pcmcia/i82593.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/i82593.h	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,224 @@
+/*
+ * Definitions for Intel 82593 CSMA/CD Core LAN Controller
+ * The definitions are taken from the 1992 users manual with Intel
+ * order number 297125-001.
+ *
+ * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp
+ *
+ * Copyright 1994, Anders Klemets <klemets@it.kth.se>
+ *
+ * This software may be freely distributed for noncommercial purposes
+ * as long as this notice is retained.
+ * 
+ * HISTORY
+ * i82593.h,v
+ * Revision 1.1  1996/07/17 15:23:12  root
+ * Initial revision
+ *
+ * Revision 1.3  1995/04/05  15:13:58  adj
+ * Initial alpha release
+ *
+ * Revision 1.2  1994/06/16  23:57:31  klemets
+ * Mirrored all the fields in the configuration block.
+ *
+ * Revision 1.1  1994/06/02  20:25:34  klemets
+ * Initial revision
+ *
+ *
+ */
+#ifndef	_I82593_H
+#define	_I82593_H
+
+/* Intel 82593 CSMA/CD Core LAN Controller */
+
+/* Port 0 Command Register definitions */
+
+/* Execution operations */
+#define OP0_NOP			0	/* CHNL = 0 */
+#define OP0_SWIT_TO_PORT_1	0	/* CHNL = 1 */
+#define OP0_IA_SETUP		1
+#define OP0_CONFIGURE		2
+#define OP0_MC_SETUP		3
+#define OP0_TRANSMIT		4
+#define OP0_TDR			5
+#define OP0_DUMP		6
+#define OP0_DIAGNOSE		7
+#define OP0_TRANSMIT_NO_CRC	9
+#define OP0_RETRANSMIT		12
+#define OP0_ABORT		13
+/* Reception operations */
+#define OP0_RCV_ENABLE		8
+#define OP0_RCV_DISABLE		10
+#define OP0_STOP_RCV		11
+/* Status pointer control operations */
+#define OP0_FIX_PTR		15	/* CHNL = 1 */
+#define OP0_RLS_PTR		15	/* CHNL = 0 */
+#define OP0_RESET		14
+
+#define CR0_CHNL		(1 << 4)	/* 0=Channel 0, 1=Channel 1 */
+#define CR0_STATUS_0		0x00
+#define CR0_STATUS_1		0x20
+#define CR0_STATUS_2		0x40
+#define CR0_STATUS_3		0x60
+#define CR0_INT_ACK		(1 << 7)	/* 0=No ack, 1=acknowledge */
+
+/* Port 0 Status Register definitions */
+
+#define SR0_NO_RESULT		0		/* dummy */
+#define SR0_EVENT_MASK		0x0f
+#define SR0_IA_SETUP_DONE	1
+#define SR0_CONFIGURE_DONE	2
+#define SR0_MC_SETUP_DONE	3
+#define SR0_TRANSMIT_DONE	4
+#define SR0_TDR_DONE		5
+#define SR0_DUMP_DONE		6
+#define SR0_DIAGNOSE_PASSED	7
+#define SR0_TRANSMIT_NO_CRC_DONE 9
+#define SR0_RETRANSMIT_DONE	12
+#define SR0_EXECUTION_ABORTED	13
+#define SR0_END_OF_FRAME	8
+#define SR0_RECEPTION_ABORTED	10
+#define SR0_DIAGNOSE_FAILED	15
+#define SR0_STOP_REG_HIT	11
+
+#define SR0_CHNL		(1 << 4)
+#define SR0_EXECUTION		(1 << 5)
+#define SR0_RECEPTION		(1 << 6)
+#define SR0_INTERRUPT		(1 << 7)
+#define SR0_BOTH_RX_TX		(SR0_EXECUTION | SR0_RECEPTION)
+
+#define SR3_EXEC_STATE_MASK	0x03
+#define SR3_EXEC_IDLE		0
+#define SR3_TX_ABORT_IN_PROGRESS 1
+#define SR3_EXEC_ACTIVE		2
+#define SR3_ABORT_IN_PROGRESS	3
+#define SR3_EXEC_CHNL		(1 << 2)
+#define SR3_STP_ON_NO_RSRC	(1 << 3)
+#define SR3_RCVING_NO_RSRC	(1 << 4)
+#define SR3_RCV_STATE_MASK	0x60
+#define SR3_RCV_IDLE		0x00
+#define SR3_RCV_READY		0x20
+#define SR3_RCV_ACTIVE		0x40
+#define SR3_RCV_STOP_IN_PROG	0x60
+#define SR3_RCV_CHNL		(1 << 7)
+
+/* Port 1 Command Register definitions */
+
+#define OP1_NOP			0
+#define OP1_SWIT_TO_PORT_0	1
+#define OP1_INT_DISABLE		2
+#define OP1_INT_ENABLE		3
+#define OP1_SET_TS		5
+#define OP1_RST_TS		7
+#define OP1_POWER_DOWN		8
+#define OP1_RESET_RING_MNGMT	11
+#define OP1_RESET		14
+#define OP1_SEL_RST		15
+
+#define CR1_STATUS_4		0x00
+#define CR1_STATUS_5		0x20
+#define CR1_STATUS_6		0x40
+#define CR1_STOP_REG_UPDATE	(1 << 7)
+
+/* Receive frame status bits */
+
+#define	RX_RCLD			(1 << 0)
+#define RX_IA_MATCH		(1 << 1)
+#define	RX_NO_AD_MATCH		(1 << 2)
+#define RX_NO_SFD		(1 << 3)
+#define RX_SRT_FRM		(1 << 7)
+#define RX_OVRRUN		(1 << 8)
+#define RX_ALG_ERR		(1 << 10)
+#define RX_CRC_ERR		(1 << 11)
+#define RX_LEN_ERR		(1 << 12)
+#define RX_RCV_OK		(1 << 13)
+#define RX_TYP_LEN		(1 << 15)
+
+/* Transmit status bits */
+
+#define TX_NCOL_MASK		0x0f
+#define TX_FRTL			(1 << 4)
+#define TX_MAX_COL		(1 << 5)
+#define TX_HRT_BEAT		(1 << 6)
+#define TX_DEFER		(1 << 7)
+#define TX_UND_RUN		(1 << 8)
+#define TX_LOST_CTS		(1 << 9)
+#define TX_LOST_CRS		(1 << 10)
+#define TX_LTCOL		(1 << 11)
+#define TX_OK			(1 << 13)
+#define TX_COLL			(1 << 15)
+
+struct i82593_conf_block {
+  u_char fifo_limit : 4,
+  	 forgnesi   : 1,
+  	 fifo_32    : 1,
+  	 d6mod      : 1,
+  	 throttle_enb : 1;
+  u_char throttle   : 6,
+	 cntrxint   : 1,
+	 contin	    : 1;
+  u_char addr_len   : 3,
+  	 acloc 	    : 1,
+ 	 preamb_len : 2,
+  	 loopback   : 2;
+  u_char lin_prio   : 3,
+	 tbofstop   : 1,
+	 exp_prio   : 3,
+	 bof_met    : 1;
+  u_char	    : 4,
+	 ifrm_spc   : 4;
+  u_char	    : 5,
+	 slottim_low : 3;
+  u_char slottim_hi : 3,
+		    : 1,
+	 max_retr   : 4;
+  u_char prmisc     : 1,
+	 bc_dis     : 1,
+  		    : 1,
+	 crs_1	    : 1,
+	 nocrc_ins  : 1,
+	 crc_1632   : 1,
+  	 	    : 1,
+  	 crs_cdt    : 1;
+  u_char cs_filter  : 3,
+	 crs_src    : 1,
+	 cd_filter  : 3,
+		    : 1;
+  u_char	    : 2,
+  	 min_fr_len : 6;
+  u_char lng_typ    : 1,
+	 lng_fld    : 1,
+	 rxcrc_xf   : 1,
+	 artx	    : 1,
+	 sarec	    : 1,
+	 tx_jabber  : 1,	/* why is this called max_len in the manual? */
+	 hash_1	    : 1,
+  	 lbpkpol    : 1;
+  u_char	    : 6,
+  	 fdx	    : 1,
+  	  	    : 1;
+  u_char dummy_6    : 6,	/* supposed to be ones */
+  	 mult_ia    : 1,
+  	 dis_bof    : 1;
+  u_char dummy_1    : 1,	/* supposed to be one */
+	 tx_ifs_retrig : 2,
+	 mc_all     : 1,
+	 rcv_mon    : 2,
+	 frag_acpt  : 1,
+  	 tstrttrs   : 1;
+  u_char fretx	    : 1,
+	 runt_eop   : 1,
+	 hw_sw_pin  : 1,
+	 big_endn   : 1,
+	 syncrqs    : 1,
+	 sttlen     : 1,
+	 tx_eop     : 1,
+  	 rx_eop	    : 1;
+  u_char rbuf_size  : 5,
+	 rcvstop    : 1,
+  	 	    : 2;
+};
+
+#define I82593_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
+
+#endif _I82593_H
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/netwave_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/netwave_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,1709 @@
+/*********************************************************************
+ *                
+ * Filename:      netwave_cs.c
+ * Version:       0.4.1
+ * Description:   Netwave AirSurfer Wireless LAN PC Card driver
+ * Status:        Experimental.
+ * Authors:       John Markus Bjørndalen <johnm@cs.uit.no>
+ *                Dag Brattli <dagb@cs.uit.no>
+ *                David Hinds <dhinds@hyper.stanford.edu>
+ * Created at:    A long time ago!
+ * Modified at:   Mon Nov 10 11:54:37 1997
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1997 University of Tromsø, Norway
+ *
+ * Revision History:
+ *
+ *   08-Nov-97 15:14:47   John Markus Bjørndalen <johnm@cs.uit.no>
+ *    - Fixed some bugs in netwave_rx and cleaned it up a bit. 
+ *      (One of the bugs would have destroyed packets when receiving
+ *      multiple packets per interrupt). 
+ *    - Cleaned up parts of newave_hw_xmit. 
+ *    - A few general cleanups. 
+ *   24-Oct-97 13:17:36   Dag Brattli <dagb@cs.uit.no>
+ *    - Fixed netwave_rx receive function (got updated docs)
+ *   Others:
+ *    - Changed name from xircnw to netwave, take a look at 
+ *      http://www.netwave-wireless.com
+ *    - Some reorganizing of the code
+ *    - Removed possible race condition between interrupt handler and transmit
+ *      function
+ *    - Started to add wireless extensions, but still needs some coding
+ *    - Added watchdog for better handling of transmission timeouts 
+ *      (hopefully this works better)
+ ********************************************************************/
+
+/* To have statistics (just packets sent) define this */
+#undef NETWAVE_STATS
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>
+#endif
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+#define NETWAVE_REGOFF         0x8000
+/* The Netwave IO registers, offsets to iobase */
+#define NETWAVE_REG_COR        0x0
+#define NETWAVE_REG_CCSR       0x2
+#define NETWAVE_REG_ASR        0x4
+#define NETWAVE_REG_IMR        0xa
+#define NETWAVE_REG_PMR        0xc
+#define NETWAVE_REG_IOLOW      0x6
+#define NETWAVE_REG_IOHI       0x7
+#define NETWAVE_REG_IOCONTROL  0x8
+#define NETWAVE_REG_DATA       0xf
+/* The Netwave Extended IO registers, offsets to RamBase */
+#define NETWAVE_EREG_ASCC      0x114
+#define NETWAVE_EREG_RSER      0x120
+#define NETWAVE_EREG_RSERW     0x124
+#define NETWAVE_EREG_TSER      0x130
+#define NETWAVE_EREG_TSERW     0x134
+#define NETWAVE_EREG_CB        0x100
+#define NETWAVE_EREG_SPCQ      0x154
+#define NETWAVE_EREG_SPU       0x155
+#define NETWAVE_EREG_LIF       0x14e
+#define NETWAVE_EREG_ISPLQ     0x156
+#define NETWAVE_EREG_HHC       0x158
+#define NETWAVE_EREG_NI        0x16e
+#define NETWAVE_EREG_MHS       0x16b
+#define NETWAVE_EREG_TDP       0x140
+#define NETWAVE_EREG_RDP       0x150
+#define NETWAVE_EREG_PA        0x160
+#define NETWAVE_EREG_EC        0x180
+#define NETWAVE_EREG_CRBP      0x17a
+#define NETWAVE_EREG_ARW       0x166
+
+/*
+ * Commands used in the extended command buffer
+ * NETWAVE_EREG_CB (0x100-0x10F) 
+ */
+#define NETWAVE_CMD_NOP        0x00
+#define NETWAVE_CMD_SRC        0x01
+#define NETWAVE_CMD_STC        0x02
+#define NETWAVE_CMD_AMA        0x03
+#define NETWAVE_CMD_DMA        0x04
+#define NETWAVE_CMD_SAMA       0x05
+#define NETWAVE_CMD_ER         0x06
+#define NETWAVE_CMD_DR         0x07
+#define NETWAVE_CMD_TL         0x08
+#define NETWAVE_CMD_SRP        0x09
+#define NETWAVE_CMD_SSK        0x0a
+#define NETWAVE_CMD_SMD        0x0b
+#define NETWAVE_CMD_SAPD       0x0c
+#define NETWAVE_CMD_SSS        0x11
+/* End of Command marker */
+#define NETWAVE_CMD_EOC        0x00
+
+/* ASR register bits */
+#define NETWAVE_ASR_RXRDY   0x80
+#define NETWAVE_ASR_TXBA    0x01
+
+#define TX_TIMEOUT  20
+#define WATCHDOG_JIFFIES 32
+
+static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */
+static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */
+
+static const unsigned int corConfIENA   = 0x01; /* Interrupt enable */
+static const unsigned int corConfLVLREQ = 0x40; /* Keep high */
+
+static const unsigned int rxConfRxEna  = 0x80; /* Receive Enable */
+static const unsigned int rxConfMAC    = 0x20; /* MAC host receive mode*/ 
+static const unsigned int rxConfPro    = 0x10; /* Promiscuous */
+static const unsigned int rxConfAMP    = 0x08; /* Accept Multicast Packets */
+static const unsigned int rxConfBcast  = 0x04; /* Accept Broadcast Packets */
+
+static const unsigned int txConfTxEna  = 0x80; /* Transmit Enable */
+static const unsigned int txConfMAC    = 0x20; /* Host sends MAC mode */
+static const unsigned int txConfEUD    = 0x10; /* Enable Uni-Data packets */
+static const unsigned int txConfKey    = 0x02; /* Scramble data packets */
+static const unsigned int txConfLoop   = 0x01; /* Loopback mode */
+
+/*static int netwave_debug = 0;*/
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n";
+#else
+#define DEBUG(n, args...)
+#endif
+
+static dev_info_t dev_info = "netwave_cs";
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Choose the domain, default is 0x100 */
+static u_int  domain = 0x100;
+
+/* Scramble key, range from 0x0 to 0xffff.  
+ * 0x0 is no scrambling. 
+ */
+static u_int  scramble_key = 0x0;
+
+/* Shared memory speed, in ns. The documentation states that 
+ * the card should not be read faster than every 400ns. 
+ * This timing should be provided by the HBA. If it becomes a 
+ * problem, try setting mem_speed to 400. 
+ */
+static int mem_speed = 0;
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(domain, "i");
+MODULE_PARM(scramble_key, "i");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+/* PCMCIA (Card Services) related functions */
+static void netwave_release(u_long arg);     /* Card removal */
+static int  netwave_event(event_t event, int priority, 
+					      event_callback_args_t *args);
+static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card 
+													   insertion */
+static dev_link_t *netwave_attach(void);     /* Create instance */
+static void netwave_detach(dev_link_t *);    /* Destroy instance */
+static void netwave_flush_stale_links(void);	     /* Destroy all staled instances */
+
+/* Hardware configuration */
+static void netwave_doreset(ioaddr_t iobase, u_char* ramBase);
+static void netwave_reset(struct net_device *dev);
+
+/* Misc device stuff */
+static int netwave_open(struct net_device *dev);  /* Open the device */
+static int netwave_close(struct net_device *dev); /* Close the device */
+static int netwave_config(struct net_device *dev, struct ifmap *map);
+
+/* Packet transmission and Packet reception */
+static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
+static int netwave_rx( struct net_device *dev);
+
+/* Interrupt routines */
+static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void netwave_watchdog(u_long);	/* Transmission watchdog */
+
+/* Statistics */
+static void update_stats(struct net_device *dev);
+static struct enet_statistics *netwave_get_stats(struct net_device *dev);
+
+/* Wireless extensions */
+#ifdef WIRELESS_EXT
+static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev);
+#endif
+static int netwave_ioctl(struct net_device *, struct ifreq *, int);
+
+static void set_multicast_list(struct net_device *dev);
+
+/*
+   A linked list of "instances" of the skeleton device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally can't be allocated dynamically.
+*/
+
+#define SIOCGIPSNAP	SIOCDEVPRIVATE		/* Site Survey Snapshot */
+/*#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1*/
+
+#define MAX_ESA 10
+
+typedef struct net_addr {
+    u_char addr48[6];
+} net_addr;
+
+struct site_survey {
+    u_short length;
+    u_char  struct_revision;
+    u_char  roaming_state;
+	
+    u_char  sp_existsFlag;
+    u_char  sp_link_quality;
+    u_char  sp_max_link_quality;
+    u_char  linkQualityGoodFairBoundary;
+    u_char  linkQualityFairPoorBoundary;
+    u_char  sp_utilization;
+    u_char  sp_goodness;
+    u_char  sp_hotheadcount;
+    u_char  roaming_condition;
+	
+    net_addr sp;
+    u_char   numAPs;
+    net_addr nearByAccessPoints[MAX_ESA];
+};	
+   
+typedef struct netwave_private {
+    dev_node_t node;
+    u_char     *ramBase;
+    int        timeoutCounter;
+    int        lastExec;
+    struct timer_list      watchdog;	/* To avoid blocking state */
+    struct site_survey     nss;
+    struct enet_statistics stats;
+#ifdef WIRELESS_EXT
+    struct iw_statistics   iw_stats;    /* Wireless stats */
+#endif
+} netwave_private;
+
+#ifdef NETWAVE_STATS
+static struct enet_statistics *netwave_get_stats(struct net_device *dev);
+#endif
+
+/*
+ * The Netwave card is little-endian, so won't work for big endian
+ * systems.
+ */
+static inline unsigned short get_uint16(u_char* staddr) 
+{
+    return readw(staddr); /* Return only 16 bits */
+}
+
+static inline short get_int16(u_char* staddr)
+{
+    return readw(staddr);
+}
+
+/**************************************************************************/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/* 
+ * Wait until the WOC (Write Operation Complete) bit in the 
+ * ASR (Adapter Status Register) is asserted. 
+ * This should have aborted if it takes too long time. 
+ */
+static inline void wait_WOC(unsigned int iobase)
+{
+    /* Spin lock */
+    while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; 
+}
+
+#ifdef WIRELESS_EXT
+static void netwave_snapshot(netwave_private *priv, u_char *ramBase, 
+			     ioaddr_t iobase) { 
+    u_short resultBuffer;
+
+    /* if time since last snapshot is > 1 sec. (100 jiffies?)  then take 
+     * new snapshot, else return cached data. This is the recommended rate.  
+     */
+    if ( jiffies - priv->lastExec > 100) { 
+	/* Take site survey  snapshot */ 
+	/*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies -
+	  priv->lastExec); */
+	wait_WOC(iobase); 
+	writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); 
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); 
+	wait_WOC(iobase); 
+
+	/* Get result and copy to cach */ 
+	resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); 
+	copy_from_pc( &priv->nss, ramBase+resultBuffer, 
+		      sizeof(struct site_survey)); 
+    } 
+}
+#endif
+
+#ifdef WIRELESS_EXT
+/*
+ * Function netwave_get_wireless_stats (dev)
+ *
+ *    Wireless extensions statistics
+ *
+ */
+static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
+{	
+    unsigned long flags;
+    ioaddr_t iobase = dev->base_addr;
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    struct iw_statistics* wstats;
+	
+    wstats = &priv->iw_stats;
+
+    save_flags(flags);
+    cli();
+	
+    netwave_snapshot( priv, ramBase, iobase);
+
+    wstats->status = priv->nss.roaming_state;
+    wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); 
+    wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ);
+    wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f;
+    wstats->discard.nwid = 0L;
+    wstats->discard.code = 0L;
+    wstats->discard.misc = 0L;
+
+    restore_flags(flags);
+    
+    return &priv->iw_stats;
+}
+#endif
+
+/*
+ * Function netwave_init (dev)
+ *
+ *    We never need to do anything when a device is "initialized"
+ *    by the net software, because we only register already-found cards.
+ */
+int netwave_init(struct net_device *dev)
+{
+    /* We do all the initialization of this in netwave_attach instead */
+    return 0;
+}
+
+/*
+ * Function netwave_attach (void)
+ *
+ *     Creates an "instance" of the driver, allocating local data 
+ *     structures for one device.  The device is registered with Card 
+ *     Services.
+ *
+ *     The dev_link structure is initialized, but we don't actually
+ *     configure the card at this point -- we wait until we receive a
+ *     card insertion event.
+ */
+static dev_link_t *netwave_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    netwave_private *priv; 
+    int i, ret;
+    
+    DEBUG(0, "netwave_attach()\n");
+    
+    /* Perform some cleanup */
+    netwave_flush_stale_links();
+
+    /* Initialize the dev_link_t structure */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &netwave_release;
+    link->release.data = (u_long)link;
+	
+    /* The io structure describes IO port mapping */
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    /* link->io.NumPorts2 = 16; 
+       link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */
+    link->io.IOAddrLines = 5;
+    
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &netwave_interrupt;
+    
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Allocate space for private device-specific data */
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev, 0, sizeof(struct net_device));
+
+    dev->priv = kmalloc(sizeof(netwave_private), GFP_KERNEL);
+    memset(dev->priv, 0, sizeof(netwave_private));
+
+    /* Set the watchdog timer */
+    priv = (netwave_private *) dev->priv;
+    priv->watchdog.function = &netwave_watchdog;
+    priv->watchdog.data = (unsigned long) dev;
+
+    /* Netwave specific entries in the device structure */
+    dev->hard_start_xmit = &netwave_start_xmit;
+    dev->set_config = &netwave_config;
+    dev->get_stats  = &netwave_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    /* wireless extensions */
+#ifdef WIRELESS_EXT
+    dev->get_wireless_stats = &netwave_get_wireless_stats;
+#endif
+    dev->do_ioctl = &netwave_ioctl;
+
+    ether_setup(dev);
+    dev->name = ((struct netwave_private *)dev->priv)->node.dev_name;
+    dev->init = &netwave_init;
+    dev->open = &netwave_open;
+    dev->stop = &netwave_close;
+    dev->tbusy = 1;
+    link->priv = link->irq.Instance = dev;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &netwave_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	netwave_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* netwave_attach */
+
+/*
+ * Function netwave_detach (link)
+ *
+ *    This deletes a driver "instance".  The device is de-registered
+ *    with Card Services.  If it has been released, all local data
+ *    structures are freed.  Otherwise, the structures will be freed
+ *    when the device is released.
+ */
+static void netwave_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    long flags;
+
+    DEBUG(0, "netwave_detach(0x%p)\n", link);
+  
+    save_flags(flags);
+    if (link->state & DEV_RELEASE_PENDING) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    cli();
+    restore_flags(flags);
+
+    /*
+	  If the device is currently configured and active, we won't
+	  actually delete it yet.  Instead, it is marked so that when
+	  the release() function is called, that will trigger a proper
+	  detach().
+	*/
+    if (link->state & DEV_CONFIG) {
+	netwave_release((u_long) link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    DEBUG(1, "netwave_cs: detach postponed, '%s' still "
+		  "locked\n", link->dev->dev_name);
+	    
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+	
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+      {
+	DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n",
+	      link->dev->dev_name);
+	return;
+      }
+
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev != NULL)
+	  unregister_netdev(dev);
+	link->dev = NULL;
+	if (dev->priv)
+	    kfree(dev->priv);
+	kfree(link->priv);
+    }
+    kfree(link);
+    
+} /* netwave_detach */
+
+/*
+ * Function netwave_flush_stale_links (void)
+ *
+ *    This deletes all driver "instances" that need to be deleted.
+ *    Sometimes, netwave_detach can't be performed following a call from
+ *    cardmgr (device still open) and the device is put in a STALE_LINK
+ *    state.
+ *    This function is in charge of making the cleanup...
+ */
+static void netwave_flush_stale_links(void)
+{
+    dev_link_t *	link;		/* Current node in linked list */
+    dev_link_t *	next;		/* Next node in linked list */
+
+    DEBUG(1, "netwave_flush_stale_links(0x%p)\n", dev_list);
+
+    /* Go through the list */
+    for (link = dev_list; link; link = next) {
+        next = link->next;
+        /* Check if in need of being removed */
+        if(link->state & DEV_STALE_LINK)
+	    netwave_detach(link);
+    }
+} /* netwave_flush_stale_links */
+
+/*
+ * Function netwave_ioctl (dev, rq, cmd)
+ *
+ *     Perform ioctl : config & info stuff
+ *     This is the stuff that are treated the wireless extensions (iwconfig)
+ *
+ */
+static int netwave_ioctl(struct net_device *dev, /* ioctl device */
+						 struct ifreq *rq,	 /* Data passed */
+						 int	cmd)	     /* Ioctl number */
+{
+    unsigned long flags;
+    int			ret = 0;
+#ifdef WIRELESS_EXT
+    ioaddr_t iobase = dev->base_addr;
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    struct iwreq *wrq = (struct iwreq *) rq;
+#endif
+	
+    DEBUG( 0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
+	
+    /* Disable interrupts & save flags */
+    save_flags(flags);
+    cli();
+
+    /* Look what is the request */
+    switch(cmd) {
+	/* --------------- WIRELESS EXTENSIONS --------------- */
+#ifdef WIRELESS_EXT
+    case SIOCGIWNAME:
+	/* Get name */
+	strcpy(wrq->u.name, "Netwave");
+	break;
+    case SIOCSIWNWID:
+	/* Set domain */
+#if WIRELESS_EXT > 8
+	if(!wrq->u.nwid.disabled) {
+	    domain = wrq->u.nwid.value;
+#else	/* WIRELESS_EXT > 8 */
+	if(wrq->u.nwid.on) {
+	    domain = wrq->u.nwid.nwid;
+#endif	/* WIRELESS_EXT > 8 */
+	    printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", 
+		    (domain >> 8) & 0x01, domain & 0xff);
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	    writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	} break;
+    case SIOCGIWNWID:
+	/* Read domain*/
+#if WIRELESS_EXT > 8
+	wrq->u.nwid.value = domain;
+	wrq->u.nwid.disabled = 0;
+	wrq->u.nwid.fixed = 1;
+#else	/* WIRELESS_EXT > 8 */
+	wrq->u.nwid.nwid = domain;
+	wrq->u.nwid.on = 1;
+#endif	/* WIRELESS_EXT > 8 */
+	break;
+#if WIRELESS_EXT > 8	/* Note : The API did change... */
+    case SIOCGIWENCODE:
+	/* Get scramble key */
+	if(wrq->u.encoding.pointer != (caddr_t) 0)
+	  {
+	    char	key[2];
+	    key[1] = scramble_key & 0xff;
+	    key[0] = (scramble_key>>8) & 0xff;
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	    wrq->u.encoding.length = 2;
+	    if(copy_to_user(wrq->u.encoding.pointer, key, 2))
+	      ret = -EFAULT;
+	  }
+	break;
+    case SIOCSIWENCODE:
+	/* Set  scramble key */
+	if(wrq->u.encoding.pointer != (caddr_t) 0)
+	  {
+	    char	key[2];
+	    if(copy_from_user(key, wrq->u.encoding.pointer, 2))
+	      {
+		ret = -EFAULT;
+		break;
+	      }
+	    scramble_key = (key[0] << 8) | key[1];
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	  }
+	break;
+    case SIOCGIWMODE:
+      /* Mode of operation */
+	if(domain & 0x100)
+	  wrq->u.mode = IW_MODE_INFRA;
+	else
+	  wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#else /* WIRELESS_EXT > 8 */
+    case SIOCGIWENCODE:
+	/* Get scramble key */
+	wrq->u.encoding.code = scramble_key;
+	wrq->u.encoding.method = 1;
+	break;
+    case SIOCSIWENCODE:
+	/* Set  scramble key */
+	scramble_key = wrq->u.encoding.code;
+	wait_WOC(iobase);
+	writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+	writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	break;
+#endif /* WIRELESS_EXT > 8 */
+   case SIOCGIWRANGE:
+       /* Basic checking... */
+       if(wrq->u.data.pointer != (caddr_t) 0) {
+	   struct iw_range	range;
+		   
+	   /* Set the length (useless : its constant...) */
+	   wrq->u.data.length = sizeof(struct iw_range);
+		   
+	   /* Set information in the range struct */
+	   range.throughput = 450 * 1000;	/* don't argue on this ! */
+	   range.min_nwid = 0x0000;
+	   range.max_nwid = 0x01FF;
+
+	   range.num_channels = range.num_frequency = 0;
+		   
+	   range.sensitivity = 0x3F;
+	   range.max_qual.qual = 255;
+	   range.max_qual.level = 255;
+	   range.max_qual.noise = 0;
+		   
+#if WIRELESS_EXT > 7
+	   range.num_bitrates = 1;
+	   range.bitrate[0] = 1000000;	/* 1 Mb/s */
+#endif /* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+	   range.encoding_size[0] = 2;		/* 16 bits scrambling */
+	   range.num_encoding_sizes = 1;
+	   range.max_encoding_tokens = 1;	/* Only one key possible */
+#endif /* WIRELESS_EXT > 8 */
+
+	   /* Copy structure to the user buffer */
+	   if(copy_to_user(wrq->u.data.pointer, &range,
+			sizeof(struct iw_range)))
+	     ret = -EFAULT;
+       }
+       break;
+    case SIOCGIWPRIV:
+	/* Basic checking... */
+	if(wrq->u.data.pointer != (caddr_t) 0) {
+	    struct iw_priv_args	priv[] =
+	    {	/* cmd,		set_args,	get_args,	name */
+		{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
+		  sizeof(struct site_survey), 
+		  "getsitesurvey" },
+	    };
+			
+	    /* Set the number of ioctl available */
+	    wrq->u.data.length = 1;
+			
+	    /* Copy structure to the user buffer */
+	    if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+			 sizeof(priv)))
+	      ret = -EFAULT;
+	} 
+	break;
+    case SIOCGIPSNAP:
+	if(wrq->u.data.pointer != (caddr_t) 0) {
+	    /* Take snapshot of environment */
+	    netwave_snapshot( priv, ramBase, iobase);
+	    wrq->u.data.length = priv->nss.length;
+	    /* Copy structure to the user buffer */
+	    if(copy_to_user(wrq->u.data.pointer, 
+			 (u_char *) &priv->nss,
+			 sizeof( struct site_survey)))
+	      {
+		printk(KERN_DEBUG "Bad buffer!\n");
+		break;
+	      }
+
+	    priv->lastExec = jiffies;
+	}
+	break;
+#endif
+    default:
+	ret = -EOPNOTSUPP;
+    }
+	
+    /* ReEnable interrupts & restore flags */
+    restore_flags(flags);
+    
+    return ret;
+}
+
+/*
+ * Function netwave_pcmcia_config (link)
+ *
+ *     netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION 
+ *     event is received, to configure the PCMCIA socket, and to make the
+ *     device available to the system. 
+ *
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void netwave_pcmcia_config(dev_link_t *link) {
+    client_handle_t handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    struct net_device *dev;
+    int i, j, last_ret, last_fn;
+    u_char buf[64];
+    win_req_t req;
+    memreq_t mem;
+    u_char *ramBase = NULL;
+    /*    modwin_t mod;
+	  short iobase, *phys_addr;
+	  */  
+    handle = link->handle;
+    dev = link->priv;
+
+    DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
+
+    /*
+      This reads the card's CONFIG tuple to find its configuration
+      registers.
+    */
+    tuple.Attributes = 0;
+    tuple.TupleData = (cisdata_t *) buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+	
+    /*
+     *  Try allocating IO ports.  This tries a few fixed addresses.
+     *  If you want, you can also read the card's config table to
+     *  pick addresses -- see the serial driver for an example.
+     */
+    for (j = 0x0; j < 0x400; j += 0x20) {
+	link->io.BasePort1 = j ^ 0x300;
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	goto failed;
+    }
+		
+    /*
+     *  Now allocate an interrupt line.  Note that this does not
+     *  actually assign a handler to the interrupt.
+     */
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+	
+    /*
+     *  This actually configures the PCMCIA socket -- setting up
+     *  the I/O windows and the interrupt mapping.
+     */
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    
+    /*
+     *  Allocate a 32K memory window.  Note that the dev_link_t
+     *  structure provides space for one window handle -- if your
+     *  device needs several windows, you'll need to keep track of
+     *  the handles in your private data structure, link->priv.
+     */
+    DEBUG(1, "Setting mem speed of %d\n", mem_speed);
+    
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0x8000;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    mem.CardOffset = 0x20000; mem.Page = 0; 
+    CS_CHECK(MapMemPage, link->win, &mem);
+    
+    /* Store base address of the common window frame */
+    ramBase = ioremap(req.Base, 0x8000);
+    ((netwave_private*)dev->priv)->ramBase = ramBase;
+    
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    dev->tbusy = 0;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
+	goto failed;
+    }
+	
+    link->state &= ~DEV_CONFIG_PENDING;
+	
+    link->dev = &((netwave_private *)dev->priv)->node;
+
+    /* Reset card before reading physical address */
+    netwave_doreset(dev->base_addr, ramBase);
+    
+    /* Read the ethernet address and fill in the Netwave registers. */
+    for (i = 0; i < 6; i++) 
+	dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
+
+    printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
+	   "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
+	   (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
+	   (int) readb(ramBase+NETWAVE_EREG_NI+1));
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    /* get revision words */
+    printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
+	   get_uint16(ramBase + NETWAVE_EREG_ARW),
+	   get_uint16(ramBase + NETWAVE_EREG_ARW+2));
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    netwave_release((u_long)link);
+    return;
+} /* netwave_pcmcia_config */
+
+/*
+ * Function netwave_release (arg)
+ *
+ *    After a card is removed, netwave_release() will unregister the net
+ *    device, and release the PCMCIA configuration.  If the device is
+ *    still open, this will be postponed until it is closed.
+ */
+static void netwave_release(u_long arg) {
+    dev_link_t *link = (dev_link_t *)arg;
+    struct net_device *dev = link->priv;
+
+    DEBUG(0, "netwave_release(0x%p)\n", link);
+
+    /*
+      If the device is currently in use, we won't release until it
+      is actually closed.
+      */
+    if (link->open) {
+	printk(KERN_DEBUG "netwave_cs: release postponed, '%s' still open\n",
+	       link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+	
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win) {
+	iounmap(((netwave_private *)dev->priv)->ramBase);
+	CardServices(ReleaseWindow, link->win);
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+ 
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+    
+} /* netwave_release */
+
+/*
+ * Function netwave_event (event, priority, args)
+ *
+ *    The card status event handler.  Mostly, this schedules other
+ *    stuff to run after an event is received.  A CARD_REMOVAL event
+ *    also sets some flags to discourage the net drivers from trying
+ *    to talk to the card any more.
+ *
+ *    When a CARD_REMOVAL event is received, we immediately set a flag
+ *    to block future accesses to this device.  All the functions that
+ *    actually access the device should check this flag to make sure
+ *    the card is still present.
+ *
+ */
+static int netwave_event(event_t event, int priority,
+			 event_callback_args_t *args) {
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+	
+    DEBUG(1, "netwave_event(0x%06x)\n", event);
+  
+    switch (event) {
+    case CS_EVENT_REGISTRATION_COMPLETE:
+	DEBUG(0, "netwave_cs: registration complete\n");
+	break;
+
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    dev->tbusy = 1; dev->start = 0;
+	    /* ((netwave_private *)link->priv)->block = 1; */
+	    link->release.expires = jiffies + 5;
+	    add_timer(&link->release);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	netwave_pcmcia_config( link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open) {
+		dev->tbusy = 1; dev->start = 0;
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		netwave_reset(dev);
+		dev->tbusy = 0; dev->start = 1;
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* netwave_event */
+
+/*
+ * Function netwave_doreset (ioBase, ramBase)
+ *
+ *    Proper hardware reset of the card.
+ */
+static void netwave_doreset(ioaddr_t ioBase, u_char* ramBase) {
+    /* Reset card */
+    wait_WOC(ioBase);
+    outb(0x80, ioBase + NETWAVE_REG_PMR);
+    writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */
+    outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */
+}
+
+/*
+ * Function netwave_reset (dev)
+ *
+ *    Reset and restore all of the netwave registers 
+ */
+static void netwave_reset(struct net_device *dev) {
+    /* u_char state; */
+    netwave_private *priv = (netwave_private*) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+
+    DEBUG(0, "netwave_reset: Done with hardware reset\n");
+
+    priv->timeoutCounter = 0;
+	
+    /* If watchdog was activated, kill it ! */
+    del_timer(&priv->watchdog);
+	
+    /* Reset card */
+    netwave_doreset(iobase, ramBase);
+    printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n");
+	
+    /* Write a NOP to check the card */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	
+    /* Set receive conf */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+    
+    /* Set transmit conf */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+    
+    /* Now set the MU Domain */
+    printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff);
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	
+    /* Set scramble key */
+    printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key);
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+
+    /* Enable interrupts, bit 4 high to keep unused
+     * source from interrupting us, bit 2 high to 
+     * set interrupt enable, 567 to enable TxDN, 
+     * RxErr and RxRdy
+     */
+    wait_WOC(iobase);
+    outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR);
+
+    /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36
+     * waitWOC
+     * skriv 80 til d000:3688
+     * sjekk om det ble 80
+     */
+    
+    /* Enable Receiver */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	
+    /* Set the IENA bit in COR */
+    wait_WOC(iobase);
+    outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR);
+}
+
+/*
+ * Function netwave_config (dev, map)
+ *
+ *    Configure device, this work is done by netwave_pcmcia_config when a
+ *    card is inserted
+ */
+static int netwave_config(struct net_device *dev, struct ifmap *map) {
+    return 0; 
+}
+
+/*
+ * Function netwave_hw_xmit (data, len, dev)    
+ */
+static int netwave_hw_xmit(unsigned char* data, int len,
+			   struct net_device* dev) {
+    unsigned long flags;
+    unsigned int TxFreeList,
+	         curBuff,
+	         MaxData, 
+                 DataOffset;
+    int tmpcount; 
+	
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char* ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+	
+    /* Disable interrupts & save flags */
+    save_flags(flags);
+    cli();
+
+    /* Check if there are transmit buffers available */
+    wait_WOC(iobase);
+    if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) {
+	/* No buffers available */
+	printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n",
+	       dev->name);
+	return 1;
+    }
+	
+    priv->stats.tx_bytes += len;
+
+    DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n",
+	  readb(ramBase + NETWAVE_EREG_SPCQ),
+	  readb(ramBase + NETWAVE_EREG_SPU),
+	  readb(ramBase + NETWAVE_EREG_LIF),
+	  readb(ramBase + NETWAVE_EREG_ISPLQ));
+
+    /* Now try to insert it into the adapters free memory */
+    wait_WOC(iobase);
+    TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP);
+    MaxData    = get_uint16(ramBase + NETWAVE_EREG_TDP+2);
+    DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4);
+	
+    DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n",
+	  TxFreeList, MaxData, DataOffset);
+
+    /* Copy packet to the adapter fragment buffers */
+    curBuff = TxFreeList; 
+    tmpcount = 0; 
+    while (tmpcount < len) {
+	int tmplen = len - tmpcount; 
+	copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, 
+		   (tmplen < MaxData) ? tmplen : MaxData);
+	tmpcount += MaxData;
+			
+	/* Advance to next buffer */
+	curBuff = get_uint16(ramBase + curBuff);
+    }
+    
+    /* Now issue transmit list */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	
+    /* If watchdog not already active, activate it... */
+    if(priv->watchdog.prev == (struct timer_list *) NULL) {
+
+	/* set timer to expire in WATCHDOG_JIFFIES */
+	priv->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+	add_timer(&priv->watchdog);
+    }
+    restore_flags( flags);
+    return 0;
+}
+
+static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	/* This flag indicate that the hardware can't perform a transmission.
+	 * Theoritically, NET3 check it before sending a packet to the driver,
+	 * but in fact it never do that and pool continuously.
+	 * As the watchdog will abort too long transmissions, we are quite safe...
+	 */
+
+    if (dev->tbusy) {
+	/* Handled by watchdog */
+	return 1;
+		
+	/* If we get here, some higher level has decided we are broken.
+	   There should really be a 'kick me' function call instead.
+	   */
+	/*int tickssofar = jiffies - dev->trans_start;*/
+	/* printk("xmit called with busy. tickssofar %d\n", tickssofar); */
+	/*if (tickssofar < TX_TIMEOUT) 
+	  return 1;
+	  */
+	/* Should also detect if the kernel tries to xmit
+	 * on a stopped card. 
+	 */
+       
+	/*if (netwave_debug > 0)
+	  printk(KERN_DEBUG "%s timed out.\n", dev->name);
+	  netwave_reset(dev); 
+	  dev->trans_start = jiffies;
+	  dev->tbusy = 0;*/
+    }
+
+    /* Sending a NULL skb means some higher layer thinks we've missed an
+     * tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
+     * itself. 
+     */
+
+    /* Block a timer-based transmit from overlapping. This could 
+     * better be done with atomic_swap(1, dev->tbusy, but set_bit()
+     * works as well 
+     */
+    if ( test_and_set_bit(0, (void*)&dev->tbusy) != 0) 
+	printk("%s: Transmitter access conflict.\n", dev->name);
+    else {
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char* buf = skb->data;
+	
+	if (netwave_hw_xmit( buf, length, dev) == 1) {
+	    /* Some error, let's make them call us another time? */
+	    dev->tbusy = 0;
+	}
+	dev->trans_start = jiffies;
+    }
+    dev_kfree_skb(skb);
+    
+    return 0;
+} /* netwave_start_xmit */
+
+/*
+ * Function netwave_interrupt (irq, dev_id, regs)
+ *
+ *    This function is the interrupt handler for the Netwave card. This
+ *    routine will be called whenever: 
+ *	  1. A packet is received.
+ *	  2. A packet has successfully been transfered and the unit is
+ *	     ready to transmit another packet.
+ *	  3. A command has completed execution.
+ */
+static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
+    ioaddr_t iobase;
+    u_char *ramBase;
+    struct net_device *dev = (struct net_device *)dev_id;
+    struct netwave_private *priv;
+    int i;
+    dev_link_t *link;
+    
+	if ((dev == NULL) | (!dev->start))
+		return;
+    
+    priv = (netwave_private *)dev->priv;
+    
+    if (dev->interrupt) {
+	printk("%s: re-entering the interrupt handler.\n", dev->name);
+	return;
+    }
+    dev->interrupt = 1;
+	
+    /* Find the correct dev_link_t */
+    for (link = dev_list; NULL != link; link = link->next)
+	if (dev == link->priv) break;
+    
+    iobase = dev->base_addr;
+    ramBase = priv->ramBase;
+	
+    /* Now find what caused the interrupt, check while interrupts ready */
+    for (i = 0; i < 10; i++) {
+	u_char status;
+		
+	wait_WOC(iobase);	
+	if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02))
+	    break; /* None of the interrupt sources asserted */
+	
+        status = inb(iobase + NETWAVE_REG_ASR);
+		
+	if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) {
+	    DEBUG( 1, "netwave_interupt: Interrupt with status 0x%x "
+		   "from removed or suspended card!\n", status);
+	    break;
+	}
+		
+	/* RxRdy */
+	if (status & 0x80) {
+	    netwave_rx(dev);
+	    /* wait_WOC(iobase); */
+	    /* RxRdy cannot be reset directly by the host */
+	}
+	/* RxErr */
+	if (status & 0x40) {
+	    u_char rser;
+			
+	    rser = readb(ramBase + NETWAVE_EREG_RSER);			
+	    
+	    if (rser & 0x04) {
+		++priv->stats.rx_dropped; 
+		++priv->stats.rx_crc_errors;
+	    }
+	    if (rser & 0x02)
+		++priv->stats.rx_frame_errors;
+			
+	    /* Clear the RxErr bit in RSER. RSER+4 is the
+	     * write part. Also clear the RxCRC (0x04) and 
+	     * RxBig (0x02) bits if present */
+	    wait_WOC(iobase);
+	    writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4);
+
+	    /* Write bit 6 high to ASCC to clear RxErr in ASR,
+	     * WOC must be set first! 
+	     */
+	    wait_WOC(iobase);
+	    writeb(0x40, ramBase + NETWAVE_EREG_ASCC);
+
+	    /* Remember to count up priv->stats on error packets */
+	    ++priv->stats.rx_errors;
+	}
+	/* TxDN */
+	if (status & 0x20) {
+	    int txStatus;
+
+	    txStatus = readb(ramBase + NETWAVE_EREG_TSER);
+	    DEBUG(3, "Transmit done. TSER = %x id %x\n", 
+		  txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1));
+	    
+	    if (txStatus & 0x20) {
+		/* Transmitting was okay, clear bits */
+		wait_WOC(iobase);
+		writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4);
+		++priv->stats.tx_packets;
+	    }
+			
+	    if (txStatus & 0xd0) {
+		if (txStatus & 0x80) {
+		    ++priv->stats.collisions; /* Because of /proc/net/dev*/
+		    /* ++priv->stats.tx_aborted_errors; */
+		    /* printk("Collision. %ld\n", jiffies - dev->trans_start); */
+		}
+		if (txStatus & 0x40) 
+		    ++priv->stats.tx_carrier_errors;
+		/* 0x80 TxGU Transmit giveup - nine times and no luck
+		 * 0x40 TxNOAP No access point. Discarded packet.
+		 * 0x10 TxErr Transmit error. Always set when 
+		 *      TxGU and TxNOAP is set. (Those are the only ones
+		 *      to set TxErr).
+		 */
+		DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", 
+		      txStatus);
+		
+		/* Clear out TxGU, TxNOAP, TxErr and TxTrys */
+		wait_WOC(iobase);
+		writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4);
+		++priv->stats.tx_errors;
+	    }
+	    DEBUG(3, "New status is TSER %x ASR %x\n",
+		  readb(ramBase + NETWAVE_EREG_TSER),
+		  inb(iobase + NETWAVE_REG_ASR));
+			
+	    /* If watchdog was activated, kill it ! */
+	    del_timer(&priv->watchdog);
+
+	    dev->tbusy = 0;
+	    mark_bh(NET_BH);
+	}
+	/* TxBA, this would trigger on all error packets received */
+	/* if (status & 0x01) {
+	   if (netwave_debug > 3) 
+	   printk(KERN_DEBUG "Transmit buffers available, %x\n", status); 
+	   } 
+	   */
+    }
+    /* done.. */
+    dev->interrupt = 0;
+    return;
+} /* netwave_interrupt */
+
+/*
+ * Function netwave_watchdog (a)
+ *
+ *    Watchdog : when we start a transmission, we set a timer in the
+ *    kernel.  If the transmission complete, this timer is disabled. If
+ *    it expire, we reset the card.
+ *
+ */
+static void netwave_watchdog(u_long a) {
+    struct net_device *dev;
+    ioaddr_t iobase;
+	
+    dev = (struct net_device *) a;
+    iobase = dev->base_addr;
+    
+    DEBUG( 1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name);
+	
+    netwave_reset(dev); 
+	
+    /* We are not waiting anymore... */
+    dev->tbusy = 0;
+	
+} /* netwave_watchdog */
+
+static struct enet_statistics *netwave_get_stats(struct net_device *dev) {
+    netwave_private *priv = (netwave_private*)dev->priv;
+
+    update_stats(dev);
+
+    DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x"
+	  " %x tx %x %x %x %x\n", 
+	  readb(priv->ramBase + NETWAVE_EREG_SPCQ),
+	  readb(priv->ramBase + NETWAVE_EREG_SPU),
+	  readb(priv->ramBase + NETWAVE_EREG_LIF),
+	  readb(priv->ramBase + NETWAVE_EREG_ISPLQ),
+	  readb(priv->ramBase + NETWAVE_EREG_MHS),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xe),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xf),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x18),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x19),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b));
+
+    return &priv->stats;
+}
+
+static void update_stats(struct net_device *dev) {
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+
+/*     netwave_private *priv = (netwave_private*) dev->priv;
+    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
+    priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */
+
+    restore_flags(flags);
+}
+
+static int netwave_rx(struct net_device *dev) {
+    netwave_private *priv = (netwave_private*)(dev->priv);
+    u_char *ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+    u_char rxStatus;
+    struct sk_buff *skb = NULL;
+    unsigned int curBuffer,
+		rcvList;
+    int rcvLen;
+    int tmpcount = 0;
+    int dataCount, dataOffset;
+    int i;
+    u_char *ptr;
+	
+    DEBUG(3, "xinw_rx: Receiving ... \n");
+
+    /* Receive max 10 packets for now. */
+    for (i = 0; i < 10; i++) {
+	/* Any packets? */
+	wait_WOC(iobase);
+	rxStatus = readb(ramBase + NETWAVE_EREG_RSER);		
+	if ( !( rxStatus & 0x80)) /* No more packets */
+	    break;
+		
+	/* Check if multicast/broadcast or other */
+	/* multicast = (rxStatus & 0x20);  */
+		
+	/* The receive list pointer and length of the packet */
+	wait_WOC(iobase);
+	rcvLen  = get_int16( ramBase + NETWAVE_EREG_RDP);
+	rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2);
+		
+	if (rcvLen < 0) {
+	    printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", 
+		   rcvLen);
+	    return 0;
+	}
+		
+	skb = dev_alloc_skb(rcvLen+5);
+	if (skb == NULL) {
+	    DEBUG(1, "netwave_rx: Could not allocate an sk_buff of "
+		  "length %d\n", rcvLen);
+	    ++priv->stats.rx_dropped; 
+	    /* Tell the adapter to skip the packet */
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	    return 0;
+	}
+
+	skb_reserve( skb, 2);  /* Align IP on 16 byte */
+	skb_put( skb, rcvLen);
+	skb->dev = dev;
+
+	/* Copy packet fragments to the skb data area */
+	ptr = (u_char*) skb->data;
+	curBuffer = rcvList;
+	tmpcount = 0; 
+	while ( tmpcount < rcvLen) {
+	    /* Get length and offset of current buffer */
+	    dataCount  = get_uint16( ramBase+curBuffer+2);
+	    dataOffset = get_uint16( ramBase+curBuffer+4);
+		
+	    copy_from_pc( ptr + tmpcount,
+			  ramBase+curBuffer+dataOffset, dataCount);
+
+	    tmpcount += dataCount;
+		
+	    /* Point to next buffer */
+	    curBuffer = get_uint16(ramBase + curBuffer);
+	}
+	
+	skb->protocol = eth_type_trans(skb,dev);
+	/* Queue packet for network layer */
+	netif_rx(skb);
+		
+	/* Got the packet, tell the adapter to skip it */
+	wait_WOC(iobase);
+	writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	DEBUG(3, "Packet reception ok\n");
+		
+	priv->stats.rx_packets++;
+
+	priv->stats.rx_bytes += skb->len;
+    }
+    return 0;
+}
+
+static int netwave_open(struct net_device *dev) {
+    dev_link_t *link;
+
+    DEBUG(1, "netwave_open: starting.\n");
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+	
+    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    netwave_reset(dev);
+	
+    return 0;
+}
+
+static int netwave_close(struct net_device *dev) {
+    dev_link_t *link;
+    netwave_private *priv = (netwave_private *) dev->priv;
+
+    DEBUG(1, "netwave_close: finishing.\n");
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (link == NULL)
+	return -ENODEV;
+	
+    /* If watchdog was activated, kill it ! */
+    del_timer(&priv->watchdog);
+	
+    link->open--;
+    dev->start = 0;
+    if (link->state & DEV_STALE_CONFIG) {
+	link->release.expires = jiffies + 5;
+	link->state |= DEV_RELEASE_PENDING;
+	add_timer(&link->release);
+    }	
+	
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+static int __init init_netwave_cs(void) {
+    servinfo_t serv;
+
+    DEBUG(0, "%s\n", version);
+
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk("netwave_cs: Card Services release does not match!\n");
+	return -1;
+    }
+ 
+    register_pccard_driver(&dev_info, &netwave_attach, &netwave_detach);
+	
+    return 0;
+}
+
+static void __exit exit_netwave_cs(void) {
+    DEBUG(1, "netwave_cs: unloading\n");
+
+    unregister_pccard_driver(&dev_info);
+
+    /* Do some cleanup of the device list */
+    netwave_flush_stale_links();
+    if(dev_list != NULL)	/* Critical situation */
+        printk("netwave_cs: devices remaining when removing module\n");
+}
+
+module_init(init_netwave_cs);
+module_exit(exit_netwave_cs);
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1	Promiscuous mode, receive all packets
+   num_addrs == 0	Normal mode, clear multicast list
+   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+   best-effort filtering.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+    ioaddr_t iobase = dev->base_addr;
+    u_char* ramBase = ((netwave_private*) dev->priv)->ramBase;
+    u_char  rcvMode = 0;
+   
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+	static int old = 0;
+	if (old != dev->mc_count) {
+	    old = dev->mc_count;
+	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+		  dev->name, dev->mc_count);
+	}
+    }
+#endif
+	
+    if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
+	/* Multicast Mode */
+	rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast;
+    } else if (dev->flags & IFF_PROMISC) {
+	/* Promiscous mode */
+	rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast;
+    } else {
+	/* Normal mode */
+	rcvMode = rxConfRxEna + rxConfBcast;
+    }
+	
+    /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/
+    /* Now set receive mode */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+}
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/nmclan_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/nmclan_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,1778 @@
+/* ----------------------------------------------------------------------------
+Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN.
+  nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao
+
+  The Ethernet LAN uses the Advanced Micro Devices (AMD) Am79C940 Media
+  Access Controller for Ethernet (MACE).  It is essentially the Am2150
+  PCMCIA Ethernet card contained in the the Am2150 Demo Kit.
+
+Written by Roger C. Pao <rpao@paonet.org>
+  Copyright 1995 Roger C. Pao
+
+  This software may be used and distributed according to the terms of
+  the GNU Public License.
+
+Ported to Linux 1.3.* network driver environment by
+  Matti Aarnio <mea@utu.fi>
+
+References
+
+  Am2150 Technical Reference Manual, Revision 1.0, August 17, 1993
+  Am79C940 (MACE) Data Sheet, 1994
+  Am79C90 (C-LANCE) Data Sheet, 1994
+  Linux PCMCIA Programmer's Guide v1.17
+  /usr/src/linux/net/inet/dev.c, Linux kernel 1.2.8
+
+  Eric Mears, New Media Corporation
+  Tom Pollard, New Media Corporation
+  Dean Siasoyco, New Media Corporation
+  Ken Lesniak, Silicon Graphics, Inc. <lesniak@boston.sgi.com>
+  Donald Becker <becker@cesdis1.gsfc.nasa.gov>
+  David Hinds <dhinds@hyper.stanford.edu>
+
+  The Linux client driver is based on the 3c589_cs.c client driver by
+  David Hinds.
+
+  The Linux network driver outline is based on the 3c589_cs.c driver,
+  the 8390.c driver, and the example skeleton.c kernel code, which are
+  by Donald Becker.
+
+  The Am2150 network driver hardware interface code is based on the
+  OS/9000 driver for the New Media Ethernet LAN by Eric Mears.
+
+  Special thanks for testing and help in debugging this driver goes
+  to Ken Lesniak.
+
+-------------------------------------------------------------------------------
+Driver Notes and Issues
+-------------------------------------------------------------------------------
+
+1. Developed on a Dell 320SLi
+   PCMCIA Card Services 2.6.2
+   Linux dell 1.2.10 #1 Thu Jun 29 20:23:41 PDT 1995 i386
+
+2. rc.pcmcia may require loading pcmcia_core with io_speed=300:
+   'insmod pcmcia_core.o io_speed=300'.
+   This will avoid problems with fast systems which causes rx_framecnt
+   to return random values.
+
+3. If hot extraction does not work for you, use 'ifconfig eth0 down'
+   before extraction.
+
+4. There is a bad slow-down problem in this driver.
+
+5. Future: Multicast processing.  In the meantime, do _not_ compile your
+   kernel with multicast ip enabled.
+
+-------------------------------------------------------------------------------
+History
+-------------------------------------------------------------------------------
+Log: nmclan_cs.c,v
+ * Revision 0.16  1995/07/01  06:42:17  rpao
+ * Bug fix: nmclan_reset() called CardServices incorrectly.
+ *
+ * Revision 0.15  1995/05/24  08:09:47  rpao
+ * Re-implement MULTI_TX dev->tbusy handling.
+ *
+ * Revision 0.14  1995/05/23  03:19:30  rpao
+ * Added, in nmclan_config(), "tuple.Attributes = 0;".
+ * Modified MACE ID check to ignore chip revision level.
+ * Avoid tx_free_frames race condition between _start_xmit and _interrupt.
+ *
+ * Revision 0.13  1995/05/18  05:56:34  rpao
+ * Statistics changes.
+ * Bug fix: nmclan_reset did not enable TX and RX: call restore_multicast_list.
+ * Bug fix: mace_interrupt checks ~MACE_IMR_DEFAULT.  Fixes driver lockup.
+ *
+ * Revision 0.12  1995/05/14  00:12:23  rpao
+ * Statistics overhaul.
+ *
+
+95/05/13 rpao	V0.10a
+		Bug fix: MACE statistics counters used wrong I/O ports.
+		Bug fix: mace_interrupt() needed to allow statistics to be
+		processed without RX or TX interrupts pending.
+95/05/11 rpao	V0.10
+		Multiple transmit request processing.
+		Modified statistics to use MACE counters where possible.
+95/05/10 rpao	V0.09 Bug fix: Must use IO_DATA_PATH_WIDTH_AUTO.
+		*Released
+95/05/10 rpao	V0.08
+		Bug fix: Make all non-exported functions private by using
+		static keyword.
+		Bug fix: Test IntrCnt _before_ reading MACE_IR.
+95/05/10 rpao	V0.07 Statistics.
+95/05/09 rpao	V0.06 Fix rx_framecnt problem by addition of PCIC wait states.
+
+---------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------------
+Conditional Compilation Options
+---------------------------------------------------------------------------- */
+
+#define MULTI_TX			0
+#define TIMEOUT_TX			1
+#define RESET_ON_TIMEOUT		1
+#define TX_INTERRUPTABLE		1
+#define RESET_XILINX			0
+
+/* ----------------------------------------------------------------------------
+Include Files
+---------------------------------------------------------------------------- */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+/* ----------------------------------------------------------------------------
+Defines
+---------------------------------------------------------------------------- */
+
+#define ETHER_ADDR_LEN			ETH_ALEN
+					/* 6 bytes in an Ethernet Address */
+#define MACE_LADRF_LEN			8
+					/* 8 bytes in Logical Address Filter */
+
+/* Transmitter Busy Bit Index Defines */
+#define TBUSY_UNSPECIFIED		0
+#define TBUSY_PARTIAL_TX_FRAME		0
+#define TBUSY_NO_FREE_TX_FRAMES		1
+
+/* Loop Control Defines */
+#define MACE_MAX_IR_ITERATIONS		10
+#define MACE_MAX_RX_ITERATIONS		12
+	/*
+	TBD: Dean brought this up, and I assumed the hardware would
+	handle it:
+
+	If MACE_MAX_RX_ITERATIONS is > 1, rx_framecnt may still be
+	non-zero when the isr exits.  We may not get another interrupt
+	to process the remaining packets for some time.
+	*/
+
+/*
+The Am2150 has a Xilinx XC3042 field programmable gate array (FPGA)
+which manages the interface between the MACE and the PCMCIA bus.  It
+also includes buffer management for the 32K x 8 SRAM to control up to
+four transmit and 12 receive frames at a time.
+*/
+#define AM2150_MAX_TX_FRAMES		4
+#define AM2150_MAX_RX_FRAMES		12
+
+/* Am2150 Ethernet Card I/O Mapping */
+#define AM2150_RCV			0x00
+#define AM2150_XMT			0x04
+#define AM2150_XMT_SKIP			0x09
+#define AM2150_RCV_NEXT			0x0A
+#define AM2150_RCV_FRAME_COUNT		0x0B
+#define AM2150_MACE_BANK		0x0C
+#define AM2150_MACE_BASE		0x10
+
+/* MACE Registers */
+#define MACE_RCVFIFO			0
+#define MACE_XMTFIFO			1
+#define MACE_XMTFC			2
+#define MACE_XMTFS			3
+#define MACE_XMTRC			4
+#define MACE_RCVFC			5
+#define MACE_RCVFS			6
+#define MACE_FIFOFC			7
+#define MACE_IR				8
+#define MACE_IMR			9
+#define MACE_PR				10
+#define MACE_BIUCC			11
+#define MACE_FIFOCC			12
+#define MACE_MACCC			13
+#define MACE_PLSCC			14
+#define MACE_PHYCC			15
+#define MACE_CHIPIDL			16
+#define MACE_CHIPIDH			17
+#define MACE_IAC			18
+/* Reserved */
+#define MACE_LADRF			20
+#define MACE_PADR			21
+/* Reserved */
+/* Reserved */
+#define MACE_MPC			24
+/* Reserved */
+#define MACE_RNTPC			26
+#define MACE_RCVCC			27
+/* Reserved */
+#define MACE_UTR			29
+#define MACE_RTR1			30
+#define MACE_RTR2			31
+
+/* MACE Bit Masks */
+#define MACE_XMTRC_EXDEF		0x80
+#define MACE_XMTRC_XMTRC		0x0F
+
+#define MACE_XMTFS_XMTSV		0x80
+#define MACE_XMTFS_UFLO			0x40
+#define MACE_XMTFS_LCOL			0x20
+#define MACE_XMTFS_MORE			0x10
+#define MACE_XMTFS_ONE			0x08
+#define MACE_XMTFS_DEFER		0x04
+#define MACE_XMTFS_LCAR			0x02
+#define MACE_XMTFS_RTRY			0x01
+
+#define MACE_RCVFS_RCVSTS		0xF000
+#define MACE_RCVFS_OFLO			0x8000
+#define MACE_RCVFS_CLSN			0x4000
+#define MACE_RCVFS_FRAM			0x2000
+#define MACE_RCVFS_FCS			0x1000
+
+#define MACE_FIFOFC_RCVFC		0xF0
+#define MACE_FIFOFC_XMTFC		0x0F
+
+#define MACE_IR_JAB			0x80
+#define MACE_IR_BABL			0x40
+#define MACE_IR_CERR			0x20
+#define MACE_IR_RCVCCO			0x10
+#define MACE_IR_RNTPCO			0x08
+#define MACE_IR_MPCO			0x04
+#define MACE_IR_RCVINT			0x02
+#define MACE_IR_XMTINT			0x01
+
+#define MACE_MACCC_PROM			0x80
+#define MACE_MACCC_DXMT2PD		0x40
+#define MACE_MACCC_EMBA			0x20
+#define MACE_MACCC_RESERVED		0x10
+#define MACE_MACCC_DRCVPA		0x08
+#define MACE_MACCC_DRCVBC		0x04
+#define MACE_MACCC_ENXMT		0x02
+#define MACE_MACCC_ENRCV		0x01
+
+#define MACE_PHYCC_LNKFL		0x80
+#define MACE_PHYCC_DLNKTST		0x40
+#define MACE_PHYCC_REVPOL		0x20
+#define MACE_PHYCC_DAPC			0x10
+#define MACE_PHYCC_LRT			0x08
+#define MACE_PHYCC_ASEL			0x04
+#define MACE_PHYCC_RWAKE		0x02
+#define MACE_PHYCC_AWAKE		0x01
+
+#define MACE_IAC_ADDRCHG		0x80
+#define MACE_IAC_PHYADDR		0x04
+#define MACE_IAC_LOGADDR		0x02
+
+#define MACE_UTR_RTRE			0x80
+#define MACE_UTR_RTRD			0x40
+#define MACE_UTR_RPA			0x20
+#define MACE_UTR_FCOLL			0x10
+#define MACE_UTR_RCVFCSE		0x08
+#define MACE_UTR_LOOP_INCL_MENDEC	0x06
+#define MACE_UTR_LOOP_NO_MENDEC		0x04
+#define MACE_UTR_LOOP_EXTERNAL		0x02
+#define MACE_UTR_LOOP_NONE		0x00
+#define MACE_UTR_RESERVED		0x01
+
+/* Switch MACE register bank (only 0 and 1 are valid) */
+#define MACEBANK(win_num) outb((win_num), ioaddr + AM2150_MACE_BANK)
+
+#define MACE_IMR_DEFAULT \
+  (0xFF - \
+    ( \
+      MACE_IR_CERR | \
+      MACE_IR_RCVCCO | \
+      MACE_IR_RNTPCO | \
+      MACE_IR_MPCO | \
+      MACE_IR_RCVINT | \
+      MACE_IR_XMTINT \
+    ) \
+  )
+#undef MACE_IMR_DEFAULT
+#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
+
+/* ----------------------------------------------------------------------------
+Type Definitions
+---------------------------------------------------------------------------- */
+
+typedef struct _mace_statistics {
+  /* MACE_XMTFS */
+  int xmtsv;
+  int uflo;
+  int lcol;
+  int more;
+  int one;
+  int defer;
+  int lcar;
+  int rtry;
+
+  /* MACE_XMTRC */
+  int exdef;
+  int xmtrc;
+
+  /* RFS1--Receive Status (RCVSTS) */
+  int oflo;
+  int clsn;
+  int fram;
+  int fcs;
+
+  /* RFS2--Runt Packet Count (RNTPC) */
+  int rfs_rntpc;
+
+  /* RFS3--Receive Collision Count (RCVCC) */
+  int rfs_rcvcc;
+
+  /* MACE_IR */
+  int jab;
+  int babl;
+  int cerr;
+  int rcvcco;
+  int rntpco;
+  int mpco;
+
+  /* MACE_MPC */
+  int mpc;
+
+  /* MACE_RNTPC */
+  int rntpc;
+
+  /* MACE_RCVCC */
+  int rcvcc;
+} mace_statistics;
+
+typedef struct _mace_private {
+  dev_node_t node;
+  struct net_device_stats linux_stats; /* Linux statistics counters */
+  mace_statistics mace_stats; /* MACE chip statistics counters */
+
+  /* restore_multicast_list() state variables */
+  int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */
+  int multicast_num_addrs;
+
+  char tx_free_frames; /* Number of free transmit frame buffers */
+  char tx_irq_disabled; /* MACE TX interrupt disabled */
+} mace_private;
+
+/* ----------------------------------------------------------------------------
+Private Global Variables
+---------------------------------------------------------------------------- */
+
+#ifdef PCMCIA_DEBUG
+static char rcsid[] =
+"nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao";
+static char *version =
+"nmclan_cs 0.16 (Roger C. Pao)";
+#endif
+
+static dev_info_t dev_info="nmclan_cs";
+static dev_link_t *dev_list=NULL;
+
+static char *if_names[]={
+  "Auto",
+  "10baseT",
+  "BNC",
+};
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/* ----------------------------------------------------------------------------
+Parameters
+	These are the parameters that can be set during loading with
+	'insmod'.
+---------------------------------------------------------------------------- */
+
+static int if_port=0; /* default=auto */
+  /*
+   * 0=auto
+   * 1=10base-T (twisted pair)
+   * 2=10base-2 (BNC)
+   */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(if_port, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/* ----------------------------------------------------------------------------
+Function Prototypes
+---------------------------------------------------------------------------- */
+
+static void nmclan_config(dev_link_t *link);
+static void nmclan_release(u_long arg);
+static int nmclan_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static void nmclan_reset(struct net_device *dev);
+static int mace_config(struct net_device *dev, struct ifmap *map);
+static int mace_open(struct net_device *dev);
+static int mace_close(struct net_device *dev);
+static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats *mace_get_stats(struct net_device *dev);
+static int mace_rx(struct net_device *dev, unsigned char RxCnt);
+static void restore_multicast_list(struct net_device *dev);
+
+static void set_multicast_list(struct net_device *dev);
+
+static dev_link_t *nmclan_attach(void);
+static void nmclan_detach(dev_link_t *);
+
+/* ----------------------------------------------------------------------------
+flush_stale_links
+	Clean up stale device structures
+---------------------------------------------------------------------------- */
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    nmclan_detach(link);
+    }
+}
+
+/* ----------------------------------------------------------------------------
+cs_error
+	Report a Card Services related error.
+---------------------------------------------------------------------------- */
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/* ----------------------------------------------------------------------------
+nmclan_init
+	We never need to do anything when a nmclan device is "initialized"
+	by the net software, because we only register already-found cards.
+---------------------------------------------------------------------------- */
+static int nmclan_init(struct net_device *dev)
+{
+  return 0;
+} /* nmclan_init */
+
+/* ----------------------------------------------------------------------------
+nmclan_attach
+	Creates an "instance" of the driver, allocating local data
+	structures for one device.  The device is registered with Card
+	Services.
+---------------------------------------------------------------------------- */
+static dev_link_t *nmclan_attach(void)
+{
+  client_reg_t client_reg;
+  dev_link_t *link;
+  struct net_device *dev;
+  int i, ret;
+
+  DEBUG(0, "nmclan_attach()\n");
+  DEBUG(1, "%s\n", rcsid);
+  flush_stale_links();
+
+  /* Create new ethernet device */
+  link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  memset(link, 0, sizeof(struct dev_link_t));
+  link->release.function = &nmclan_release;
+  link->release.data = (u_long)link;
+  link->io.NumPorts1 = 32;
+  link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+  link->io.IOAddrLines = 5;
+  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+  if (irq_list[0] == -1)
+    link->irq.IRQInfo2 = irq_mask;
+  else
+    for (i = 0; i < 4; i++)
+      link->irq.IRQInfo2 |= 1 << irq_list[i];
+  link->irq.Handler = &mace_interrupt;
+  link->conf.Attributes = CONF_ENABLE_IRQ;
+  link->conf.Vcc = 50;
+  link->conf.IntType = INT_MEMORY_AND_IO;
+  link->conf.ConfigIndex = 1;
+  link->conf.Present = PRESENT_OPTION;
+
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  memset(dev, 0, sizeof(struct net_device));
+
+  /* Allocate private data area for this device. */
+  dev->priv = kmalloc(sizeof(mace_private), GFP_KERNEL);
+  memset(dev->priv, 0, sizeof(mace_private));
+  ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
+  dev->hard_start_xmit = &mace_start_xmit;
+  dev->set_config = &mace_config;
+  dev->get_stats = &mace_get_stats;
+  dev->set_multicast_list = &set_multicast_list;
+  ether_setup(dev);
+  dev->name = ((mace_private *)dev->priv)->node.dev_name;
+  dev->init = &nmclan_init;
+  dev->open = &mace_open;
+  dev->stop = &mace_close;
+  dev->tbusy = 0xFF;
+  link->priv = link->irq.Instance = dev;
+
+  /* Register with Card Services */
+  link->next = dev_list;
+  dev_list = link;
+  client_reg.dev_info = &dev_info;
+  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+  client_reg.EventMask =
+    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+  client_reg.event_handler = &nmclan_event;
+  client_reg.Version = 0x0210;
+  client_reg.event_callback_args.client_data = link;
+  ret = CardServices(RegisterClient, &link->handle, &client_reg);
+  if (ret != 0) {
+    cs_error(link->handle, RegisterClient, ret);
+    nmclan_detach(link);
+    return NULL;
+  }
+
+  return link;
+} /* nmclan_attach */
+
+/* ----------------------------------------------------------------------------
+nmclan_detach
+	This deletes a driver "instance".  The device is de-registered
+	with Card Services.  If it has been released, all local data
+	structures are freed.  Otherwise, the structures will be freed
+	when the device is released.
+---------------------------------------------------------------------------- */
+static void nmclan_detach(dev_link_t *link)
+{
+  dev_link_t **linkp;
+
+  DEBUG(0, "nmclan_detach(0x%p)\n", link);
+
+  /* Locate device structure */
+  for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+    if (*linkp == link) break;
+  if (*linkp == NULL)
+    return;
+
+  if (link->state & DEV_CONFIG) {
+    nmclan_release((u_long)link);
+    if (link->state & DEV_STALE_CONFIG) {
+      link->state |= DEV_STALE_LINK;
+      return;
+    }
+  }
+
+  if (link->handle)
+    CardServices(DeregisterClient, link->handle);
+
+  /* Unlink device structure, free bits */
+  *linkp = link->next;
+  if (link->priv) {
+    struct net_device *dev = link->priv;
+    if (link->dev != NULL)
+      unregister_netdev(dev);
+    if (dev->priv)
+      kfree(dev->priv);
+    kfree(link->priv);
+  }
+  kfree(link);
+
+} /* nmclan_detach */
+
+/* ----------------------------------------------------------------------------
+mace_read
+	Reads a MACE register.  This is bank independent; however, the
+	caller must ensure that this call is not interruptable.  We are
+	assuming that during normal operation, the MACE is always in
+	bank 0.
+---------------------------------------------------------------------------- */
+static int mace_read(ioaddr_t ioaddr, int reg)
+{
+  int data = 0xFF;
+  unsigned long flags;
+
+  switch (reg >> 4) {
+    case 0: /* register 0-15 */
+      data = inb(ioaddr + AM2150_MACE_BASE + reg);
+      break;
+    case 1: /* register 16-31 */
+      save_flags(flags);
+      cli();
+      MACEBANK(1);
+      data = inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F));
+      MACEBANK(0);
+      restore_flags(flags);
+      break;
+  }
+  return (data & 0xFF);
+} /* mace_read */
+
+/* ----------------------------------------------------------------------------
+mace_write
+	Writes to a MACE register.  This is bank independent; however,
+	the caller must ensure that this call is not interruptable.  We
+	are assuming that during normal operation, the MACE is always in
+	bank 0.
+---------------------------------------------------------------------------- */
+static void mace_write(ioaddr_t ioaddr, int reg, int data)
+{
+  unsigned long flags;
+
+  switch (reg >> 4) {
+    case 0: /* register 0-15 */
+      outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg);
+      break;
+    case 1: /* register 16-31 */
+      save_flags(flags);
+      cli();
+      MACEBANK(1);
+      outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F));
+      MACEBANK(0);
+      restore_flags(flags);
+      break;
+  }
+} /* mace_write */
+
+/* ----------------------------------------------------------------------------
+mace_init
+	Resets the MACE chip.
+---------------------------------------------------------------------------- */
+static void mace_init(ioaddr_t ioaddr, char *enet_addr)
+{
+  int i;
+
+  /* MACE Software reset */
+  mace_write(ioaddr, MACE_BIUCC, 1);
+  while (mace_read(ioaddr, MACE_BIUCC) & 0x01) {
+    /* Wait for reset bit to be cleared automatically after <= 200ns */;
+  }
+  mace_write(ioaddr, MACE_BIUCC, 0);
+
+  /* The Am2150 requires that the MACE FIFOs operate in burst mode. */
+  mace_write(ioaddr, MACE_FIFOCC, 0x0F);
+
+  mace_write(ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */
+  mace_write(ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until _open */
+
+  /*
+   * Bit 2-1 PORTSEL[1-0] Port Select.
+   * 00 AUI/10Base-2
+   * 01 10Base-T
+   * 10 DAI Port (reserved in Am2150)
+   * 11 GPSI
+   * For this card, only the first two are valid.
+   * So, PLSCC should be set to
+   * 0x00 for 10Base-2
+   * 0x02 for 10Base-T
+   * Or just set ASEL in PHYCC below!
+   */
+  switch (if_port) {
+    case 1:
+      mace_write(ioaddr, MACE_PLSCC, 0x02);
+      break;
+    case 2:
+      mace_write(ioaddr, MACE_PLSCC, 0x00);
+      break;
+    default:
+      mace_write(ioaddr, MACE_PHYCC, /* ASEL */ 4);
+      /* ASEL Auto Select.  When set, the PORTSEL[1-0] bits are overridden,
+	 and the MACE device will automatically select the operating media
+	 interface port. */
+      break;
+  }
+
+  mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR);
+  /* Poll ADDRCHG bit */
+  while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
+    ;
+  /* Set PADR register */
+  for (i = 0; i < ETHER_ADDR_LEN; i++)
+    mace_write(ioaddr, MACE_PADR, enet_addr[i]);
+
+  /* MAC Configuration Control Register should be written last */
+  /* Let set_multicast_list set this. */
+  /* mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */
+  mace_write(ioaddr, MACE_MACCC, 0x00);
+} /* mace_init */
+
+/* ----------------------------------------------------------------------------
+nmclan_config
+	This routine is scheduled to run after a CARD_INSERTION event
+	is received, to configure the PCMCIA socket, and to make the
+	ethernet device available to the system.
+---------------------------------------------------------------------------- */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void nmclan_config(dev_link_t *link)
+{
+  client_handle_t handle;
+  struct net_device *dev;
+  tuple_t tuple;
+  cisparse_t parse;
+  u_char buf[64];
+  int i, last_ret, last_fn;
+  ioaddr_t ioaddr;
+  u_short *phys_addr;
+
+  handle = link->handle;
+  dev = link->priv;
+  phys_addr = (u_short *)dev->dev_addr;
+
+  DEBUG(0, "nmclan_config(0x%p)\n", link);
+
+  tuple.Attributes = 0;
+  tuple.TupleData = buf;
+  tuple.TupleDataMax = 64;
+  tuple.TupleOffset = 0;
+  tuple.DesiredTuple = CISTPL_CONFIG;
+  CS_CHECK(GetFirstTuple, handle, &tuple);
+  CS_CHECK(GetTupleData, handle, &tuple);
+  CS_CHECK(ParseTuple, handle, &tuple, &parse);
+  link->conf.ConfigBase = parse.config.base;
+
+  /* Configure card */
+  link->state |= DEV_CONFIG;
+
+  CS_CHECK(RequestIO, handle, &link->io);
+  CS_CHECK(RequestIRQ, handle, &link->irq);
+  CS_CHECK(RequestConfiguration, handle, &link->conf);
+  dev->irq = link->irq.AssignedIRQ;
+  dev->base_addr = link->io.BasePort1;
+  dev->tbusy = 0;
+  i = register_netdev(dev);
+  if (i != 0) {
+    printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
+    goto failed;
+  }
+  
+  ioaddr = dev->base_addr;
+
+  /* Read the ethernet address from the CIS. */
+  tuple.DesiredTuple = 0x80 /* CISTPL_CFTABLE_ENTRY_MISC */;
+  tuple.TupleData = buf;
+  tuple.TupleDataMax = 64;
+  tuple.TupleOffset = 0;
+  CS_CHECK(GetFirstTuple, handle, &tuple);
+  CS_CHECK(GetTupleData, handle, &tuple);
+  memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN);
+
+  /* Verify configuration by reading the MACE ID. */
+  {
+    char sig[2];
+
+    sig[0] = mace_read(ioaddr, MACE_CHIPIDL);
+    sig[1] = mace_read(ioaddr, MACE_CHIPIDH);
+    if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) {
+      DEBUG(0, "nmclan_cs configured: mace id=%x %x\n",
+	    sig[0], sig[1]);
+    } else {
+      printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should"
+	     " be 0x40 0x?9\n", sig[0], sig[1]);
+      link->state &= ~DEV_CONFIG_PENDING;
+      return;
+    }
+  }
+
+  mace_init(ioaddr, dev->dev_addr);
+
+  /* The if_port symbol can be set when the module is loaded */
+  if (if_port <= 2)
+    dev->if_port = if_port;
+  else
+    printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
+
+  link->dev = &((mace_private *)dev->priv)->node;
+  link->state &= ~DEV_CONFIG_PENDING;
+  
+  printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
+	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
+  for (i = 0; i < 6; i++)
+      printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+  return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    nmclan_release((u_long)link);
+    return;
+    
+} /* nmclan_config */
+
+/* ----------------------------------------------------------------------------
+nmclan_release
+	After a card is removed, nmclan_release() will unregister the
+	net device, and release the PCMCIA configuration.  If the device
+	is still open, this will be postponed until it is closed.
+---------------------------------------------------------------------------- */
+static void nmclan_release(u_long arg)
+{
+  dev_link_t *link = (dev_link_t *)arg;
+
+  DEBUG(0, "nmclan_release(0x%p)\n", link);
+
+  if (link->open) {
+    DEBUG(1, "nmclan_cs: release postponed, '%s' "
+	  "still open\n", link->dev->dev_name);
+    link->state |= DEV_STALE_CONFIG;
+    return;
+  }
+
+  CardServices(ReleaseConfiguration, link->handle);
+  CardServices(ReleaseIO, link->handle, &link->io);
+  CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* nmclan_release */
+
+/* ----------------------------------------------------------------------------
+nmclan_event
+	The card status event handler.  Mostly, this schedules other
+	stuff to run after an event is received.  A CARD_REMOVAL event
+	also sets some flags to discourage the net drivers from trying
+	to talk to the card any more.
+---------------------------------------------------------------------------- */
+static int nmclan_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+  dev_link_t *link = args->client_data;
+  struct net_device *dev = link->priv;
+
+  DEBUG(1, "nmclan_event(0x%06x)\n", event);
+    
+  switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+      link->state &= ~DEV_PRESENT;
+      if (link->state & DEV_CONFIG) {
+	dev->tbusy = 0xFF; dev->start = 0;
+	link->release.expires = jiffies + HZ/20;
+	add_timer(&link->release);
+      }
+      break;
+    case CS_EVENT_CARD_INSERTION:
+      link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+      nmclan_config(link);
+      break;
+    case CS_EVENT_PM_SUSPEND:
+      link->state |= DEV_SUSPEND;
+      /* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+      if (link->state & DEV_CONFIG) {
+	if (link->open) {
+	  dev->tbusy = 0xFF; dev->start = 0;
+	}
+	CardServices(ReleaseConfiguration, link->handle);
+      }
+      break;
+    case CS_EVENT_PM_RESUME:
+      link->state &= ~DEV_SUSPEND;
+      /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+      if (link->state & DEV_CONFIG) {
+	CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (link->open) {
+	  dev->tbusy = 0;
+	  dev->start = 1;
+	  nmclan_reset(dev);
+	}
+      }
+      break;
+    case CS_EVENT_RESET_REQUEST:
+      return 1;
+      break;
+  }
+  return 0;
+} /* nmclan_event */
+
+/* ------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------------
+nmclan_reset
+	Reset and restore all of the Xilinx and MACE registers.
+---------------------------------------------------------------------------- */
+static void nmclan_reset(struct net_device *dev)
+{
+
+#if RESET_XILINX
+  dev_link_t *link;
+  conf_reg_t reg;
+  u_long OrigCorValue; 
+
+  /* Find our client handle. */
+  for (link = dev_list; link; link = link->next)
+    if (link->priv == dev) break;
+  if (link == NULL) {
+    printk(KERN_NOTICE "nmclan_cs: bad device pointer!\n");
+    return;
+  }
+
+  /* Save original COR value */
+  reg.Function = 0;
+  reg.Action = CS_READ;
+  reg.Offset = CISREG_COR;
+  reg.Value = 0;
+  CardServices(AccessConfigurationRegister, link->handle, &reg);
+  OrigCorValue = reg.Value;
+
+  /* Reset Xilinx */
+  reg.Action = CS_WRITE;
+  reg.Offset = CISREG_COR;
+  DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n",
+	OrigCorValue);
+  reg.Value = COR_SOFT_RESET;
+  CardServices(AccessConfigurationRegister, link->handle, &reg);
+  /* Need to wait for 20 ms for PCMCIA to finish reset. */
+
+  /* Restore original COR configuration index */
+  reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK);
+  CardServices(AccessConfigurationRegister, link->handle, &reg);
+  /* Xilinx is now completely reset along with the MACE chip. */
+  ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
+#endif /* #if RESET_XILINX */
+
+  /* Xilinx is now completely reset along with the MACE chip. */
+  ((mace_private *)dev->priv)->tx_free_frames=AM2150_MAX_TX_FRAMES;
+  
+  /* Reinitialize the MACE chip for operation. */
+  mace_init(dev->base_addr, dev->dev_addr);
+  mace_write(dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT);
+
+  /* Restore the multicast list and enable TX and RX. */
+  restore_multicast_list(dev);
+} /* nmclan_reset */
+
+/* ----------------------------------------------------------------------------
+mace_config
+	[Someone tell me what this is supposed to do?  Is if_port a defined
+	standard?  If so, there should be defines to indicate 1=10Base-T,
+	2=10Base-2, etc. including limited automatic detection.]
+---------------------------------------------------------------------------- */
+static int mace_config(struct net_device *dev, struct ifmap *map)
+{
+  if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+    if (map->port <= 2) {
+      dev->if_port = map->port;
+      printk(KERN_INFO "%s: switched to %s port\n", dev->name,
+	     if_names[dev->if_port]);
+    }
+  else
+    return -EINVAL;
+  }
+  return 0;
+} /* mace_config */
+
+/* ----------------------------------------------------------------------------
+mace_open
+	Open device driver.
+---------------------------------------------------------------------------- */
+static int mace_open(struct net_device *dev)
+{
+  ioaddr_t ioaddr = dev->base_addr;
+  dev_link_t *link;
+
+  for (link = dev_list; link; link = link->next)
+    if (link->priv == dev) break;
+  if (!DEV_OK(link))
+    return -ENODEV;
+
+  link->open++;
+  MOD_INC_USE_COUNT;
+
+  MACEBANK(0);
+
+  dev->interrupt = 0;
+  dev->tbusy = 0;
+  dev->start = 1;
+
+  nmclan_reset(dev);
+
+  return 0; /* Always succeed */
+} /* mace_open */
+
+/* ----------------------------------------------------------------------------
+mace_close
+	Closes device driver.
+---------------------------------------------------------------------------- */
+static int mace_close(struct net_device *dev)
+{
+  ioaddr_t ioaddr = dev->base_addr;
+  dev_link_t *link;
+
+  for (link = dev_list; link; link = link->next)
+    if (link->priv == dev) break;
+  if (link == NULL)
+    return -ENODEV;
+
+  DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+  
+  /* Mask off all interrupts from the MACE chip. */
+  outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
+
+  link->open--;
+  dev->start = 0;
+  if (link->state & DEV_STALE_CONFIG) {
+    link->release.expires = jiffies + HZ/20;
+    link->state |= DEV_RELEASE_PENDING;
+    add_timer(&link->release);
+  }
+
+  MOD_DEC_USE_COUNT;
+
+  return 0;
+} /* mace_close */
+
+/* ----------------------------------------------------------------------------
+mace_start_xmit
+	This routine begins the packet transmit function.  When completed,
+	it will generate a transmit interrupt.
+
+	According to /usr/src/linux/net/inet/dev.c, if _start_xmit
+	returns 0, the "packet is now solely the responsibility of the
+	driver."  If _start_xmit returns non-zero, the "transmission
+	failed, put skb back into a list."
+---------------------------------------------------------------------------- */
+static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  ioaddr_t ioaddr = dev->base_addr;
+  dev_link_t *link;
+
+#if TIMEOUT_TX
+  /* Transmitter timeout. */
+  if (dev->tbusy) {
+    int tickssofar = jiffies - dev->trans_start;
+
+    if (tickssofar < (HZ/5))
+      return 1;
+    printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+#if RESET_ON_TIMEOUT
+    printk("resetting card\n");
+    for (link = dev_list; link; link = link->next)
+      if (link->priv == dev) break;
+    if (link)
+      CardServices(ResetCard, link->handle);
+#else /* #if RESET_ON_TIMEOUT */
+    printk("NOT resetting card\n");
+#endif /* #if RESET_ON_TIMEOUT */
+    dev->trans_start = jiffies;
+    return 1;
+  }
+#else /* #if TIMEOUT_TX */
+  if (dev->tbusy)
+    return 1;
+#endif /* #if TIMEOUT_TX */
+
+  DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n",
+	dev->name, (long)skb->len);
+  
+  /* Avoid timer-based retransmission conflicts. */
+  if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) {
+    printk(KERN_NOTICE "%s: transmitter access conflict.\n",
+	   dev->name);
+    return 1;
+  }
+
+#if (!TX_INTERRUPTABLE)
+  /* Disable MACE TX interrupts. */
+  outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT,
+    ioaddr + AM2150_MACE_BASE + MACE_IMR);
+  lp->tx_irq_disabled=1;
+#endif /* #if (!TX_INTERRUPTABLE) */
+
+  {
+    /* This block must not be interrupted by another transmit request!
+       dev->tbusy will take care of timer-based retransmissions from
+       the upper layers.  The interrupt handler is guaranteed never to
+       service a transmit interrupt while we are in here.
+    */
+    set_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy);
+
+    lp->linux_stats.tx_bytes += skb->len;
+    lp->tx_free_frames--;
+    set_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
+
+    /* WARNING: Write the _exact_ number of bytes written in the header! */
+    /* Put out the word header [must be an outw()] . . . */
+    outw(skb->len, ioaddr + AM2150_XMT);
+    /* . . . and the packet [may be any combination of outw() and outb()] */
+    outsw(ioaddr + AM2150_XMT, skb->data, skb->len >> 1);
+    if (skb->len & 1) {
+      /* Odd byte transfer */
+      outb(skb->data[skb->len-1], ioaddr + AM2150_XMT);
+    }
+
+    dev->trans_start = jiffies;
+
+    if (lp->tx_free_frames > 0) {
+#if MULTI_TX
+      clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
+#endif /* #if MULTI_TX */
+    }
+
+    clear_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy);
+  }
+
+#if (!TX_INTERRUPTABLE)
+  /* Re-enable MACE TX interrupts. */
+  lp->tx_irq_disabled=0;
+  outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR);
+#endif /* #if (!TX_INTERRUPTABLE) */
+
+  dev_kfree_skb(skb);
+    
+  return 0;
+} /* mace_start_xmit */
+
+/* ----------------------------------------------------------------------------
+mace_interrupt
+	The interrupt handler.
+---------------------------------------------------------------------------- */
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct net_device *dev = (struct net_device *)dev_id;
+  mace_private *lp = (mace_private *)dev->priv;
+  ioaddr_t ioaddr = dev->base_addr;
+  int status;
+  int IntrCnt = MACE_MAX_IR_ITERATIONS;
+
+  if (dev == NULL) {
+    DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n",
+	  irq);
+    return;
+  }
+
+  if (dev->interrupt || lp->tx_irq_disabled) {
+    sti();
+    printk(
+      (lp->tx_irq_disabled?
+       KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
+       "[isr=%02X, imr=%02X]\n": 
+       KERN_NOTICE "%s: Re-entering the interrupt handler "
+       "[isr=%02X, imr=%02X]\n"),
+      dev->name,
+      inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
+      inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)
+    );
+    /* WARNING: MACE_IR has been read! */
+    return;
+  }
+  dev->interrupt = 1;
+  sti();
+
+  if (dev->start == 0) {
+    DEBUG(2, "%s: interrupt from dead card\n", dev->name);
+    goto exception;
+  }
+
+  do {
+    /* WARNING: MACE_IR is a READ/CLEAR port! */
+    status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
+ 
+    DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
+
+    if (status & MACE_IR_RCVINT) {
+      mace_rx(dev, MACE_MAX_RX_ITERATIONS);
+    }
+
+    if (status & MACE_IR_XMTINT) {
+      unsigned char fifofc;
+      unsigned char xmtrc;
+      unsigned char xmtfs;
+
+      fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC);
+      if ((fifofc & MACE_FIFOFC_XMTFC)==0) {
+	lp->linux_stats.tx_errors++;
+	outb(0xFF, ioaddr + AM2150_XMT_SKIP);
+      }
+
+      /* Transmit Retry Count (XMTRC, reg 4) */
+      xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC);
+      if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++;
+      lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC);
+
+      if (
+        (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) &
+        MACE_XMTFS_XMTSV /* Transmit Status Valid */
+      ) {
+	lp->mace_stats.xmtsv++;
+
+	if (xmtfs & ~MACE_XMTFS_XMTSV) {
+	  if (xmtfs & MACE_XMTFS_UFLO) {
+	    /* Underflow.  Indicates that the Transmit FIFO emptied before
+	       the end of frame was reached. */
+	    lp->mace_stats.uflo++;
+	  }
+	  if (xmtfs & MACE_XMTFS_LCOL) {
+	    /* Late Collision */
+	    lp->mace_stats.lcol++;
+	  }
+	  if (xmtfs & MACE_XMTFS_MORE) {
+	    /* MORE than one retry was needed */
+	    lp->mace_stats.more++;
+	  }
+	  if (xmtfs & MACE_XMTFS_ONE) {
+	    /* Exactly ONE retry occurred */
+	    lp->mace_stats.one++;
+	  }
+	  if (xmtfs & MACE_XMTFS_DEFER) {
+	    /* Transmission was defered */
+	    lp->mace_stats.defer++;
+	  }
+	  if (xmtfs & MACE_XMTFS_LCAR) {
+	    /* Loss of carrier */
+	    lp->mace_stats.lcar++;
+	  }
+	  if (xmtfs & MACE_XMTFS_RTRY) {
+	    /* Retry error: transmit aborted after 16 attempts */
+	    lp->mace_stats.rtry++;
+	  }
+        } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */
+
+      } /* if (xmtfs & MACE_XMTFS_XMTSV) */
+
+      lp->linux_stats.tx_packets++;
+      lp->tx_free_frames++;
+      clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
+      mark_bh(NET_BH);
+    } /* if (status & MACE_IR_XMTINT) */
+
+    if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) {
+      if (status & MACE_IR_JAB) {
+        /* Jabber Error.  Excessive transmit duration (20-150ms). */
+        lp->mace_stats.jab++;
+      }
+      if (status & MACE_IR_BABL) {
+        /* Babble Error.  >1518 bytes transmitted. */
+        lp->mace_stats.babl++;
+      }
+      if (status & MACE_IR_CERR) {
+	/* Collision Error.  CERR indicates the absence of the
+	   Signal Quality Error Test message after a packet
+	   transmission. */
+        lp->mace_stats.cerr++;
+      }
+      if (status & MACE_IR_RCVCCO) {
+        /* Receive Collision Count Overflow; */
+        lp->mace_stats.rcvcco++;
+      }
+      if (status & MACE_IR_RNTPCO) {
+        /* Runt Packet Count Overflow */
+        lp->mace_stats.rntpco++;
+      }
+      if (status & MACE_IR_MPCO) {
+        /* Missed Packet Count Overflow */
+        lp->mace_stats.mpco++;
+      }
+    } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */
+
+  } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
+
+exception:
+  dev->interrupt = 0;
+  return;
+} /* mace_interrupt */
+
+/* ----------------------------------------------------------------------------
+mace_rx
+	Receives packets.
+---------------------------------------------------------------------------- */
+static int mace_rx(struct net_device *dev, unsigned char RxCnt)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  ioaddr_t ioaddr = dev->base_addr;
+  unsigned char rx_framecnt;
+  unsigned short rx_status;
+
+  while (
+    ((rx_framecnt = inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) &&
+    (rx_framecnt <= 12) && /* rx_framecnt==0xFF if card is extracted. */
+    (RxCnt--)
+  ) {
+    rx_status = inw(ioaddr + AM2150_RCV);
+
+    DEBUG(3, "%s: in mace_rx(), framecnt 0x%X, rx_status"
+	  " 0x%X.\n", dev->name, rx_framecnt, rx_status);
+
+    if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */
+      lp->linux_stats.rx_errors++;
+      if (rx_status & MACE_RCVFS_OFLO) {
+        lp->mace_stats.oflo++;
+      }
+      if (rx_status & MACE_RCVFS_CLSN) {
+        lp->mace_stats.clsn++;
+      }
+      if (rx_status & MACE_RCVFS_FRAM) {
+	lp->mace_stats.fram++;
+      }
+      if (rx_status & MACE_RCVFS_FCS) {
+        lp->mace_stats.fcs++;
+      }
+    } else {
+      short pkt_len = (rx_status & ~MACE_RCVFS_RCVSTS) - 4;
+        /* Auto Strip is off, always subtract 4 */
+      struct sk_buff *skb;
+
+      lp->mace_stats.rfs_rntpc += inb(ioaddr + AM2150_RCV);
+        /* runt packet count */
+      lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV);
+        /* rcv collision count */
+
+      DEBUG(3, "    receiving packet size 0x%X rx_status"
+	    " 0x%X.\n", pkt_len, rx_status);
+      
+      skb = dev_alloc_skb(pkt_len+2);
+      
+      if (skb != NULL) {
+	skb->dev = dev;
+
+	skb_reserve(skb, 2);
+	insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1);
+	if (pkt_len & 1)
+	    *(skb->tail-1) = inb(ioaddr + AM2150_RCV);
+	skb->protocol = eth_type_trans(skb, dev);
+	
+	netif_rx(skb); /* Send the packet to the upper (protocol) layers. */
+
+	lp->linux_stats.rx_packets++;
+	lp->linux_stats.rx_bytes += skb->len;
+	outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
+	continue;
+      } else {
+	DEBUG(1, "%s: couldn't allocate a sk_buff of size"
+	      " %d.\n", dev->name, pkt_len);
+	lp->linux_stats.rx_dropped++;
+      }
+    }
+    outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
+  } /* while */
+
+  return 0;
+} /* mace_rx */
+
+/* ----------------------------------------------------------------------------
+pr_linux_stats
+---------------------------------------------------------------------------- */
+static void pr_linux_stats(struct net_device_stats *pstats)
+{
+  DEBUG(2, "pr_linux_stats\n");
+  DEBUG(2, " rx_packets=%-7ld        tx_packets=%ld\n",
+	(long)pstats->rx_packets, (long)pstats->tx_packets);
+  DEBUG(2, " rx_errors=%-7ld         tx_errors=%ld\n",
+	(long)pstats->rx_errors, (long)pstats->tx_errors);
+  DEBUG(2, " rx_dropped=%-7ld        tx_dropped=%ld\n",
+	(long)pstats->rx_dropped, (long)pstats->tx_dropped);
+  DEBUG(2, " multicast=%-7ld         collisions=%ld\n",
+	(long)pstats->multicast, (long)pstats->collisions);
+
+  DEBUG(2, " rx_length_errors=%-7ld  rx_over_errors=%ld\n",
+	(long)pstats->rx_length_errors, (long)pstats->rx_over_errors);
+  DEBUG(2, " rx_crc_errors=%-7ld     rx_frame_errors=%ld\n",
+	(long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors);
+  DEBUG(2, " rx_fifo_errors=%-7ld    rx_missed_errors=%ld\n",
+	(long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors);
+
+  DEBUG(2, " tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n",
+	(long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors);
+  DEBUG(2, " tx_fifo_errors=%-7ld    tx_heartbeat_errors=%ld\n",
+	(long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors);
+  DEBUG(2, " tx_window_errors=%ld\n",
+	(long)pstats->tx_window_errors);
+} /* pr_linux_stats */
+
+/* ----------------------------------------------------------------------------
+pr_mace_stats
+---------------------------------------------------------------------------- */
+static void pr_mace_stats(mace_statistics *pstats)
+{
+  DEBUG(2, "pr_mace_stats\n");
+
+  DEBUG(2, " xmtsv=%-7d             uflo=%d\n",
+	pstats->xmtsv, pstats->uflo);
+  DEBUG(2, " lcol=%-7d              more=%d\n",
+	pstats->lcol, pstats->more);
+  DEBUG(2, " one=%-7d               defer=%d\n",
+	pstats->one, pstats->defer);
+  DEBUG(2, " lcar=%-7d              rtry=%d\n",
+	pstats->lcar, pstats->rtry);
+
+  /* MACE_XMTRC */
+  DEBUG(2, " exdef=%-7d             xmtrc=%d\n",
+	pstats->exdef, pstats->xmtrc);
+  
+  /* RFS1--Receive Status (RCVSTS) */
+  DEBUG(2, " oflo=%-7d              clsn=%d\n",
+	pstats->oflo, pstats->clsn);
+  DEBUG(2, " fram=%-7d              fcs=%d\n",
+	pstats->fram, pstats->fcs);
+
+  /* RFS2--Runt Packet Count (RNTPC) */
+  /* RFS3--Receive Collision Count (RCVCC) */
+  DEBUG(2, " rfs_rntpc=%-7d         rfs_rcvcc=%d\n",
+	pstats->rfs_rntpc, pstats->rfs_rcvcc);
+
+  /* MACE_IR */
+  DEBUG(2, " jab=%-7d               babl=%d\n",
+	pstats->jab, pstats->babl);
+  DEBUG(2, " cerr=%-7d              rcvcco=%d\n",
+	pstats->cerr, pstats->rcvcco);
+  DEBUG(2, " rntpco=%-7d            mpco=%d\n",
+	pstats->rntpco, pstats->mpco);
+
+  /* MACE_MPC */
+  DEBUG(2, " mpc=%d\n", pstats->mpc);
+
+  /* MACE_RNTPC */
+  DEBUG(2, " rntpc=%d\n", pstats->rntpc);
+
+  /* MACE_RCVCC */
+  DEBUG(2, " rcvcc=%d\n", pstats->rcvcc);
+
+} /* pr_mace_stats */
+
+/* ----------------------------------------------------------------------------
+update_stats
+	Update statistics.  We change to register window 1, so this
+	should be run single-threaded if the device is active. This is
+	expected to be a rare operation, and it's simpler for the rest
+	of the driver to assume that window 0 is always valid rather
+	than use a special window-state variable.
+
+	oflo & uflo should _never_ occur since it would mean the Xilinx
+	was not able to transfer data between the MACE FIFO and the
+	card's SRAM fast enough.  If this happens, something is
+	seriously wrong with the hardware.
+---------------------------------------------------------------------------- */
+static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+    
+  lp->mace_stats.rcvcc += mace_read(ioaddr, MACE_RCVCC);
+  lp->mace_stats.rntpc += mace_read(ioaddr, MACE_RNTPC);
+  lp->mace_stats.mpc += mace_read(ioaddr, MACE_MPC);
+  /* At this point, mace_stats is fully updated for this call.
+     We may now update the linux_stats. */
+
+  /* The MACE has no equivalent for linux_stats field which are commented
+     out. */
+
+  /* lp->linux_stats.multicast; */
+  lp->linux_stats.collisions = 
+    lp->mace_stats.rcvcco * 256 + lp->mace_stats.rcvcc;
+    /* Collision: The MACE may retry sending a packet 15 times
+       before giving up.  The retry count is in XMTRC.
+       Does each retry constitute a collision?
+       If so, why doesn't the RCVCC record these collisions? */
+
+  /* detailed rx_errors: */
+  lp->linux_stats.rx_length_errors = 
+    lp->mace_stats.rntpco * 256 + lp->mace_stats.rntpc;
+  /* lp->linux_stats.rx_over_errors */
+  lp->linux_stats.rx_crc_errors = lp->mace_stats.fcs;
+  lp->linux_stats.rx_frame_errors = lp->mace_stats.fram;
+  lp->linux_stats.rx_fifo_errors = lp->mace_stats.oflo;
+  lp->linux_stats.rx_missed_errors = 
+    lp->mace_stats.mpco * 256 + lp->mace_stats.mpc;
+
+  /* detailed tx_errors */
+  lp->linux_stats.tx_aborted_errors = lp->mace_stats.rtry;
+  lp->linux_stats.tx_carrier_errors = lp->mace_stats.lcar;
+    /* LCAR usually results from bad cabling. */
+  lp->linux_stats.tx_fifo_errors = lp->mace_stats.uflo;
+  lp->linux_stats.tx_heartbeat_errors = lp->mace_stats.cerr;
+  /* lp->linux_stats.tx_window_errors; */
+
+  return;
+} /* update_stats */
+
+/* ----------------------------------------------------------------------------
+mace_get_stats
+	Gathers ethernet statistics from the MACE chip.
+---------------------------------------------------------------------------- */
+static struct net_device_stats *mace_get_stats(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+
+  update_stats(dev->base_addr, dev);
+
+  DEBUG(1, "%s: updating the statistics.\n", dev->name);
+  pr_linux_stats(&lp->linux_stats);
+  pr_mace_stats(&lp->mace_stats);
+
+  return &lp->linux_stats;
+} /* net_device_stats */
+
+/* ----------------------------------------------------------------------------
+updateCRC
+	Modified from Am79C90 data sheet.
+---------------------------------------------------------------------------- */
+
+#if BROKEN_MULTICAST
+
+static void updateCRC(int *CRC, int bit)
+{
+  int poly[]={
+    1,1,1,0, 1,1,0,1,
+    1,0,1,1, 1,0,0,0,
+    1,0,0,0, 0,0,1,1,
+    0,0,1,0, 0,0,0,0
+  }; /* CRC polynomial.  poly[n] = coefficient of the x**n term of the
+	CRC generator polynomial. */
+
+  int j;
+
+  /* shift CRC and control bit (CRC[32]) */
+  for (j = 32; j > 0; j--)
+    CRC[j] = CRC[j-1];
+  CRC[0] = 0;
+
+  /* If bit XOR(control bit) = 1, set CRC = CRC XOR polynomial. */
+  if (bit ^ CRC[32])
+    for (j = 0; j < 32; j++)
+      CRC[j] ^= poly[j];
+} /* updateCRC */
+
+/* ----------------------------------------------------------------------------
+BuildLAF
+	Build logical address filter.
+	Modified from Am79C90 data sheet.
+
+Input
+	ladrf: logical address filter (contents initialized to 0)
+	adr: ethernet address
+---------------------------------------------------------------------------- */
+static void BuildLAF(int *ladrf, int *adr)
+{
+  int CRC[33]={1}; /* CRC register, 1 word/bit + extra control bit */
+
+  int i, byte; /* temporary array indices */
+  int hashcode; /* the output object */
+
+  CRC[32]=0;
+
+  for (byte = 0; byte < 6; byte++)
+    for (i = 0; i < 8; i++)
+      updateCRC(CRC, (adr[byte] >> i) & 1);
+
+  hashcode = 0;
+  for (i = 0; i < 6; i++)
+    hashcode = (hashcode << 1) + CRC[i];
+
+  byte = hashcode >> 3;
+  ladrf[byte] |= (1 << (hashcode & 7));
+
+#ifdef PCMCIA_DEBUG
+  if (pc_debug > 2) {
+    printk(KERN_DEBUG "    adr =");
+    for (i = 0; i < 6; i++)
+      printk(" %02X", adr[i]);
+    printk("\n" KERN_DEBUG "    hashcode = %d(decimal), ladrf[0:63]"
+	   " =", hashcode);
+    for (i = 0; i < 8; i++)
+      printk(" %02X", ladrf[i]);
+    printk("\n");
+  }
+#endif
+} /* BuildLAF */
+
+/* ----------------------------------------------------------------------------
+restore_multicast_list
+	Restores the multicast filter for MACE chip to the last
+	set_multicast_list() call.
+
+Input
+	multicast_num_addrs
+	multicast_ladrf[]
+---------------------------------------------------------------------------- */
+static void restore_multicast_list(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  int num_addrs = lp->multicast_num_addrs;
+  int *ladrf = lp->multicast_ladrf;
+  ioaddr_t ioaddr = dev->base_addr;
+  int i;
+
+  DEBUG(2, "%s: restoring Rx mode to %d addresses.\n",
+	dev->name, num_addrs);
+
+  if (num_addrs > 0) {
+
+    DEBUG(1, "Attempt to restore multicast list detected.\n");
+
+    mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR);
+    /* Poll ADDRCHG bit */
+    while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
+      ;
+    /* Set LADRF register */
+    for (i = 0; i < MACE_LADRF_LEN; i++)
+      mace_write(ioaddr, MACE_LADRF, ladrf[i]);
+
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_RCVFCSE | MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+
+  } else if (num_addrs < 0) {
+
+    /* Promiscuous mode: receive all packets */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC,
+      MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV
+    );
+
+  } else {
+
+    /* Normal mode */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+
+  }
+} /* restore_multicast_list */
+
+/* ----------------------------------------------------------------------------
+set_multicast_list
+	Set or clear the multicast filter for this adaptor.
+
+Input
+	num_addrs == -1	Promiscuous mode, receive all packets
+	num_addrs == 0	Normal mode, clear multicast list
+	num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+Output
+	multicast_num_addrs
+	multicast_ladrf[]
+---------------------------------------------------------------------------- */
+
+static void set_multicast_list(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */
+  int i;
+  struct dev_mc_list *dmi = dev->mc_list;
+
+#ifdef PCMCIA_DEBUG
+  if (pc_debug > 1) {
+    static int old = 0;
+    if (dev->mc_count != old) {
+      old = dev->mc_count;
+      DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+	    dev->name, old);
+    }
+  }
+#endif
+
+  /* Set multicast_num_addrs. */
+  lp->multicast_num_addrs = dev->mc_count;
+
+  /* Set multicast_ladrf. */
+  if (num_addrs > 0) {
+    /* Calculate multicast logical address filter */
+    memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
+    for (i = 0; i < dev->mc_count; i++) {
+      memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN);
+      dmi = dmi->next;
+      BuildLAF(lp->multicast_ladrf, adr);
+    }
+  }
+
+  restore_multicast_list(dev);
+
+} /* set_multicast_list */
+
+#endif /* BROKEN_MULTICAST */
+
+static void restore_multicast_list(struct net_device *dev)
+{
+  ioaddr_t ioaddr = dev->base_addr;
+
+  DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name,
+	((mace_private *)(dev->priv))->multicast_num_addrs);
+  
+  if (dev->flags & IFF_PROMISC) {
+    /* Promiscuous mode: receive all packets */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC,
+      MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV
+    );
+  } else {
+    /* Normal mode */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+  }
+} /* restore_multicast_list */
+
+static void set_multicast_list(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+
+#ifdef PCMCIA_DEBUG
+  if (pc_debug > 1) {
+    static int old = 0;
+    if (dev->mc_count != old) {
+      old = dev->mc_count;
+      DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+	    dev->name, old);
+    }
+  }
+#endif
+
+  lp->multicast_num_addrs = dev->mc_count;
+  restore_multicast_list(dev);
+
+} /* set_multicast_list */
+
+/* ----------------------------------------------------------------------------
+init_nmclan_cs
+---------------------------------------------------------------------------- */
+
+static int __init init_nmclan_cs(void)
+{
+  servinfo_t serv;
+  DEBUG(0, "%s\n", version);
+  CardServices(GetCardServicesInfo, &serv);
+  if (serv.Revision != CS_RELEASE_CODE) {
+    printk(KERN_NOTICE "nmclan_cs: Card Services release does not match!\n");
+    return -1;
+  }
+  register_pccard_driver(&dev_info, &nmclan_attach, &nmclan_detach);
+  return 0;
+}
+
+/* ----------------------------------------------------------------------------
+exit_nmclan_cs
+---------------------------------------------------------------------------- */
+
+static void __exit exit_nmclan_cs(void)
+{
+  DEBUG(0, "nmclan_cs: unloading\n");
+  unregister_pccard_driver(&dev_info);
+  while (dev_list != NULL)
+    nmclan_detach(dev_list);
+}
+
+module_init(init_nmclan_cs);
+module_exit(exit_nmclan_cs);
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/ositech.h linux/drivers/net/pcmcia/ositech.h
--- v2.3.22/linux/drivers/net/pcmcia/ositech.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/ositech.h	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,358 @@
+/*
+    This file contains the firmware of Seven of Diamonds from OSITECH.
+    (Special thanks to Kevin MacPherson of OSITECH)
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+*/
+
+    static const u_char __Xilinx7OD[] = {
+    0xFF, 0x04, 0xA0, 0x36, 0xF3, 0xEC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF,
+    0xF3, 0xFF, 0xFF, 0xFF, 
+    0xEF, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F, 0xFE, 0xFF,
+    0xCE, 0xFE, 0xFE, 0xFE, 
+    0xFE, 0xDE, 0xBD, 0xDD, 0xFD, 0xFF, 0xFD, 0xCF, 0xF7, 0xBF, 0x7F, 0xFF,
+    0x7F, 0x3F, 0xFE, 0xBF, 
+    0xFF, 0xFF, 0xFF, 0xBC, 0xFF, 0xFF, 0xBD, 0xB5, 0x7F, 0x7F, 0xBF, 0xBF,
+    0x7F, 0xFF, 0xEF, 0xFF, 
+    0xFF, 0xFF, 0xFB, 0xFF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDE,
+    0xFE, 0xFE, 0xFA, 0xDE, 
+    0xBD, 0xFD, 0xED, 0xFD, 0xFD, 0xCF, 0xEF, 0xEF, 0xEF, 0xEF, 0xC7, 0xDF,
+    0xDF, 0xDF, 0xDF, 0xDF, 
+    0xFF, 0x7E, 0xFE, 0xFD, 0x7D, 0x6D, 0xEE, 0xFE, 0x7C, 0xFB, 0xF4, 0xFB,
+    0xCF, 0xDB, 0xDF, 0xFF, 
+    0xFF, 0xBB, 0x7F, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0x9E, 0xBF, 0x3B, 0xBF,
+    0xBF, 0x7F, 0x7F, 0x7F, 
+    0x7E, 0x6F, 0xDF, 0xEF, 0xF5, 0xF6, 0xFD, 0xF6, 0xF5, 0xED, 0xEB, 0xFF,
+    0xEF, 0xEF, 0xEF, 0x7E, 
+    0x7F, 0x7F, 0x6F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xEF, 0xBF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x1F, 0x1F, 0xEE, 0xFF, 0xBC,
+    0xB7, 0xFF, 0xDF, 0xFF, 
+    0xDF, 0xEF, 0x3B, 0xE3, 0xD3, 0xFF, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF,
+    0xFF, 0xBA, 0xBF, 0x2D, 
+    0xDB, 0xBD, 0xFD, 0xDB, 0xDF, 0xFA, 0xFB, 0xFF, 0xEF, 0xFB, 0xDB, 0xF3,
+    0xFF, 0xDF, 0xFD, 0x7F, 
+    0xEF, 0xFB, 0xFF, 0xFF, 0xBE, 0xBF, 0x27, 0xBA, 0xFE, 0xFB, 0xDF, 0xFF,
+    0xF6, 0xFF, 0xFF, 0xEF, 
+    0xFB, 0xDB, 0xF3, 0xD9, 0x9A, 0x3F, 0xFF, 0xAF, 0xBF, 0xFF, 0xFF, 0xBE,
+    0x3F, 0x37, 0xBD, 0x96, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, 0xFB, 0xF3, 0xF3, 0xEB, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xF7, 0xFA, 0xBC, 0xAE, 0xFE, 0xBE, 0xFE, 0xBB, 0x7F, 0xFD, 0xFF,
+    0x7F, 0xEF, 0xF7, 0xFB, 
+    0xBB, 0xD7, 0xF7, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xBC, 0xED, 0xFD,
+    0xBD, 0x9D, 0x7D, 0x7B, 
+    0xFB, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xF7, 
+    0xAA, 0xB9, 0xBF, 0x8F, 0xBF, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xCF,
+    0xFB, 0xEB, 0xCB, 0xEB, 
+    0xEE, 0xFF, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF, 0x3E, 0x33, 0x3F, 0x1C, 0x7C,
+    0xFC, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xCF, 0xD3, 0xF3, 0xE3, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xEB, 0xFE, 0x35, 
+    0x3F, 0x3D, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0x6F, 0xE3,
+    0xE3, 0xE3, 0xEF, 0xFF, 
+    0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFE, 0x3E, 0x5E, 0xFE, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFD, 0xFF, 0xFF, 
+    0xAF, 0xCF, 0xF2, 0xCB, 0xCF, 0x8E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD,
+    0xFC, 0x3E, 0x1F, 0x9E, 
+    0xAD, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xB3, 0xF7, 0xE7,
+    0xF7, 0xFA, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xEE, 0xEB, 0xAB, 0xAF, 0x9F, 0xE3, 0x7F, 0xFF, 0xDE,
+    0xFF, 0x7F, 0xEE, 0xFF, 
+    0xFF, 0xFB, 0x3A, 0xFA, 0xFF, 0xF2, 0x77, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF,
+    0xFE, 0xBD, 0xAE, 0xDE, 
+    0x7D, 0x7D, 0xFD, 0xFF, 0xBF, 0xEE, 0xFF, 0xFD, 0xFF, 0xDB, 0xFB, 0xFF,
+    0xF7, 0xEF, 0xFB, 0xFF, 
+    0xFF, 0xFE, 0xFF, 0x2D, 0xAF, 0xB9, 0xFD, 0x79, 0xFB, 0xFA, 0xFF, 0xBF,
+    0xEF, 0xFF, 0xFF, 0x91, 
+    0xFA, 0xFB, 0xDF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF, 0x37, 0xBF,
+    0xBF, 0xFF, 0x7F, 0x7F, 
+    0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xF3, 0xFB, 0xFB, 0xFF, 0xF5, 0xEF,
+    0xFF, 0xFF, 0xF7, 0xFA, 
+    0xFF, 0xFF, 0xEE, 0xFA, 0xFE, 0xFB, 0x55, 0xDD, 0xFF, 0x7F, 0xAF, 0xFE,
+    0xFF, 0xFB, 0xFB, 0xF5, 
+    0xFF, 0xF7, 0xEF, 0xFF, 0xFF, 0xFF, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D,
+    0x7B, 0x7B, 0x7B, 0x7B, 
+    0xFB, 0xAE, 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF7, 0xDA, 0xB7, 0x61, 
+    0xFF, 0xB9, 0x59, 0xF3, 0x73, 0xF3, 0xDF, 0x7F, 0x6F, 0xDF, 0xEF, 0xF7,
+    0xEB, 0xEB, 0xD7, 0xFF, 
+    0xD7, 0xFF, 0xFF, 0xF7, 0xFE, 0x7F, 0xFB, 0x3E, 0x38, 0x73, 0xF6, 0x7F,
+    0xFC, 0xFF, 0xFF, 0xCF, 
+    0xFF, 0xB7, 0xFB, 0xB3, 0xB3, 0x67, 0xFF, 0xE7, 0xFD, 0xFF, 0xEF, 0xF6,
+    0x7F, 0xB7, 0xBC, 0xF5, 
+    0x7B, 0xF6, 0xF7, 0xF5, 0xFF, 0xFF, 0xEF, 0xFF, 0xF7, 0xFF, 0xF7, 0xCE,
+    0xE7, 0xFF, 0x9F, 0xFF, 
+    0xFF, 0xF5, 0xFE, 0x7D, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xEF, 0xFF, 0xF6, 
+    0xCB, 0xDB, 0xEE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xBE,
+    0x1E, 0x3E, 0xFE, 0xFF, 
+    0x7D, 0xFE, 0xFF, 0xFF, 0xEF, 0xBF, 0xE7, 0xFF, 0xE3, 0xE3, 0xFF, 0xDF,
+    0xE7, 0xFF, 0xFF, 0xFF, 
+    0xB8, 0xEF, 0xB7, 0x2F, 0xEE, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x7F, 0xEF,
+    0xEB, 0xBF, 0xA3, 0xD3, 
+    0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xFD, 0x3F, 0xCF, 0xFD,
+    0xFB, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xAF, 0xFB, 0xBF, 0xBB, 0xBF, 0xDB, 0xFD, 0xFB, 0xFF, 0xFF,
+    0xFF, 0xFF, 0x3E, 0xFE, 
+    0x3F, 0xBA, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xEF, 0xC3, 0x7F,
+    0xB2, 0x9B, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x3C, 0xFF, 0x3F, 0x3C, 0xFF, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xAF, 0xF3, 0xFE, 0xF3, 0xE3, 0xEB, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xF7,
+    0x9A, 0xFE, 0xAF, 0x9E, 
+    0xBE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0x7B, 0xEF, 0xF7, 0xBF, 0xFB, 0xFB,
+    0xFB, 0xFF, 0xFF, 0x7F, 
+    0xFF, 0xFF, 0xFF, 0xBC, 0xBD, 0xFD, 0xBD, 0xDD, 0x7D, 0x7B, 0x7B, 0x7B,
+    0x7B, 0xFB, 0xAE, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x9A, 0xFF,
+    0x9F, 0xFF, 0xAF, 0xEF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xCF, 0xF3, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF,
+    0xFF, 0xBF, 0xFF, 0xFF, 
+    0xEF, 0xFE, 0xFF, 0x37, 0xFC, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xCF, 0xEF, 0xFD, 0xF3, 
+    0xFF, 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0xFD, 0x2F, 0xFD,
+    0xFF, 0xFD, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xEF, 0xCF, 0xFF, 0xF3, 0xBF, 0x69, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFE, 
+    0xFB, 0x9F, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x87,
+    0xFE, 0xDA, 0xEF, 0xCF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xBF, 0xEF, 0xEF, 0xFD,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xEF, 0xFD, 0xFF, 0x7B, 0xFF, 0xEB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xEB, 0xF8, 0xFF, 0xEF, 
+    0xAF, 0xFF, 0xFF, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F, 0xEE, 0x7F, 0xEF, 0xFF,
+    0xBB, 0xFF, 0xBF, 0xFB, 
+    0xFF, 0xFF, 0xFF, 0xF7, 0xF6, 0xFB, 0xBD, 0xFD, 0xDD, 0xF5, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xAF, 
+    0xFF, 0x5F, 0xF5, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6,
+    0xF3, 0xFF, 0xDE, 0xFE, 
+    0xEF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xDE, 0xDF, 0x5F, 0xDF,
+    0xFD, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xAF, 0xFF, 0xFF, 
+    0xEF, 0xED, 0xFF, 0xDF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xDA, 0xBD, 0xBE,
+    0xAE, 0xFE, 0x7F, 0xFD, 
+    0xDF, 0xFF, 0xFF, 0x7F, 0xEF, 0xFF, 0xFB, 0xFB, 0xFB, 0x7F, 0xF7, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xF7, 
+    0xBC, 0xFD, 0xBD, 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE,
+    0xFF, 0xFF, 0xFD, 0xFF, 
+    0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x9F, 0xBF, 0xBF, 0xCF,
+    0x7F, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xAF, 0xFF, 0xEB, 0xEB, 0xEB, 0xFF, 0xD7, 0xFE, 0xFF, 0xFF,
+    0xBF, 0xE7, 0xFE, 0xBF, 
+    0x7F, 0xFC, 0xFF, 0xFF, 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFB,
+    0xFB, 0xFF, 0xFF, 0xDD, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBD, 0xDF, 0x9D, 0xFD, 0xDF, 0xB9,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xEF, 0xFF, 0xFB, 0xEF, 0xEB, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF6, 0x9F, 0xFF, 0xFC, 
+    0xFE, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xDF, 0xFA, 0xCD, 0xCF,
+    0xBF, 0x9F, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xF7, 0xFE, 0xBF, 0xFF, 0xDF, 0xEF, 0x5F, 0xFF, 0xFF, 0xFF,
+    0xFF, 0x7F, 0x6F, 0xFF, 
+    0xBB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0xFF,
+    0x5F, 0xFF, 0xBF, 0xBF, 
+    0xF9, 0xFF, 0xFF, 0xFF, 0x7F, 0x6E, 0x7B, 0xFF, 0xEF, 0xFD, 0xEB, 0xDF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xF7, 0xB6, 0x3E, 0xFC, 0xFD, 0xBF, 0x7E, 0xFB, 0xFF, 0xFF, 0xFF, 0xF7,
+    0xEF, 0xF7, 0xF3, 0xF7, 
+    0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0x35, 0x79, 0xFF,
+    0xBF, 0xFC, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0x53, 0xDF, 0xFF, 0xEB, 0xBF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xBC, 
+    0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF5,
+    0xFF, 0xF7, 0xFF, 0xFB, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xAA, 0xEE, 0xFE, 0x3F, 0x7D,
+    0xFD, 0xFF, 0xFF, 0xFF, 
+    0x7F, 0xAF, 0x77, 0xFB, 0xFB, 0xFF, 0xFB, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF7, 0xBE, 0xBD, 0xBD, 
+    0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, 0xFF, 0xEF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFC, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0xD9, 0xB8, 0xFF, 0xFF, 0x79, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xCF, 
+    0xFB, 0xFF, 0xEB, 0xFF, 0xEB, 0xD7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDE,
+    0xF8, 0xFB, 0xFE, 0x3F, 
+    0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xAD, 0xBF, 0xFA, 0xFF, 0x73,
+    0xDF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0x3A, 0xF5, 0xB7, 0xFC, 0x3F, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF,
+    0x7F, 0xEF, 0xF3, 0xFF, 
+    0xBF, 0xFE, 0xF3, 0x9F, 0xFE, 0xFF, 0xFF, 0xFF, 0xF7, 0x3E, 0xFF, 0xFF,
+    0xFF, 0xBF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xD3, 0xFE, 0xDB, 0xFF, 0xDB, 0xDF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0x3E, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F,
+    0xF3, 0xFF, 0xED, 0xFF, 
+    0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF6, 0x3C, 0xFE, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x9F, 0xEF, 0xEF, 0xD1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0x7E, 0xBF, 
+    0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0xEF, 0xDF, 0xF1,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x3E, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xBF, 
+    0xEF, 0xFD, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
+    0xFC, 0x3E, 0xFE, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2E, 0xEF, 0xF3, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xF7, 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0x7F, 0xAF, 0xFB, 
+    0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xF2, 0xD6, 0xED,
+    0xBD, 0xBD, 0xBD, 0x7D, 
+    0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x92, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+    0xAF, 0xEB, 0xEB, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFE, 0x2E, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0x4F, 0xEF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFE, 
+    0x3C, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xCE,
+    0xC3, 0xFD, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xEF, 0xCF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF7, 0xEE, 0x3E, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xDF, 0xE2, 0xFF,
+    0xFF, 0xFF, 0xFB, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xBE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0x7F, 0xEE, 
+    0x5F, 0xE6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E,
+    0x7D, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xBF, 0xF7, 0x36, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xEF, 0xD3, 0xF6, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xEE,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xEF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE,
+    0xFB, 0xFA, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD6, 0xFD, 0xBD, 0xBD, 0xBD,
+    0x7D, 0x7B, 0x7B, 0x7B, 
+    0x7B, 0xFB, 0xAE, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xF7, 0xBA, 0xBF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xEB, 0x6B,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0x4F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+    0x3E, 0x6E, 0xFC, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC3, 0xC9, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0x3E, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xEF, 0xFB, 
+    0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE,
+    0xFE, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0xEF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFB,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xF6, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE,
+    0xEF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0xF7, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x7F, 0xFA, 0xEF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xE7, 0xFF, 0xFE, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xEF, 0xBF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0xFF, 0xFC, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0x7F, 
+    0xFE, 0xAE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7,
+    0xF7, 0xFA, 0xFF, 0xFD, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B,
+    0x7B, 0x7B, 0xFB, 0xAF, 
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xE7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xCF, 0xFE, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xE7, 0xF2, 0xFC, 
+    0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAE, 0xEF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7E, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
+    0xFE, 0xFE, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0xDD, 0xFE, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xAF, 0xEF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xF6, 0x9C, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB,
+    0xAE, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7A, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xDF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0x6F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xF7, 0xFE, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xEB,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x9E, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xEF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFE, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xCB, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFD, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xEF, 
+    0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFB, 0xAF, 0x7F, 0xFF, 
+    0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xBF, 0xFF, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x7F, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xF7, 0xBC, 0xBD, 
+    0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0x7F, 
+    0xAF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+    0xFE, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF,
+    0xFF, 0xFF, 0xEF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xBF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xEF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFE, 0xFF, 0x9F, 0x9F,
+    0x9F, 0x3F, 0x3F, 0x3F, 
+    0x3F, 0x3F, 0xFF, 0xEF, 0xDF, 0xDF, 0xDF, 0xDF, 0xCF, 0xB7, 0xBF, 0xBF,
+    0xBF, 0xBF, 0xFF, 0xBC, 
+    0xB9, 0x9D, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xEF, 0xD7,
+    0xF5, 0xF3, 0xF1, 0xD1, 
+    0x65, 0xE3, 0xE3, 0xE3, 0xA3, 0xFF, 0xFE, 0x7F, 0xFE, 0xDE, 0xDE, 0xFF,
+    0xBD, 0xBD, 0xBD, 0xBD, 
+    0xDF, 0xEF, 0xFB, 0xF7, 0xF3, 0xF3, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
+    0xFB, 0xFE, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+    
+    };
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/pcnet_cs.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/pcmcia/pcnet_cs.c	Wed Oct 20 21:33:12 1999
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dhinds@hyper.stanford.edu
 
-    pcnet_cs.c 1.99 1999/09/15 15:33:09
+    pcnet_cs.c 1.101 1999/10/21 00:56:19
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -72,7 +72,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.99 1999/09/15 15:33:09 (David Hinds)";
+"pcnet_cs.c 1.101 1999/10/21 00:56:19 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -477,7 +477,8 @@
 {
     struct net_device *dev = link->priv;
     unsigned char prom[32];
-    int i, j, ioaddr;
+    ioaddr_t ioaddr;
+    int i, j;
 
     /* This is lifted straight from drivers/net/ne.c */
     struct {
@@ -851,7 +852,7 @@
 
 static void set_misc_reg(struct net_device *dev)
 {
-    int nic_base = dev->base_addr;
+    ioaddr_t nic_base = dev->base_addr;
     pcnet_dev_t *info = (pcnet_dev_t *)dev;
     u_char tmp;
     
@@ -889,7 +890,7 @@
 	int i;
 	for (i = 0; i < 20; i++) {
 	    if ((inb(dev->base_addr+0x1c) & 0x01) == 0) break;
-	    current->state = TASK_INTERRUPTIBLE;
+	    __set_current_state(TASK_UNINTERRUPTIBLE);
 	    schedule_timeout(HZ/10);
 	}
     }
@@ -941,7 +942,7 @@
 
 static void pcnet_reset_8390(struct net_device *dev)
 {
-    int nic_base = dev->base_addr;
+    ioaddr_t nic_base = dev->base_addr;
     int i;
 
     ei_status.txing = ei_status.dmaing = 0;
@@ -996,7 +997,7 @@
 {
     pcnet_dev_t *info = (pcnet_dev_t *)(arg);
     struct net_device *dev = &info->dev;
-    int nic_base = dev->base_addr;
+    ioaddr_t nic_base = dev->base_addr;
 
     if (dev->start == 0) goto reschedule;
 
@@ -1027,7 +1028,7 @@
 			     struct e8390_pkt_hdr *hdr,
 			     int ring_page)
 {
-    int nic_base = dev->base_addr;
+    ioaddr_t nic_base = dev->base_addr;
 
     if (ei_status.dmaing) {
 	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
@@ -1059,7 +1060,7 @@
 static void dma_block_input(struct net_device *dev, int count,
 			    struct sk_buff *skb, int ring_offset)
 {
-    int nic_base = dev->base_addr;
+    ioaddr_t nic_base = dev->base_addr;
     int xfer_count = count;
     char *buf = skb->data;
 
@@ -1116,7 +1117,7 @@
 			     const unsigned char *buf,
 			     const int start_page)
 {
-    int nic_base = dev->base_addr;
+    ioaddr_t nic_base = dev->base_addr;
     pcnet_dev_t *info = (pcnet_dev_t *)dev;
 #ifdef PCMCIA_DEBUG
     int retries = 0;
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/smc91c92_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,2013 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for SMC91c92-based cards.
+
+    This driver supports Megahertz PCMCIA ethernet cards; and
+    Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
+    multifunction cards.
+
+    Copyright (C) 1999 David A. Hinds -- dhinds@hyper.stanford.edu
+
+    smc91c92_cs.c 1.79 1999/10/19 00:38:29
+    
+    This driver contains code written by Donald Becker
+    (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au),
+    David Hinds (dhinds@hyper.stanford.edu), and Erik Stahlman
+    (erik@vt.edu).  Donald wrote the SMC 91c92 code using parts of
+    Erik's SMC 91c94 driver.  Rowan wrote a similar driver, and I've
+    incorporated some parts of his driver here.  I (Dave) wrote most
+    of the PCMCIA glue code, and the Ositech support code.  Kelly
+    Stephens (kstephen@holli.com) added support for the Motorola
+    Mariner, with help from Allen Brost. 
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+/* Ositech Seven of Diamonds firmware */
+#include "ositech.h"
+
+/*====================================================================*/
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+static char *if_names[] = { "auto", "10baseT", "10base2"};
+
+/* Parameters that can be set with 'insmod' */
+
+/*
+  Transceiver/media type.
+   0 = auto
+   1 = 10baseT (and autoselect if #define AUTOSELECT),
+   2 = AUI/10base2,
+*/
+static int if_port = 0;
+
+/* Bit map of interrupts to choose from. */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(if_port, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/* Operational parameter that usually are not changed. */
+
+/* Do you want to use 32 bit xfers?  This should work on all chips,
+   but could cause trouble with some PCMCIA controllers... */
+#define USE_32_BIT		1
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT		((400*HZ)/1000)
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+#define INTR_WORK		4
+
+/* Times to check the check the chip before concluding that it doesn't
+   currently have room for another Tx packet. */
+#define MEMORY_WAIT_TIME       	8
+
+/* Values that should be specific lengths */
+typedef unsigned short uint16;
+
+static dev_info_t dev_info = "smc91c92_cs";
+
+static dev_link_t *dev_list = NULL;
+
+struct smc_private {
+    u_short			manfid;
+    u_short			cardid;
+    struct net_device_stats	stats;
+    dev_node_t			node;
+    struct sk_buff		*saved_skb;
+    int				packets_waiting;
+    caddr_t			base;
+    u_short			cfg;
+    struct timer_list		media;
+    int				watchdog, tx_err;
+    u_short			media_status;
+    u_short			fast_poll;
+    u_long			last_rx;
+};
+
+/* Special definitions for Megahertz multifunction cards */
+#define MEGAHERTZ_ISR		0x0380
+
+/* Special function registers for Motorola Mariner */
+#define MOT_LAN			0x0000
+#define MOT_UART		0x0020
+#define MOT_EEPROM		0x20
+
+#define MOT_NORMAL \
+(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
+
+/* Special function registers for Ositech cards */
+#define OSITECH_AUI_CTL		0x0c
+#define OSITECH_PWRDOWN		0x0d
+#define OSITECH_RESET		0x0e
+#define OSITECH_ISR		0x0f
+#define OSITECH_AUI_PWR		0x0c
+#define OSITECH_RESET_ISR	0x0e
+
+#define OSI_AUI_PWR		0x40
+#define OSI_LAN_PWRDOWN		0x02
+#define OSI_MODEM_PWRDOWN	0x01
+#define OSI_LAN_RESET		0x02
+#define OSI_MODEM_RESET		0x01
+
+/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
+#define	BANK_SELECT		14		/* Window select register. */
+#define SMC_SELECT_BANK(x)  { outw( x, ioaddr + BANK_SELECT); }
+
+/* Bank 0 registers. */
+#define	TCR 		0	/* transmit control register */
+#define	 TCR_CLEAR	0	/* do NOTHING */
+#define  TCR_ENABLE	0x0001	/* if this is 1, we can transmit */
+#define	 TCR_PAD_EN	0x0080	/* pads short packets to 64 bytes */
+#define  TCR_MONCSN	0x0400  /* Monitor Carrier. */
+#define  TCR_FDUPLX	0x0800  /* Full duplex mode. */
+#define	 TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
+
+#define EPH		2	/* Ethernet Protocol Handler report. */
+#define  EPH_TX_SUC	0x0001
+#define  EPH_SNGLCOL	0x0002
+#define  EPH_MULCOL	0x0004
+#define  EPH_LTX_MULT	0x0008
+#define  EPH_16COL	0x0010
+#define  EPH_SQET	0x0020
+#define  EPH_LTX_BRD	0x0040
+#define  EPH_TX_DEFR	0x0080
+#define  EPH_LAT_COL	0x0200
+#define  EPH_LOST_CAR	0x0400
+#define  EPH_EXC_DEF	0x0800
+#define  EPH_CTR_ROL	0x1000
+#define  EPH_RX_OVRN	0x2000
+#define  EPH_LINK_OK	0x4000
+#define  EPH_TX_UNRN	0x8000
+#define MEMINFO		8	/* Memory Information Register */
+#define MEMCFG		10	/* Memory Configuration Register */
+
+/* Bank 1 registers. */
+#define CONFIG			0
+#define  CFG_MII_SELECT		0x8000	/* 91C100 only */
+#define  CFG_NO_WAIT		0x1000
+#define  CFG_FULL_STEP		0x0400
+#define  CFG_SET_SQLCH		0x0200
+#define  CFG_AUI_SELECT	 	0x0100
+#define  CFG_16BIT		0x0080
+#define  CFG_DIS_LINK		0x0040
+#define  CFG_STATIC		0x0030
+#define  CFG_IRQ_SEL_1		0x0004
+#define  CFG_IRQ_SEL_0		0x0002
+#define BASE_ADDR		2
+#define	ADDR0			4
+#define	GENERAL			10
+#define	CONTROL			12
+#define  CTL_STORE		0x0001
+#define  CTL_RELOAD		0x0002
+#define  CTL_EE_SELECT		0x0004
+#define  CTL_TE_ENABLE		0x0020
+#define  CTL_CR_ENABLE		0x0040
+#define  CTL_LE_ENABLE		0x0080
+#define  CTL_AUTO_RELEASE	0x0800
+#define	 CTL_POWERDOWN		0x2000
+
+/* Bank 2 registers. */
+#define MMU_CMD		0
+#define	 MC_ALLOC	0x20  	/* or with number of 256 byte packets */
+#define	 MC_RESET	0x40
+#define  MC_RELEASE  	0x80  	/* remove and release the current rx packet */
+#define  MC_FREEPKT  	0xA0  	/* Release packet in PNR register */
+#define  MC_ENQUEUE	0xC0 	/* Enqueue the packet for transmit */
+#define	PNR_ARR		2
+#define FIFO_PORTS	4
+#define  FP_RXEMPTY	0x8000
+#define	POINTER		6
+#define  PTR_AUTO_INC	0x0040
+#define  PTR_READ	0x2000
+#define	 PTR_AUTOINC 	0x4000
+#define	 PTR_RCV	0x8000
+#define	DATA_1		8
+#define	INTERRUPT	12
+#define  IM_RCV_INT		0x1
+#define	 IM_TX_INT		0x2
+#define	 IM_TX_EMPTY_INT	0x4
+#define	 IM_ALLOC_INT		0x8
+#define	 IM_RX_OVRN_INT		0x10
+#define	 IM_EPH_INT		0x20
+
+#define	RCR		4
+enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
+	     RxEnable = 0x0100, RxStripCRC = 0x0200};
+#define  RCR_SOFTRESET	0x8000 	/* resets the chip */
+#define	 RCR_STRIP_CRC	0x200	/* strips CRC */
+#define  RCR_ENABLE	0x100	/* IFF this is set, we can recieve packets */
+#define  RCR_ALMUL	0x4 	/* receive all multicast packets */
+#define	 RCR_PROMISC	0x2	/* enable promiscuous mode */
+
+/* the normal settings for the RCR register : */
+#define	 RCR_NORMAL	(RCR_STRIP_CRC | RCR_ENABLE)
+#define  RCR_CLEAR	0x0		/* set it to a base state */
+#define	COUNTER		6
+
+/* BANK 3 -- not the same values as in smc9194! */
+#define	MULTICAST0	0
+#define	MULTICAST2	2
+#define	MULTICAST4	4
+#define	MULTICAST6	6
+#define REVISION	0x0a
+
+/* Transmit status bits. */
+#define TS_SUCCESS 0x0001
+#define TS_16COL   0x0010
+#define TS_LATCOL  0x0200
+#define TS_LOSTCAR 0x0400
+
+/* Receive status bits. */
+#define RS_ALGNERR	0x8000
+#define RS_BADCRC	0x2000
+#define RS_ODDFRAME	0x1000
+#define RS_TOOLONG	0x0800
+#define RS_TOOSHORT	0x0400
+#define RS_MULTICAST	0x0001
+#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+#define set_bits(v, p) outw(inw(p)|(v), (p))
+#define mask_bits(v, p) outw(inw(p)&(v), (p))
+
+/*====================================================================*/
+
+static dev_link_t *smc91c92_attach(void);
+static void smc91c92_detach(dev_link_t *);
+static void smc91c92_config(dev_link_t *link);
+static void smc91c92_release(u_long arg);
+static int smc91c92_event(event_t event, int priority,
+			  event_callback_args_t *args);
+
+static int smc91c92_open(struct net_device *dev);
+static int smc91c92_close(struct net_device *dev);
+static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void smc_rx(struct net_device *dev);
+static struct net_device_stats *smc91c92_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static int s9k_config(struct net_device *dev, struct ifmap *map);
+static void smc_set_xcvr(struct net_device *dev, int if_port);
+static void smc_reset(struct net_device *dev);
+static void media_check(u_long arg);
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    smc91c92_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static int smc91c92_init(struct net_device *dev)
+{
+    DEBUG(0, "%s: smc91c92_init called!\n", dev->name);
+    return 0;
+}
+
+/*======================================================================
+
+  smc91c92_attach() creates an "instance" of the driver, allocating
+  local data structures for one device.  The device is registered
+  with Card Services.
+
+======================================================================*/
+
+static dev_link_t *smc91c92_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    int i, ret;
+
+    DEBUG(0, "smc91c92_attach()\n");
+    flush_stale_links();
+    
+    /* Create new ethernet device */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &smc91c92_release;
+    link->release.data = (u_long)link;
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 4;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &smc_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev, 0, sizeof(struct net_device));
+    
+    /* Make up a SMC91-specific-data structure. */
+    dev->priv = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
+    memset(dev->priv, 0, sizeof(struct smc_private));
+    
+    /* The SMC91c92-specific entries in the device structure. */
+    dev->hard_start_xmit = &smc_start_xmit;
+    dev->get_stats = &smc91c92_get_stats;
+    dev->set_config = &s9k_config;
+    dev->set_multicast_list = &set_rx_mode;
+    ether_setup(dev);
+    dev->name = ((struct smc_private *)dev->priv)->node.dev_name;
+    dev->init = &smc91c92_init;
+    dev->open = &smc91c92_open;
+    dev->stop = &smc91c92_close;
+    dev->tbusy = 1;
+    link->priv = link->irq.Instance = dev;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &smc91c92_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	smc91c92_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* smc91c92_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void smc91c92_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    long flags;
+
+    DEBUG(0, "smc91c92_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+    
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+    
+    if (link->state & DEV_CONFIG) {
+	smc91c92_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+    
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev != NULL)
+	    unregister_netdev(dev);
+	if (dev->priv)
+	    kfree(dev->priv);
+	kfree(link->priv);
+    }
+    kfree(link);
+    
+} /* smc91c92_detach */
+
+/*====================================================================*/
+
+static int cvt_ascii_address(struct net_device *dev, char *s)
+{
+    int i, j, da, c;
+
+    if (strlen(s) != 12)
+	return -1;
+    for (i = 0; i < 6; i++) {
+	da = 0;
+	for (j = 0; j < 2; j++) {
+	    c = *s++;
+	    da <<= 4;
+	    da += ((c >= '0') && (c <= '9')) ?
+		(c - '0') : ((c & 0x0f) + 9);
+	}
+	dev->dev_addr[i] = da;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+		     cisparse_t *parse)
+{
+    int i;
+    i = CardServices(fn, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    i = CardServices(GetTupleData, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+/*======================================================================
+
+    Configuration stuff for Megahertz cards
+
+    mhz_3288_power() is used to power up a 3288's ethernet chip.
+    mhz_mfc_config() handles socket setup for multifunction (1144
+    and 3288) cards.  mhz_setup() gets a card's hardware ethernet
+    address.
+    
+======================================================================*/
+
+static int mhz_3288_power(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *lp = dev->priv;
+    u_char tmp;
+    
+    /* Read the ISR twice... */
+    readb(lp->base+MEGAHERTZ_ISR);
+    udelay(5);
+    readb(lp->base+MEGAHERTZ_ISR);
+
+    /* Pause 200ms... */
+    mdelay(200);
+    
+    /* Now read and write the COR... */
+    tmp = readb(lp->base + link->conf.ConfigBase + CISREG_COR);
+    udelay(5);
+    writeb(tmp, lp->base + link->conf.ConfigBase + CISREG_COR);
+
+    return 0;
+}
+
+static int mhz_mfc_config(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *lp = dev->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255];
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    win_req_t req;
+    memreq_t mem;
+    int i, k;
+
+    link->conf.Attributes |= CONF_ENABLE_SPKR;
+    link->conf.Status = CCSR_AUDIO_ENA;
+    link->irq.Attributes =
+	IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts2 = 8;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+    i = first_tuple(link->handle, &tuple, &parse);
+    /* The Megahertz combo cards have modem-like CIS entries, so
+       we have to explicitly try a bunch of port combinations. */
+    while (i == CS_SUCCESS) {
+	link->conf.ConfigIndex = cf->index;
+	link->io.BasePort2 = cf->io.win[0].base;
+	for (k = 0; k < 0x400; k += 0x10) {
+	    if (k & 0x80) continue;
+	    link->io.BasePort1 = k ^ 0x300;
+	    i = CardServices(RequestIO, link->handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+	if (i == CS_SUCCESS) break;
+	i = next_tuple(link->handle, &tuple, &parse);
+    }
+    if (i != CS_SUCCESS)
+	return i;
+    dev->base_addr = link->io.BasePort1;
+    
+    /* Allocate a memory window, for accessing the ISR */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = 0;
+    req.Size = 0x1000;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS)
+	return i;
+    lp->base = ioremap(req.Base, 0x1000);
+    mem.CardOffset = mem.Page = 0;
+    if (lp->manfid == MANFID_MOTOROLA)
+	mem.CardOffset = link->conf.ConfigBase;
+    i = CardServices(MapMemPage, link->win, &mem);
+    
+    if ((i == CS_SUCCESS)
+	&& (lp->manfid == MANFID_MEGAHERTZ)
+	&& (lp->cardid == PRODID_MEGAHERTZ_EM3288))
+	mhz_3288_power(link);
+    
+    return i;
+}
+
+static int mhz_setup(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct net_device *dev = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255], *station_addr;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+
+    /* Read the station address from the CIS.  It is stored as the last
+       (fourth) string in the Version 1 Version/ID tuple. */
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
+	return -1;
+    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
+    if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS)
+	first_tuple(handle, &tuple, &parse);
+    if (parse.version_1.ns > 3) {
+	station_addr = parse.version_1.str + parse.version_1.ofs[3];
+	if (cvt_ascii_address(dev, station_addr) == 0)
+	    return 0;
+    }
+
+    /* Another possibility: for the EM3288, in a special tuple */
+    tuple.DesiredTuple = 0x81;
+    if (CardServices(GetFirstTuple, handle, &tuple) != CS_SUCCESS)
+	return -1;
+    if (CardServices(GetTupleData, handle, &tuple) != CS_SUCCESS)
+	return -1;
+    buf[12] = '\0';
+    if (cvt_ascii_address(dev, buf) == 0)
+	return 0;
+    
+    return -1;
+}
+
+/*======================================================================
+
+    Configuration stuff for the Motorola Mariner
+
+    mot_config() writes directly to the Mariner configuration
+    registers because the CIS is just bogus.
+    
+======================================================================*/
+
+static void mot_config(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *lp = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    ioaddr_t iouart = link->io.BasePort2;
+    
+    /* Set UART base address and force map with COR bit 1 */
+    writeb(iouart & 0xff,        lp->base + MOT_UART + CISREG_IOBASE_0);
+    writeb((iouart >> 8) & 0xff, lp->base + MOT_UART + CISREG_IOBASE_1);
+    writeb(MOT_NORMAL,           lp->base + MOT_UART + CISREG_COR);
+    
+    /* Set SMC base address and force map with COR bit 1 */
+    writeb(ioaddr & 0xff,        lp->base + MOT_LAN + CISREG_IOBASE_0);
+    writeb((ioaddr >> 8) & 0xff, lp->base + MOT_LAN + CISREG_IOBASE_1);
+    writeb(MOT_NORMAL,           lp->base + MOT_LAN + CISREG_COR);
+
+    /* Wait for things to settle down */
+    mdelay(100);
+}
+
+static int mot_setup(dev_link_t *link) {
+    struct net_device *dev = link->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i, wait, loop;
+    unsigned int addr;
+
+    /* Read Ethernet address from Serial EEPROM */
+    
+    for (i = 0; i < 3; i++) {
+	SMC_SELECT_BANK( 2 );
+	outw(MOT_EEPROM + i, ioaddr + POINTER);
+	SMC_SELECT_BANK( 1 );
+	outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
+
+	for (loop = 0; loop < 200; loop++) {
+	    udelay(10);
+	    wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
+	    if (wait == 0) break;
+	}
+	
+	if (wait)
+	    return -1;
+	
+	addr = inw(ioaddr + GENERAL);
+	dev->dev_addr[2*i]   = addr & 0xff;
+	dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
+    }
+    
+    return 0;
+}
+
+/*====================================================================*/
+
+static int smc_config(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255];
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+    link->io.NumPorts1 = 16;
+    i = first_tuple(link->handle, &tuple, &parse);
+    while (i != CS_NO_MORE_ITEMS) {
+	if (i == CS_SUCCESS) {
+	    link->conf.ConfigIndex = cf->index;
+	    link->io.BasePort1 = cf->io.win[0].base;
+	    i = CardServices(RequestIO, link->handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+	i = next_tuple(link->handle, &tuple, &parse);
+    }
+    if (i == CS_SUCCESS)
+	dev->base_addr = link->io.BasePort1;
+    return i;
+}
+
+static int smc_setup(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct net_device *dev = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    cistpl_lan_node_id_t *node_id;
+    u_char buf[255], *station_addr;
+    int i;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    
+    /* Check for a LAN function extension tuple */
+    tuple.DesiredTuple = CISTPL_FUNCE;
+    i = first_tuple(handle, &tuple, &parse);
+    while (i == CS_SUCCESS) {
+	if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID)
+	    break;
+	i = next_tuple(handle, &tuple, &parse);
+    }
+    if (i == CS_SUCCESS) {
+	node_id = (cistpl_lan_node_id_t *)parse.funce.data;
+	if (node_id->nb == 6) {
+	    for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = node_id->id[i];
+	    return 0;
+	}
+    }
+    
+    /* Try the third string in the Version 1 Version/ID tuple. */
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
+	return -1;
+    station_addr = parse.version_1.str + parse.version_1.ofs[2];
+    if (cvt_ascii_address(dev, station_addr) == 0)
+	return 0;
+
+    return -1;
+}
+
+/*====================================================================*/
+
+static int osi_config(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+    int i, j;
+    
+    link->conf.Attributes |= CONF_ENABLE_SPKR;
+    link->conf.Status = CCSR_AUDIO_ENA;
+    link->irq.Attributes =
+	IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+    link->io.NumPorts1 = 64;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts2 = 8;
+    
+    /* Enable Hard Decode, LAN, Modem */
+    link->conf.ConfigIndex = 0x23;
+    
+    for (j = 0; j < 4; j++) {
+	link->io.BasePort2 = com[j];
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	/* Fallback: turn off hard decode */
+	link->conf.ConfigIndex = 0x03;
+	link->io.NumPorts2 = 0;
+	i = CardServices(RequestIO, link->handle, &link->io);
+    }
+    dev->base_addr = link->io.BasePort1 + 0x10;
+    return i;
+}
+
+static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
+{
+    client_handle_t handle = link->handle;
+    struct net_device *dev = link->priv;
+    tuple_t tuple;
+    u_char buf[255];
+    int i;
+    
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    
+    /* Read the station address from tuple 0x90, subtuple 0x04 */
+    tuple.DesiredTuple = 0x90;
+    i = CardServices(GetFirstTuple, handle, &tuple);
+    while (i == CS_SUCCESS) {
+	i = CardServices(GetTupleData, handle, &tuple);
+	if ((i != CS_SUCCESS) || (buf[0] == 0x04))
+	    break;
+	i = CardServices(GetNextTuple, handle, &tuple);
+    }
+    if (i != CS_SUCCESS)
+	return -1;
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = buf[i+2];
+
+    if (manfid != MANFID_OSITECH) return 0;
+
+    if (cardid == PRODID_OSITECH_SEVEN) {
+	/* Download the Seven of Diamonds firmware */
+	for (i = 0; i < sizeof(__Xilinx7OD); i++) {
+	    outb(__Xilinx7OD[i], link->io.BasePort1+2);
+	    udelay(50);
+	}
+    } else {
+	/* Make sure both functions are powered up */
+	set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
+	/* Now, turn on the interrupt for both card functions */
+	set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR);
+	DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
+	      inw(link->io.BasePort1 + OSITECH_AUI_PWR),
+	      inw(link->io.BasePort1 + OSITECH_RESET_ISR));
+    }
+
+    return 0;
+}
+
+/*======================================================================
+
+    This verifies that the chip is some SMC91cXX variant, and returns
+    the revision code if successful.  Otherwise, it returns -ENODEV.
+    
+======================================================================*/
+
+static int check_sig(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int width;
+    u_short s;
+
+    SMC_SELECT_BANK(1);
+    if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
+	/* Try powering up the chip */
+	outw(0, ioaddr + CONTROL);
+	mdelay(55);
+    }
+
+    /* Try setting bus width */
+    width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO);
+    s = inb(ioaddr + CONFIG);
+    if (width)
+	s |= CFG_16BIT;
+    else
+	s &= ~CFG_16BIT;
+    outb(s, ioaddr + CONFIG);
+    
+    /* Check Base Address Register to make sure bus width is OK */
+    s = inw(ioaddr + BASE_ADDR);
+    if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
+	((s >> 8) != (s & 0xff))) {
+	SMC_SELECT_BANK(3);
+	s = inw(ioaddr + REVISION);
+	return (s & 0xff);
+    }
+
+    if (width) {
+	event_callback_args_t args;
+	printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
+	args.client_data = link;
+	smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	CardServices(RequestIO, link->handle, &link->io);
+	smc91c92_event(CS_EVENT_CARD_RESET, 0, &args);
+	return check_sig(link);
+    }
+    return -ENODEV;
+}
+
+/*======================================================================
+
+    smc91c92_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+
+======================================================================*/
+
+#define CS_EXIT_TEST(ret, svc, label) \
+if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; }
+
+static void smc91c92_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct net_device *dev = link->priv;
+    struct smc_private *lp = dev->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_short buf[32];
+    char *name;
+    int i, rev;
+
+    DEBUG(0, "smc91c92_config(0x%p)\n", link);
+    
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    i = first_tuple(handle, &tuple, &parse);
+    CS_EXIT_TEST(i, ParseTuple, config_failed);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    tuple.DesiredTuple = CISTPL_MANFID;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+	lp->manfid = parse.manfid.manf;
+	lp->cardid = parse.manfid.card;
+    }
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    if (lp->manfid == MANFID_OSITECH) {
+	i = osi_config(link);
+    } else if (lp->manfid == MANFID_MOTOROLA
+	     || ((lp->manfid == MANFID_MEGAHERTZ)
+		 && ((lp->cardid == PRODID_MEGAHERTZ_VARIOUS)
+		     || (lp->cardid == PRODID_MEGAHERTZ_EM3288)))) {
+	i = mhz_mfc_config(link);
+    } else {
+	i = smc_config(link);
+    }
+    CS_EXIT_TEST(i, RequestIO, config_failed);
+    
+    i = CardServices(RequestIRQ, link->handle, &link->irq);
+    CS_EXIT_TEST(i, RequestIRQ, config_failed);
+    i = CardServices(RequestConfiguration, link->handle, &link->conf);
+    CS_EXIT_TEST(i, RequestConfiguration, config_failed);
+    
+    if (lp->manfid == MANFID_MOTOROLA)
+	mot_config(link);
+
+    dev->irq = link->irq.AssignedIRQ;
+
+    if ((if_port >= 0) && (if_port <= 2))
+	dev->if_port = if_port;
+    else
+	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
+    dev->tbusy = 0;
+    
+    if (register_netdev(dev) != 0) {
+	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
+	goto config_undo;
+    }
+
+    switch (lp->manfid) {
+    case MANFID_OSITECH:
+    case MANFID_PSION:
+	i = osi_setup(link, lp->manfid, lp->cardid); break;
+    case MANFID_SMC:
+    case MANFID_NEW_MEDIA:
+	i = smc_setup(link); break;
+    case 0x128: /* For broken Megahertz cards */
+    case MANFID_MEGAHERTZ:
+	i = mhz_setup(link); break;
+    case MANFID_MOTOROLA:
+    default: /* get the hw address from EEPROM */
+	i = mot_setup(link); break;
+    }
+    
+    if (i != 0) {
+	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
+	link->state &= ~DEV_CONFIG_PENDING;
+	goto config_undo;
+    }
+
+    link->dev = &lp->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    rev = check_sig(link);
+    name = "???";
+    if (rev > 0)
+	switch (rev >> 4) {
+	case 3: name = "92"; break;
+	case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
+	case 5: name = "95"; break;
+	case 7: name = "100"; break;
+	case 8: name = "100-FD"; break;
+	}
+    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
+	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
+	   dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    if (rev > 0) {
+	u_long mir, mcr, mii;
+	ioaddr_t ioaddr = dev->base_addr;
+	SMC_SELECT_BANK(0);
+	mir = inw(ioaddr + MEMINFO) & 0xff;
+	if (mir == 0xff) mir++;
+	/* Get scale factor for memory size */
+	mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
+	mir *= 128 * (1<<((mcr >> 9) & 7));
+	if (mir & 0x3ff)
+	    printk(KERN_INFO "  %lu byte", mir);
+	else
+	    printk(KERN_INFO "  %lu kb", mir>>10);
+	SMC_SELECT_BANK(1);
+	mii = inw(ioaddr + CONFIG) & CFG_MII_SELECT;
+	printk(" buffer, %s xcvr\n", mii ? "MII" : if_names[dev->if_port]);
+    }
+    
+    return;
+    
+config_undo:
+    unregister_netdev(dev);
+config_failed:			/* CS_EXIT_TEST() calls jump to here... */
+    smc91c92_release((u_long)link);
+    
+} /* smc91c92_config */
+
+/*======================================================================
+
+    After a card is removed, smc91c92_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void smc91c92_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    struct net_device *dev = link->priv;
+
+    DEBUG(0, "smc91c92_release(0x%p)\n", link);
+    
+    if (link->open) {
+	DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",
+	      dev->name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if (link->win) {
+	struct smc_private *lp = dev->priv;
+	iounmap(lp->base);
+	CardServices(ReleaseWindow, link->win);
+    }
+    
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* smc91c92_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int smc91c92_event(event_t event, int priority,
+			  event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+    
+    DEBUG(1, "smc91c92_event(0x%06x)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    dev->tbusy = 1;
+	    dev->start = 0;
+	    link->release.expires = jiffies + HZ/20;
+	    link->state |= DEV_RELEASE_PENDING;
+	    add_timer(&link->release);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT;
+	smc91c92_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open) {
+		dev->tbusy = 1; dev->start = 0;
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    struct smc_private *lp = dev->priv;
+	    if ((lp->manfid == MANFID_MEGAHERTZ) &&
+		(lp->cardid == PRODID_MEGAHERTZ_EM3288))
+		mhz_3288_power(link);
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (lp->manfid == MANFID_MOTOROLA)
+		mot_config(link);
+	    if ((lp->manfid == MANFID_OSITECH) &&
+		(lp->cardid != PRODID_OSITECH_SEVEN)) {
+		/* Power up the card and enable interrupts */
+		set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
+		set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
+	    }
+	    if (link->open) {
+		smc_reset(dev);
+		dev->tbusy = 0;	dev->start = 1;
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* smc91c92_event */
+
+/*======================================================================
+  
+    The driver core code, most of which should be common with a
+    non-PCMCIA implementation.
+    
+======================================================================*/
+
+#ifdef PCMCIA_DEBUG
+static void smc_dump(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short i, w, save;
+    save = inw(ioaddr + BANK_SELECT);
+    for (w = 0; w < 4; w++) {
+	SMC_SELECT_BANK(w);
+	printk(KERN_DEBUG "bank %d: ", w);
+	for (i = 0; i < 14; i += 2)
+	    printk(" %04x", inw(ioaddr + i));
+	printk("\n");
+    }
+    outw(save, ioaddr + BANK_SELECT);
+}
+#endif
+
+static int smc91c92_open(struct net_device *dev)
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    dev_link_t *link;
+
+#ifdef PCMCIA_DEBUG
+    DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",
+	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
+    if (pc_debug > 1) smc_dump(dev);
+#endif
+    
+    /* Check that the PCMCIA card is still here. */
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    /* Physical device present signature. */
+    if (!DEV_OK(link))
+	return -ENODEV;
+    if (check_sig(link) < 0) {
+	printk("smc91c92_cs: Yikes!  Bad chip signature!\n");
+	return -ENODEV;
+    }
+    link->open++;
+    MOD_INC_USE_COUNT;
+    
+    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    lp->saved_skb = 0;
+    lp->packets_waiting = 0;
+    
+    smc_reset(dev);
+    lp->media.function = &media_check;
+    lp->media.data = (u_long)dev;
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+    
+    return 0;
+} /* smc91c92_open */
+
+/*====================================================================*/
+
+static int smc91c92_close(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    dev_link_t *link;
+
+    DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
+	  dev->name, inw(ioaddr + BANK_SELECT));
+    
+    dev->tbusy = 1;
+    dev->start = 0;
+    
+    /* Shut off all interrupts, and turn off the Tx and Rx sections.
+       Don't bother to check for chip present. */
+    SMC_SELECT_BANK( 2 );	/* Nominally paranoia, but do no assume... */
+    outw(0, ioaddr + INTERRUPT);
+    SMC_SELECT_BANK( 0 );
+    mask_bits(0xff00, ioaddr + RCR);
+    mask_bits(0xff00, ioaddr + TCR);
+    
+    /* Put the chip into power-down mode. */
+    SMC_SELECT_BANK( 1 );
+    outw(CTL_POWERDOWN, ioaddr + CONTROL  );
+    
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (link == NULL)
+	return -ENODEV;
+    
+    link->open--; dev->start = 0;
+    del_timer(&((struct smc_private *)dev->priv)->media);
+    if (link->state & DEV_STALE_CONFIG) {
+	link->release.expires = jiffies + HZ/20;
+	link->state |= DEV_RELEASE_PENDING;
+	add_timer(&link->release);
+    }
+    
+    MOD_DEC_USE_COUNT;
+    
+    return 0;
+} /* smc91c92_close */
+
+/*======================================================================
+
+   Transfer a packet to the hardware and trigger the packet send.
+   This may be called at either from either the Tx queue code
+   or the interrupt handler.
+   
+======================================================================*/
+
+static void smc_hardware_send_packet( struct net_device * dev )
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    struct sk_buff *skb = lp->saved_skb;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned char packet_no;
+    
+    if ( !skb ) {
+	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
+	return;
+    }
+    
+    /* There should be a packet slot waiting. */
+    packet_no = inw(ioaddr + PNR_ARR) >> 8;
+    if ( packet_no & 0x80 ) {
+	/* If not, there is a hardware problem!  Likely an ejected card. */
+	printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
+	       " failed, status %#2.2x.\n", dev->name, packet_no);
+	dev_kfree_skb (skb);
+	lp->saved_skb = NULL;
+	dev->tbusy = 0;
+	return;
+    }
+    
+    lp->stats.tx_bytes += skb->len;
+    /* The card should use the just-allocated buffer. */
+    outw( packet_no, ioaddr + PNR_ARR );
+    /* point to the beginning of the packet */
+    outw( PTR_AUTOINC , ioaddr + POINTER );
+    
+    /* Send the packet length ( +6 for status, length and ctl byte )
+       and the status word ( set to zeros ). */
+    {
+	unsigned char *buf = skb->data;
+	int length = skb->len;	/* The chip will pad to ethernet min length. */
+
+	DEBUG(2, "%s: Trying to xmit packet of length %d.\n",
+	      dev->name, length);
+	
+#ifdef USE_32_BIT
+	outl((length+6) << 16, ioaddr + DATA_1);
+	if (length & 0x2) {
+	    outsl(ioaddr + DATA_1, buf,  length >> 2 );
+	    outw( *((uint16 *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
+	} else
+	    outsl(ioaddr + DATA_1, buf,  length >> 2 );
+#else
+	/* send the packet length: +6 for status words, length, and ctl */
+	outw( 0, ioaddr + DATA_1 );
+	outw(length + 6, ioaddr + DATA_1 );
+	outsw(ioaddr + DATA_1 , buf, length >> 1);
+#endif
+	
+	/* The odd last byte, if there is one, goes in the control word. */
+	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1 );
+    }
+    
+    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
+    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
+	 (inw(ioaddr + INTERRUPT) & 0xff00),
+	 ioaddr + INTERRUPT);
+    
+    /* The chip does the rest of the work. */
+    outw( MC_ENQUEUE , ioaddr + MMU_CMD );
+    
+    lp->saved_skb = NULL;
+    dev_kfree_skb (skb);
+    dev->trans_start = jiffies;
+    dev->tbusy = 0;
+    return;
+}
+
+/*====================================================================*/
+
+static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned short num_pages;
+    short time_out, ir;
+    
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+	int tickssofar = jiffies - dev->trans_start;
+	if (tickssofar < TX_TIMEOUT)
+	    return 1;
+	printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
+	       "Tx_status %2.2x status %4.4x.\n",
+	       dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
+	lp->stats.tx_errors++;
+	smc_reset(dev);
+	dev->trans_start = jiffies;
+	dev->tbusy = 0;
+	lp->saved_skb = NULL;
+    }
+
+    DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
+	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
+    
+    /* Avoid timer-based retransmission conflicts. */
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+	printk(KERN_ERR "%s: transmitter access conflict.\n", dev->name);
+	return 1;
+    }
+    
+    if ( lp->saved_skb) {
+	/* THIS SHOULD NEVER HAPPEN. */
+	lp->stats.tx_aborted_errors++;
+	printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
+	       dev->name);
+	return 1;
+    }
+    lp->saved_skb = skb;
+    
+    num_pages = skb->len >> 8;
+    
+    if (num_pages > 7) {
+	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
+	dev_kfree_skb (skb);
+	lp->saved_skb = NULL;
+	lp->stats.tx_dropped++;
+	return 0;		/* Do not re-queue this packet. */
+    }
+    /* A packet is now waiting. */
+    lp->packets_waiting++;
+    
+    SMC_SELECT_BANK( 2 );	/* Paranoia, we should always be in window 2 */
+    
+    /* Allocate the memory; send the packet now if we win. */
+    outw( MC_ALLOC | num_pages, ioaddr + MMU_CMD );
+    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
+	ir = inw(ioaddr+INTERRUPT);
+	if (ir & IM_ALLOC_INT) {
+	    /* Acknowledge the interrupt, send the packet. */
+	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
+	    smc_hardware_send_packet(dev);	/* Send the packet now.. */
+	    return 0;
+	}
+    }
+    
+    /* Otherwise defer until the Tx-space-allocated interrupt. */
+    DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
+    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
+    
+    return 0;
+}
+
+/*======================================================================
+
+    Handle a Tx anomolous event.  Entered while in Window 2.
+    
+======================================================================*/
+
+static void smc_tx_err( struct net_device * dev )
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
+    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
+    int tx_status;
+    
+    /* select this as the packet to read from */
+    outw( packet_no, ioaddr + PNR_ARR );
+    
+    /* read the first word from this packet */
+    outw( PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER );
+    
+    tx_status = inw(ioaddr + DATA_1);
+
+    lp->stats.tx_errors++;
+    if (tx_status & TS_LOSTCAR) lp->stats.tx_carrier_errors++;
+    if (tx_status & TS_LATCOL)  lp->stats.tx_window_errors++;
+    if (tx_status & TS_16COL) {
+	lp->stats.tx_aborted_errors++;
+	lp->tx_err++;
+    }
+    
+    if ( tx_status & TS_SUCCESS ) {
+	printk(KERN_NOTICE "%s: Successful packet caused error "
+	       "interrupt?\n", dev->name);
+    }
+    /* re-enable transmit */
+    SMC_SELECT_BANK( 0 );
+    outw( inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    SMC_SELECT_BANK( 2 );
+    
+    outw( MC_FREEPKT, ioaddr + MMU_CMD ); 	/* Free the packet memory. */
+    
+    /* one less packet waiting for me */
+    lp->packets_waiting--;
+    
+    outw( saved_packet, ioaddr + PNR_ARR );
+    return;
+}
+
+/*====================================================================*/
+
+static void smc_eph_irq(struct net_device *dev)
+{
+    struct smc_private *lp = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned short card_stats, ephs;
+    
+    SMC_SELECT_BANK(0);
+    ephs = inw(ioaddr + EPH);
+    DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
+	  " %4.4x.\n", dev->name, ephs);
+    /* Could be a counter roll-over warning: update stats. */
+    card_stats = inw( ioaddr + COUNTER );
+    /* single collisions */
+    lp->stats.collisions += card_stats & 0xF;
+    card_stats >>= 4;
+    /* multiple collisions */
+    lp->stats.collisions += card_stats & 0xF;
+#if 0 		/* These are for when linux supports these statistics */
+    card_stats >>= 4;			/* deferred */
+    card_stats >>= 4;			/* excess deferred */
+#endif
+    /* If we had a transmit error we must re-enable the transmitter. */
+    outw( inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+
+    /* Clear a link error interrupt. */
+    SMC_SELECT_BANK(1);
+    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
+    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
+	 ioaddr + CONTROL);
+    SMC_SELECT_BANK(2);
+}
+
+/*====================================================================*/
+    
+static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct net_device *dev = dev_id;
+    struct smc_private *lp;
+    ioaddr_t ioaddr;
+    u_short saved_bank, saved_pointer, mask, status;
+    char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
+
+    if ((dev == NULL) || !dev->start)
+	return;
+    ioaddr = dev->base_addr;
+    
+#ifdef PCMCIA_DEBUG
+    if (dev->interrupt) {
+	printk(KERN_ERR "%s: re-entering the interrupt handler.\n",
+	       dev->name);
+	return;
+    }
+    dev->interrupt = 1;
+
+    DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
+	  irq, ioaddr);
+#endif
+    
+    lp = (struct smc_private *)dev->priv;
+    lp->watchdog = 0;
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    if ((saved_bank & 0xff00) != 0x3300) {
+	/* The device does not exist -- the card could be off-line, or
+	   maybe it has been ejected. */
+#ifdef PCMCIA_DEBUG
+	if (dev->start)
+	    DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
+		  "/ejected device.\n", dev->name, irq);
+	dev->interrupt = 0;
+#endif
+	goto irq_done;
+    }
+    
+    SMC_SELECT_BANK(2);
+    saved_pointer = inw(ioaddr + POINTER);
+    mask = inw(ioaddr + INTERRUPT) >> 8;
+    /* clear all interrupts */
+    outw( 0, ioaddr + INTERRUPT );
+    
+    do { /* read the status flag, and mask it */
+	status = inw(ioaddr + INTERRUPT) & 0xff;
+	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
+	      status, mask);
+	if ((status & mask) == 0)
+	    break;
+	
+	if (status & IM_RCV_INT) {
+	    /* Got a packet(s). */
+	    smc_rx(dev);
+	    lp->last_rx = jiffies;
+	}
+	if (status & IM_TX_INT) {
+	    smc_tx_err(dev);
+	    outw(IM_TX_INT, ioaddr + INTERRUPT);
+	}
+	status &= mask;
+	if (status & IM_TX_EMPTY_INT) {
+	    outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
+	    mask &= ~IM_TX_EMPTY_INT;
+	    lp->stats.tx_packets += lp->packets_waiting;
+	    lp->packets_waiting = 0;
+	}
+	if (status & IM_ALLOC_INT) {
+	    /* Clear this interrupt so it doesn't happen again */
+	    mask &= ~IM_ALLOC_INT;
+	    
+	    smc_hardware_send_packet(dev);
+	    
+	    /* enable xmit interrupts based on this */
+	    mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
+	    
+	    /* and let the card send more packets to me */
+	    mark_bh( NET_BH );
+	}
+	if (status & IM_RX_OVRN_INT) {
+	    lp->stats.rx_errors++;
+	    lp->stats.rx_fifo_errors++;		
+	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
+	}
+	if (status & IM_EPH_INT)
+	    smc_eph_irq(dev);
+    } while ( --bogus_cnt);
+
+    DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
+	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
+    
+    /* restore state register */
+    outw((mask<<8), ioaddr + INTERRUPT);
+    outw(saved_pointer, ioaddr + POINTER);
+    SMC_SELECT_BANK( saved_bank );
+
+#ifdef PCMCIA_DEBUG
+    dev->interrupt = 0;
+    DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
+#endif
+
+irq_done:
+    
+    if ((lp->manfid == MANFID_OSITECH) &&
+	(lp->cardid != PRODID_OSITECH_SEVEN)) {
+	/* Retrigger interrupt if needed */
+	mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
+	set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
+    }
+    if (lp->manfid == MANFID_MOTOROLA) {
+	u_char cor;
+	cor = readb(lp->base + MOT_UART + CISREG_COR);
+	writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_UART + CISREG_COR);
+	writeb(cor, lp->base + MOT_UART + CISREG_COR);
+	cor = readb(lp->base + MOT_LAN + CISREG_COR);
+	writeb(cor & ~COR_IREQ_ENA, lp->base + MOT_LAN + CISREG_COR);
+	writeb(cor, lp->base + MOT_LAN + CISREG_COR);
+    }
+#ifdef DOES_NOT_WORK
+    if (lp->base != NULL) { /* Megahertz MFC's */
+	readb(lp->base+MEGAHERTZ_ISR);
+	readb(lp->base+MEGAHERTZ_ISR);
+    }
+#endif
+}
+
+/*====================================================================*/
+
+static void smc_rx(struct net_device *dev)
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int rx_status;
+    int packet_length;	/* Caution: not frame length, rather words
+			   to transfer from the chip. */
+    
+    /* Assertion: we are in Window 2. */
+    
+    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
+	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
+	       dev->name);
+	return;
+    }
+    
+    /*  Reset the read pointer, and read the status and packet length. */
+    outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );
+    rx_status = inw(ioaddr + DATA_1);
+    packet_length = inw(ioaddr + DATA_1) & 0x07ff;
+
+    DEBUG(2, "%s: Receive status %4.4x length %d.\n",
+	  dev->name, rx_status, packet_length);
+    
+    if ( !(rx_status & RS_ERRORS )) {		
+	/* do stuff to make a new packet */
+	struct sk_buff *skb;
+	
+	/* Note: packet_length adds 5 or 6 extra bytes here! */
+	skb = dev_alloc_skb(packet_length+2);
+	
+	if ( skb == NULL ) {
+	    DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
+	    lp->stats.rx_dropped++;
+	    outw( MC_RELEASE, ioaddr + MMU_CMD );
+	    return;
+	}
+	
+	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
+	skb_reserve(skb, 2);
+	insw(ioaddr+DATA_1, skb_put(skb, packet_length),
+		(packet_length+1)>>1);
+	skb->protocol = eth_type_trans(skb, dev);
+	
+	skb->dev = dev;
+	netif_rx(skb);
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes += skb->len;
+	if (rx_status & RS_MULTICAST)
+	    lp->stats.multicast++;
+    } else {
+	/* error ... */
+	lp->stats.rx_errors++;
+	
+	if (rx_status & RS_ALGNERR)  lp->stats.rx_frame_errors++;
+	if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
+	    lp->stats.rx_length_errors++;
+	if (rx_status & RS_BADCRC)	lp->stats.rx_crc_errors++;
+    }
+    /* Let the MMU free the memory of this packet. */
+    outw(MC_RELEASE, ioaddr + MMU_CMD);
+    
+    return;
+}
+
+/*====================================================================*/
+
+static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    /* Nothing to update - the 91c92 is a pretty primative chip. */
+    return &lp->stats;
+}
+
+/*======================================================================
+
+    Compute the AUTODIN polynomial "CRC32" for ethernet packets.
+
+======================================================================*/
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+
+static unsigned ether_crc(int length, unsigned char *data)
+{
+    int crc = 0xffffffff;	/* Initial value. */
+    
+    while (--length >= 0) {
+	unsigned char current_octet = *data++;
+	int bit;
+	for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
+	    crc = (crc << 1) ^
+		((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+	}
+    }
+    /* The hash index is the either the upper or lower bits of the CRC, so
+     * we return the entire CRC.
+     */
+    return crc;
+}
+
+/*======================================================================
+  
+    Calculate values for the hardware multicast filter hash table.
+    
+======================================================================*/
+
+static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
+			       unsigned char *multicast_table)
+{
+    struct dev_mc_list	*mc_addr;
+    
+    for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
+	unsigned int position = ether_crc(6, mc_addr->dmi_addr);
+#ifndef final_version		/* Verify multicast address. */
+	if ( (mc_addr->dmi_addr[0] & 1) == 0)
+	    continue;
+#endif
+	multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
+    }
+}
+
+/*======================================================================
+  
+    Set the receive mode.
+    
+    This routine is used by both the protocol level to notify us of
+    promiscuous/multicast mode changes, and by the open/reset code to
+    initialize the Rx registers.  We always set the multicast list and
+    leave the receiver running.
+    
+======================================================================*/
+
+static void set_rx_mode(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned int multicast_table[ 2 ] = { 0, };
+    long flags;
+    uint16 rx_cfg_setting;
+    
+    if (dev->flags & IFF_PROMISC) {
+	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
+	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
+    } else if (dev->flags & IFF_ALLMULTI)
+	rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
+    else {
+	if (dev->mc_count)  {
+	    fill_multicast_tbl(dev->mc_count, dev->mc_list,
+			       (unsigned char *)multicast_table);
+	}
+	rx_cfg_setting = RxStripCRC | RxEnable;
+    }
+    
+    /* Load MC table and Rx setting into the chip without interrupts. */
+    save_flags(flags);
+    cli();
+    SMC_SELECT_BANK( 3 );
+    outl(multicast_table[0], ioaddr + MULTICAST0);
+    outl(multicast_table[1], ioaddr + MULTICAST4);
+    SMC_SELECT_BANK(0);
+    outw(rx_cfg_setting, ioaddr + RCR);
+    SMC_SELECT_BANK(2);
+    restore_flags(flags);
+    
+    return;
+}
+
+/*======================================================================
+
+    Senses when a card's config changes. Here, it's coax or TP.
+ 
+======================================================================*/
+
+static int s9k_config(struct net_device *dev, struct ifmap *map)
+{
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+	if (map->port <= 2) {
+	    dev->if_port = map->port;
+	    printk(KERN_INFO "%s: switched to %s port\n",
+		   dev->name, if_names[dev->if_port]);
+	} else
+	    return -EINVAL;
+    }
+    smc_reset(dev);
+    return 0;
+}
+
+/*======================================================================
+
+    Reset the chip, reloading every register that might be corrupted.
+
+======================================================================*/
+
+/*
+  Set transceiver type, perhaps to something other than what the user
+  specified in dev->if_port.
+*/
+static void smc_set_xcvr(struct net_device *dev, int if_port)
+{
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short saved_bank;
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    SMC_SELECT_BANK(1);
+    if (if_port == 2) {
+	outw(lp->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
+	if ((lp->manfid == MANFID_OSITECH) &&
+	    (lp->cardid != PRODID_OSITECH_SEVEN))
+	    set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
+	lp->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
+    } else {
+	outw(lp->cfg, ioaddr + CONFIG);
+	if ((lp->manfid == MANFID_OSITECH) &&
+	    (lp->cardid != PRODID_OSITECH_SEVEN))
+	    mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
+	lp->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
+    }
+    SMC_SELECT_BANK(saved_bank);
+}
+
+static void smc_reset(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *lp = dev->priv;
+    int i;
+
+    DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
+    
+    /* The first interaction must be a write to bring the chip out
+       of sleep mode. */
+    SMC_SELECT_BANK( 0 );
+    /* Reset the chip. */
+    outw( RCR_SOFTRESET, ioaddr + RCR );
+    udelay(10);
+    
+    /* Clear the transmit and receive configuration registers. */
+    outw( RCR_CLEAR, ioaddr + RCR );
+    outw( TCR_CLEAR, ioaddr + TCR );
+    
+    /* Set the Window 1 control, configuration and station addr registers.
+       No point in writing the I/O base register ;-> */
+    SMC_SELECT_BANK(1);
+    /* Automatically release succesfully transmitted packets,
+       Accept link errors, counter and Tx error interrupts. */
+    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
+	 ioaddr + CONTROL);
+    lp->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
+    lp->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC |
+	(lp->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0);
+    smc_set_xcvr(dev, dev->if_port);
+    if ((lp->manfid == MANFID_OSITECH) &&
+	(lp->cardid != PRODID_OSITECH_SEVEN))
+	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
+	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
+	     ioaddr - 0x10 + OSITECH_AUI_PWR);
+    
+    /* Fill in the physical address.  The databook is wrong about the order! */
+    for (i = 0; i < 6; i += 2)
+	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
+	     ioaddr + ADDR0 + i);
+    
+    /* Reset the MMU */
+    SMC_SELECT_BANK(2);
+    outw(MC_RESET, ioaddr + MMU_CMD );
+    outw(0, ioaddr + INTERRUPT );
+    
+    /* Re-enable the chip. */
+    SMC_SELECT_BANK(0);
+    outw(((lp->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
+	 TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR);
+    set_rx_mode(dev);
+
+    /* Enable interrupts. */
+    SMC_SELECT_BANK( 2 );
+    outw( (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
+	  ioaddr + INTERRUPT );
+}
+
+/*======================================================================
+
+    Media selection timer routine
+    
+======================================================================*/
+
+static void media_check(u_long arg)
+{
+    struct net_device *dev = (struct net_device *)(arg);
+    struct smc_private *lp = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short i, media, saved_bank;
+
+    if (dev->start == 0) goto reschedule;
+    
+    lp = (struct smc_private *)dev->priv;
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    SMC_SELECT_BANK(2);
+    i = inw(ioaddr + INTERRUPT);
+    SMC_SELECT_BANK(0);
+    media = inw(ioaddr + EPH) & EPH_LINK_OK;
+    SMC_SELECT_BANK(1);
+    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
+    SMC_SELECT_BANK(saved_bank);
+    
+    /* Check for pending interrupt with watchdog flag set: with
+       this, we can limp along even if the interrupt is blocked */
+    if (lp->watchdog++ && ((i>>8) & i)) {
+	if (!lp->fast_poll)
+	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+	smc_interrupt(dev->irq, dev, NULL);
+	lp->fast_poll = HZ;
+    }
+    if (lp->fast_poll) {
+	lp->fast_poll--;
+	lp->media.expires = jiffies + 1;
+	add_timer(&lp->media);
+	return;
+    }
+
+    if (lp->cfg & CFG_MII_SELECT)
+	goto reschedule;
+
+    /* Ignore collisions unless we've had no rx's recently */
+    if (jiffies - lp->last_rx > HZ) {
+	if (lp->tx_err || (lp->media_status & EPH_16COL))
+	    media |= EPH_16COL;
+    }
+    lp->tx_err = 0;
+
+    if (media != lp->media_status) {
+	if ((media & lp->media_status & 1) &&
+	    ((lp->media_status ^ media) & EPH_LINK_OK))
+	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
+		   (lp->media_status & EPH_LINK_OK ? "lost" : "found"));
+	else if ((media & lp->media_status & 2) &&
+		 ((lp->media_status ^ media) & EPH_16COL))
+	    printk(KERN_INFO "%s: coax cable %s\n", dev->name,
+		   (media & EPH_16COL ? "problem" : "ok"));
+	if (dev->if_port == 0) {
+	    if (media & 1) {
+		if (media & EPH_LINK_OK)
+		    printk(KERN_INFO "%s: flipped to 10baseT\n",
+			   dev->name);
+		else
+		    smc_set_xcvr(dev, 2);
+	    } else {
+		if (media & EPH_16COL)
+		    smc_set_xcvr(dev, 1);
+		else
+		    printk(KERN_INFO "%s: flipped to 10base2\n",
+			   dev->name);
+	    }
+	}
+	lp->media_status = media;
+    }
+    
+reschedule:
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+}
+
+/*====================================================================*/
+
+static int __init init_smc91c92_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_ERR
+	       "smc91c92_cs: Card Services release does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &smc91c92_attach, &smc91c92_detach);
+    return 0;
+}
+
+static void __exit exit_smc91c92_cs(void)
+{
+    DEBUG(0, "smc91c92_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	smc91c92_detach(dev_list);
+}
+
+module_init(init_smc91c92_cs);
+module_exit(exit_smc91c92_cs);
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h
--- v2.3.22/linux/drivers/net/pcmcia/wavelan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/wavelan.h	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,383 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganization and extension of the driver.
+ * Original copyright follow. See wavelan_cs.h for details.
+ *
+ * This file contain the declarations of the Wavelan hardware. Note that
+ * the Pcmcia Wavelan include a i82593 controler (see definitions in
+ * file i82593.h).
+ *
+ * The main difference between the pcmcia hardware and the ISA one is
+ * the Ethernet Controler (i82593 instead of i82586). The i82593 allow
+ * only one send buffer. The PSA (Parameter Storage Area : EEprom for
+ * permanent storage of various info) is memory mapped, but not the
+ * MMI (Modem Management Interface).
+ */
+
+/*
+ * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: 
+ *   An Ethernet-like radio transceiver controlled by an Intel 82593
+ *   coprocessor.
+ *
+ *
+ ****************************************************************************
+ *   Copyright 1995
+ *   Anthony D. Joseph
+ *   Massachusetts Institute of Technology
+ *
+ *   Permission to use, copy, modify, and distribute this program
+ *   for any purpose and without fee is hereby granted, provided
+ *   that this copyright and permission notice appear on all copies
+ *   and supporting documentation, the name of M.I.T. not be used
+ *   in advertising or publicity pertaining to distribution of the
+ *   program without specific prior permission, and notice be given
+ *   in supporting documentation that copying and distribution is
+ *   by permission of M.I.T.  M.I.T. makes no representations about
+ *   the suitability of this software for any purpose.  It is pro-
+ *   vided "as is" without express or implied warranty.         
+ ****************************************************************************
+ *
+ *
+ * Credits:
+ *     Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for
+ *       providing extremely useful information about WaveLAN PCMCIA hardware
+ *
+ *     This driver is based upon several other drivers, in particular:
+ *       David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
+ *       Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
+ *	 Anders Klemets' PCMCIA WaveLAN adapter driver
+ *       Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
+ */
+
+#ifndef _WAVELAN_H
+#define	_WAVELAN_H
+
+/************************** MAGIC NUMBERS ***************************/
+
+/* The detection of the wavelan card is made by reading the MAC address
+ * from the card and checking it. If you have a non AT&T product (OEM,
+ * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this
+ * part to accomodate your hardware...
+ */
+const unsigned char	MAC_ADDRESSES[][3] =
+{
+  { 0x08, 0x00, 0x0E },		/* AT&T Wavelan (standard) & DEC RoamAbout */
+  { 0x08, 0x00, 0x6A },		/* AT&T Wavelan (alternate) */
+  { 0x00, 0x00, 0xE1 },		/* Hitachi Wavelan */
+  { 0x00, 0x60, 0x1D }		/* Lucent Wavelan (another one) */
+  /* Add your card here and send me the patch ! */
+};
+
+/*
+ * Constants used to convert channels to frequencies
+ */
+
+/* Frequency available in the 2.0 modem, in units of 250 kHz
+ * (as read in the offset register of the dac area).
+ * Used to map channel numbers used by `wfreqsel' to frequencies
+ */
+const short	channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
+				    0xD0, 0xF0, 0xF8, 0x150 };
+
+/* Frequencies of the 1.0 modem (fixed frequencies).
+ * Use to map the PSA `subband' to a frequency
+ * Note : all frequencies apart from the first one need to be multiplied by 10
+ */
+const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+
+/*************************** PC INTERFACE ****************************/
+
+/* WaveLAN host interface definitions */
+
+#define	LCCR(base)	(base)		/* LAN Controller Command Register */
+#define	LCSR(base)	(base)		/* LAN Controller Status Register */
+#define	HACR(base)	(base+0x1)	/* Host Adapter Command Register */
+#define	HASR(base)	(base+0x1)	/* Host Adapter Status Register */
+#define PIORL(base)	(base+0x2)	/* Program I/O Register Low */
+#define RPLL(base)	(base+0x2)	/* Receive Pointer Latched Low */
+#define PIORH(base)	(base+0x3)	/* Program I/O Register High */
+#define RPLH(base)	(base+0x3)	/* Receive Pointer Latched High */
+#define PIOP(base)	(base+0x4)	/* Program I/O Port */
+#define MMR(base)	(base+0x6)	/* MMI Address Register */
+#define MMD(base)	(base+0x7)	/* MMI Data Register */
+
+/* Host Adaptor Command Register bit definitions */
+
+#define HACR_LOF	  (1 << 3)	/* Lock Out Flag, toggle every 250ms */
+#define HACR_PWR_STAT	  (1 << 4)	/* Power State, 1=active, 0=sleep */
+#define HACR_TX_DMA_RESET (1 << 5)	/* Reset transmit DMA ptr on high */
+#define HACR_RX_DMA_RESET (1 << 6)	/* Reset receive DMA ptr on high */
+#define HACR_ROM_WEN	  (1 << 7)	/* EEPROM write enabled when true */
+
+#define HACR_RESET              (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET)
+#define	HACR_DEFAULT		(HACR_PWR_STAT)
+
+/* Host Adapter Status Register bit definitions */
+
+#define HASR_MMI_BUSY	(1 << 2)	/* MMI is busy when true */
+#define HASR_LOF	(1 << 3)	/* Lock out flag status */
+#define HASR_NO_CLK	(1 << 4)	/* active when modem not connected */
+
+/* Miscellaneous bit definitions */
+
+#define PIORH_SEL_TX	(1 << 5)	/* PIOR points to 0=rx/1=tx buffer */
+#define MMR_MMI_WR	(1 << 0)	/* Next MMI cycle is 0=read, 1=write */
+#define PIORH_MASK	0x1f		/* only low 5 bits are significant */
+#define RPLH_MASK	0x1f		/* only low 5 bits are significant */
+#define MMI_ADDR_MASK	0x7e		/* Bits 1-6 of MMR are significant */
+
+/* Attribute Memory map */
+
+#define CIS_ADDR	0x0000		/* Card Information Status Register */
+#define PSA_ADDR	0x0e00		/* Parameter Storage Area address */
+#define EEPROM_ADDR	0x1000		/* EEPROM address (unused ?) */
+#define COR_ADDR	0x4000		/* Configuration Option Register */
+
+/* Configuration Option Register bit definitions */
+
+#define COR_CONFIG	(1 << 0)	/* Config Index, 0 when unconfigured */
+#define COR_SW_RESET	(1 << 7)	/* Software Reset on true */
+#define COR_LEVEL_IRQ	(1 << 6)	/* Level IRQ */
+
+/* Local Memory map */
+
+#define RX_BASE		0x0000		/* Receive memory, 8 kB */
+#define TX_BASE		0x2000		/* Transmit memory, 2 kB */
+#define UNUSED_BASE	0x2800		/* Unused, 22 kB */
+#define RX_SIZE		(TX_BASE-RX_BASE)	/* Size of receive area */
+#define RX_SIZE_SHIFT	6		/* Bits to shift in stop register */
+
+#define TRUE  1
+#define FALSE 0
+
+#define MOD_ENAL 1
+#define MOD_PROM 2
+
+/* Size of a MAC address */
+#define WAVELAN_ADDR_SIZE	6
+
+/* Maximum size of Wavelan packet */
+#define WAVELAN_MTU	1500
+
+#define	MAXDATAZ		(6 + 6 + 2 + WAVELAN_MTU)
+
+/********************** PARAMETER STORAGE AREA **********************/
+
+/*
+ * Parameter Storage Area (PSA).
+ */
+typedef struct psa_t	psa_t;
+struct psa_t
+{
+  /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */
+  unsigned char	psa_io_base_addr_1;	/* [0x00] Base address 1 ??? */
+  unsigned char	psa_io_base_addr_2;	/* [0x01] Base address 2 */
+  unsigned char	psa_io_base_addr_3;	/* [0x02] Base address 3 */
+  unsigned char	psa_io_base_addr_4;	/* [0x03] Base address 4 */
+  unsigned char	psa_rem_boot_addr_1;	/* [0x04] Remote Boot Address 1 */
+  unsigned char	psa_rem_boot_addr_2;	/* [0x05] Remote Boot Address 2 */
+  unsigned char	psa_rem_boot_addr_3;	/* [0x06] Remote Boot Address 3 */
+  unsigned char	psa_holi_params;	/* [0x07] HOst Lan Interface (HOLI) Parameters */
+  unsigned char	psa_int_req_no;		/* [0x08] Interrupt Request Line */
+  unsigned char	psa_unused0[7];		/* [0x09-0x0F] unused */
+
+  unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x10-0x15] Universal (factory) MAC Address */
+  unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x16-1B] Local MAC Address */
+  unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
+#define		PSA_UNIVERSAL	0		/* Universal (factory) */
+#define		PSA_LOCAL	1		/* Local */
+  unsigned char	psa_comp_number;	/* [0x1D] Compatability Number: */
+#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
+#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
+#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
+#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz	*/
+#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
+  unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
+  unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
+#define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
+  unsigned char	psa_subband;		/* [0x20] Subband	*/
+#define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
+#define		PSA_SUBBAND_2425	1	/* 2425 MHz	*/
+#define		PSA_SUBBAND_2460	2	/* 2460 MHz	*/
+#define		PSA_SUBBAND_2484	3	/* 2484 MHz	*/
+#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	*/
+  unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
+  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay ??? (reserved) */
+  unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
+  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On Off */
+  unsigned char	psa_encryption_select;	/* [0x26] Encryption On Off */
+  unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
+  unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
+  unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
+  unsigned char	psa_nwid_prefix[2];	/* [0x38-0x39] Roaming domain */
+  unsigned char	psa_reserved[2];	/* [0x3A-0x3B] Reserved - fixed 00 */
+  unsigned char	psa_conf_status;	/* [0x3C] Conf Status, bit 0=1:config*/
+  unsigned char	psa_crc[2];		/* [0x3D] CRC-16 over PSA */
+  unsigned char	psa_crc_status;		/* [0x3F] CRC Valid Flag */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	PSA_SIZE	64
+
+/* Calculate offset of a field in the above structure
+ * Warning : only even addresses are used */
+#define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
+
+/******************** MODEM MANAGEMENT INTERFACE ********************/
+
+/*
+ * Modem Management Controller (MMC) write structure.
+ */
+typedef struct mmw_t	mmw_t;
+struct mmw_t
+{
+  unsigned char	mmw_encr_key[8];	/* encryption key */
+  unsigned char	mmw_encr_enable;	/* enable/disable encryption */
+#define	MMW_ENCR_ENABLE_MODE	0x02	/* Mode of security option */
+#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option */
+  unsigned char	mmw_unused0[1];		/* unused */
+  unsigned char	mmw_des_io_invert;	/* Encryption option */
+#define	MMW_DES_IO_INVERT_RES	0x0F	/* Reserved */
+#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* Control ??? (set to 0) */
+  unsigned char	mmw_unused1[5];		/* unused */
+  unsigned char	mmw_loopt_sel;		/* looptest selection */
+#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* disable NWID filtering */
+#define	MMW_LOOPT_SEL_INT	0x20	/* activate Attention Request */
+#define	MMW_LOOPT_SEL_LS	0x10	/* looptest w/o collision avoidance */
+#define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
+#define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
+#define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
+#define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
+  unsigned char	mmw_jabber_enable;	/* jabber timer enable */
+  /* Abort transmissions > 200 ms */
+  unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
+  /* 0 : signal level & qual updated for every new message, 1 : frozen */
+  unsigned char	mmw_anten_sel;		/* antenna selection */
+#define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
+#define	MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algo. enable */
+  unsigned char	mmw_ifs;		/* inter frame spacing */
+  /* min time between transmission in bit periods (.5 us) - bit 0 ignored */
+  unsigned char	mmw_mod_delay;	 	/* modem delay (synchro) */
+  unsigned char	mmw_jam_time;		/* jamming time (after collision) */
+  unsigned char	mmw_unused2[1];		/* unused */
+  unsigned char	mmw_thr_pre_set;	/* level threshold preset */
+  /* Discard all packet with signal < this value (4) */
+  unsigned char	mmw_decay_prm;		/* decay parameters */
+  unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
+  unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
+  /* Discard all packet with quality < this value (3) */
+  unsigned char	mmw_netw_id_l;		/* NWID low order byte */
+  unsigned char	mmw_netw_id_h;		/* NWID high order byte */
+  /* Network ID or Domain : create virtual net on the air */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
+  unsigned char	mmw_unused3[1];		/* unused */
+  unsigned char	mmw_fee_ctrl;		/* frequency eeprom control */
+#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions */
+#define	MMW_FEE_CTRL_DWLD	0x08	/* Download eeprom to mmc */
+#define	MMW_FEE_CTRL_CMD	0x07	/* EEprom commands : */
+#define	MMW_FEE_CTRL_READ	0x06	/* Read */
+#define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
+#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address */
+#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses */
+#define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
+#define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
+#define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
+#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers */
+#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write addr in protect register */
+#define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
+  /* Never issue this command (PRDS) : it's irreversible !!! */
+
+  unsigned char	mmw_fee_addr;		/* EEprom address */
+#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel */
+#define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
+#define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
+#define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
+#define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
+#define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
+
+  unsigned char	mmw_fee_data_l;		/* Write data to EEprom */
+  unsigned char	mmw_fee_data_h;		/* high octet */
+  unsigned char	mmw_ext_ant;		/* Setting for external antenna */
+#define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
+#define	MMW_EXT_ANT_POL		0x02	/* Polarity of the antenna */
+#define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
+#define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
+#define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	MMW_SIZE	37
+
+/* Calculate offset of a field in the above structure */
+#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
+
+/*
+ * Modem Management Controller (MMC) read structure.
+ */
+typedef struct mmr_t	mmr_t;
+struct mmr_t
+{
+  unsigned char	mmr_unused0[8];		/* unused */
+  unsigned char	mmr_des_status;		/* encryption status */
+  unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
+#define	MMR_DES_AVAIL_DES	0x55		/* DES available */
+#define	MMR_DES_AVAIL_AES	0x33		/* AES (AT&T) available */
+  unsigned char	mmr_des_io_invert;	/* des I/O invert register */
+  unsigned char	mmr_unused1[5];		/* unused */
+  unsigned char	mmr_dce_status;		/* DCE status */
+#define	MMR_DCE_STATUS_RX_BUSY		0x01	/* receiver busy */
+#define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
+#define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
+#define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
+#define MMR_DCE_STATUS			0x0F	/* mask to get the bits */
+  unsigned char	mmr_dsp_id;		/* DSP id (AA = Daedalus rev A) */
+  unsigned char	mmr_unused2[2];		/* unused */
+  unsigned char	mmr_correct_nwid_l;	/* # of correct NWID's rxd (low) */
+  unsigned char	mmr_correct_nwid_h;	/* # of correct NWID's rxd (high) */
+  /* Warning : Read high order octet first !!! */
+  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWID's rxd (low) */
+  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWID's rxd (high) */
+  unsigned char	mmr_thr_pre_set;	/* level threshold preset */
+#define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
+#define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
+  unsigned char	mmr_signal_lvl;		/* signal level */
+#define	MMR_SIGNAL_LVL		0x3F		/* signal level */
+#define	MMR_SIGNAL_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_silence_lvl;	/* silence level (noise) */
+#define	MMR_SILENCE_LVL		0x3F		/* silence level */
+#define	MMR_SILENCE_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_sgnl_qual;		/* signal quality */
+#define	MMR_SGNL_QUAL		0x0F		/* signal quality */
+#define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
+  unsigned char	mmr_netw_id_l;		/* NWID low order byte ??? */
+  unsigned char	mmr_unused3[3];		/* unused */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmr_fee_status;		/* Status of frequency eeprom */
+#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision id */
+#define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
+#define	MMR_FEE_STATUS_BUSY	0x04		/* EEprom busy */
+  unsigned char	mmr_unused4[1];		/* unused */
+  unsigned char	mmr_fee_data_l;		/* Read data from eeprom (low) */
+  unsigned char	mmr_fee_data_h;		/* Read data from eeprom (high) */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	MMR_SIZE	36
+
+/* Calculate offset of a field in the above structure */
+#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
+/* Make the two above structures one */
+typedef union mm_t
+{
+  struct mmw_t	w;	/* Write to the mmc */
+  struct mmr_t	r;	/* Read from the mmc */
+} mm_t;
+
+#endif /* _WAVELAN_H */
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,4856 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ * Original copyright follow. See wavelan_cs.h for details.
+ *
+ * This code is derived from Anthony D. Joseph's code and all the changes here
+ * are also under the original copyright below.
+ *
+ * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and
+ * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services
+ *
+ * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added
+ * critical code in the routine to initialize the Modem Management Controller.
+ *
+ * Thanks to Alan Cox and Bruce Janson for their advice.
+ *
+ *	-- Yunzhou Li (scip4166@nus.sg)
+ *
+#ifdef WAVELAN_ROAMING	
+ * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
+ * based on patch by Joe Finney from Lancaster University.
+#endif :-)
+ *
+ * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
+ * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
+ *
+ *   A non-shared memory PCMCIA ethernet driver for linux
+ *
+ * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu)
+ *
+ *
+ * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu)
+ *
+ * Apr 2 '98  made changes to bring the i82593 control/int handling in line
+ *             with offical specs...
+ *
+ ****************************************************************************
+ *   Copyright 1995
+ *   Anthony D. Joseph
+ *   Massachusetts Institute of Technology
+ *
+ *   Permission to use, copy, modify, and distribute this program
+ *   for any purpose and without fee is hereby granted, provided
+ *   that this copyright and permission notice appear on all copies
+ *   and supporting documentation, the name of M.I.T. not be used
+ *   in advertising or publicity pertaining to distribution of the
+ *   program without specific prior permission, and notice be given
+ *   in supporting documentation that copying and distribution is
+ *   by permission of M.I.T.  M.I.T. makes no representations about
+ *   the suitability of this software for any purpose.  It is pro-
+ *   vided "as is" without express or implied warranty.         
+ ****************************************************************************
+ *
+ */
+
+#include "wavelan_cs.h"		/* Private header */
+
+/************************* MISC SUBROUTINES **************************/
+/*
+ * Subroutines which won't fit in one of the following category
+ * (wavelan modem or i82593)
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for disabling interrupts.
+ */
+static inline unsigned long
+wv_splhi(void)
+{
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+
+  return(flags);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(unsigned long	flags)
+{
+  restore_flags(flags);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for reporting error to cardservices
+ */
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+#ifdef STRUCT_CHECK
+/*------------------------------------------------------------------*/
+/*
+ * Sanity routine to verify the sizes of the various WaveLAN interface
+ * structures.
+ */
+static char *
+wv_structuct_check(void)
+{
+#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
+
+  SC(psa_t, PSA_SIZE, "psa_t");
+  SC(mmw_t, MMW_SIZE, "mmw_t");
+  SC(mmr_t, MMR_SIZE, "mmr_t");
+
+#undef	SC
+
+  return((char *) NULL);
+} /* wv_structuct_check */
+#endif	/* STRUCT_CHECK */
+
+/******************* MODEM MANAGEMENT SUBROUTINES *******************/
+/*
+ * Usefull subroutines to manage the modem of the wavelan
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read from card's Host Adaptor Status Register.
+ */
+static inline u_char
+hasr_read(u_long	base)
+{
+  return(inb(HASR(base)));
+} /* hasr_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register.
+ */
+static inline void
+hacr_write(u_long	base,
+	   u_char	hacr)
+{
+  outb(hacr, HACR(base));
+} /* hacr_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register. Include a delay for
+ * those times when it is needed.
+ */
+static inline void
+hacr_write_slow(u_long	base,
+		u_char	hacr)
+{
+  hacr_write(base, hacr);
+  /* delay might only be needed sometimes */
+  udelay(1000L);
+} /* hacr_write_slow */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Parameter Storage Area from the WaveLAN card's memory
+ */
+static void
+psa_read(device *	dev,
+	 int		o,	/* offset in PSA */
+	 u_char *	b,	/* buffer to fill */
+	 int		n)	/* size to read */
+{
+  u_char *	ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1);
+
+  while(n-- > 0)
+    {
+      *b++ = readb(ptr);
+      /* Due to a lack of address decode pins, the WaveLAN PCMCIA card
+       * only supports reading even memory addresses. That means the
+       * increment here MUST be two.
+       * Because of that, we can't use memcpy_fromio()...
+       */
+      ptr += 2;
+    }
+} /* psa_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write the Paramter Storage Area to the WaveLAN card's memory
+ */
+static void
+psa_write(device *	dev,
+	  int		o,	/* Offset in psa */
+	  u_char *	b,	/* Buffer in memory */
+	  int		n)	/* Length of buffer */
+{
+  u_char *	ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1);
+  int		count = 0;
+  ioaddr_t	base = dev->base_addr;
+  /* As there seem to have no flag PSA_BUSY as in the ISA model, we are
+   * oblige to verify this address to know when the PSA is ready... */
+  volatile u_char *	verify = ((u_char *) dev->mem_start) + PSA_ADDR +
+    (psaoff(0, psa_comp_number) << 1);
+
+  /* Authorize writting to PSA */
+  hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
+
+  while(n-- > 0)
+    {
+      /* write to PSA */
+      writeb(*b++, ptr);
+      ptr += 2;
+
+      /* I don't have the spec, so I don't know what the correct
+       * sequence to write is. This hack seem to work for me... */
+      count = 0;
+      while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100))
+	udelay(1000);
+    }
+
+  /* Put the host interface back in standard state */
+  hacr_write(base, HACR_DEFAULT);
+} /* psa_write */
+
+#ifdef SET_PSA_CRC
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the PSA CRC
+ * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * NOTE: By specifying a length including the CRC position the
+ * returned value should be zero. (i.e. a correct checksum in the PSA)
+ *
+ * The Windows drivers don't use the CRC, but the AP and the PtP tool
+ * depend on it.
+ */
+static u_short
+psa_crc(unsigned char *	psa,	/* The PSA */
+	int		size)	/* Number of short for CRC */
+{
+  int		byte_cnt;	/* Loop on the PSA */
+  u_short	crc_bytes = 0;	/* Data in the PSA */
+  int		bit_cnt;	/* Loop on the bits of the short */
+
+  for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
+    {
+      crc_bytes ^= psa[byte_cnt];	/* Its an xor */
+
+      for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
+	{
+	  if(crc_bytes & 0x0001)
+	    crc_bytes = (crc_bytes >> 1) ^ 0xA001;
+	  else
+	    crc_bytes >>= 1 ;
+        }
+    }
+
+  return crc_bytes;
+} /* psa_crc */
+#endif	/* SET_PSA_CRC */
+
+/*------------------------------------------------------------------*/
+/*
+ * update the checksum field in the Wavelan's PSA
+ */
+static void
+update_psa_checksum(device *	dev)
+{
+#ifdef SET_PSA_CRC
+  psa_t		psa;
+  u_short	crc;
+
+  /* read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+  /* update the checksum */
+  crc = psa_crc((unsigned char *) &psa,
+		sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
+		- sizeof(psa.psa_crc_status));
+
+  psa.psa_crc[0] = crc & 0xFF;
+  psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+
+  /* Write it ! */
+  psa_write(dev, (char *)&psa.psa_crc - (char *)&psa,
+	    (unsigned char *)&psa.psa_crc, 2);
+
+#ifdef DEBUG_IOCTL_INFO
+  printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+          dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+
+  /* Check again (luxury !) */
+  crc = psa_crc((unsigned char *) &psa,
+		 sizeof(psa) - sizeof(psa.psa_crc_status));
+
+  if(crc != 0)
+    printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
+#endif /* DEBUG_IOCTL_INFO */
+#endif	/* SET_PSA_CRC */
+} /* update_psa_checksum */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write 1 byte to the MMC.
+ */
+static inline void
+mmc_out(u_long		base,
+	u_short		o,
+	u_char		d)
+{
+  /* Wait for MMC to go idle */
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+
+  outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base));
+  outb(d, MMD(base));
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to write bytes to the Modem Management Controller.
+ * We start by the end because it is the way it should be !
+ */
+static inline void
+mmc_write(u_long	base,
+	  u_char	o,
+	  u_char *	b,
+	  int		n)
+{
+  o += n;
+  b += n;
+
+  while(n-- > 0 )
+    mmc_out(base, --o, *(--b));
+} /* mmc_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read 1 byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory...
+ */
+static inline u_char
+mmc_in(u_long	base,
+       u_short	o)
+{
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+  outb(o << 1, MMR(base));		/* Set the read address */
+
+  outb(0, MMD(base));			/* Required dummy write */
+
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+  return (u_char) (inb(MMD(base)));	/* Now do the actual read */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read bytes from the Modem Management Controller.
+ * The implementation is complicated by a lack of address lines,
+ * which prevents decoding of the low-order bit.
+ * (code has just been moved in the above function)
+ * We start by the end because it is the way it should be !
+ */
+static inline void
+mmc_read(u_long		base,
+	 u_char		o,
+	 u_char *	b,
+	 int		n)
+{
+  o += n;
+  b += n;
+
+  while(n-- > 0)
+    *(--b) = mmc_in(base, --o);
+} /* mmc_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the type of encryption available...
+ */
+static inline int
+mmc_encr(u_long		base)	/* i/o port of the card */
+{
+  int	temp;
+
+  temp = mmc_in(base, mmroff(0, mmr_des_avail));
+  if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
+    return 0;
+  else
+    return temp;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wait for the frequency EEprom to complete a command...
+ * I hope this one will be optimally inlined...
+ */
+static inline void
+fee_wait(u_long		base,	/* i/o port of the card */
+	 int		delay,	/* Base delay to wait for */
+	 int		number)	/* Number of time to wait */
+{
+  int		count = 0;	/* Wait only a limited time */
+
+  while((count++ < number) &&
+	(mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))
+    udelay(delay);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read bytes from the Frequency EEprom (frequency select cards).
+ */
+static void
+fee_read(u_long		base,	/* i/o port of the card */
+	 u_short	o,	/* destination offset */
+	 u_short *	b,	/* data buffer */
+	 int		n)	/* number of registers */
+{
+  b += n;		/* Position at the end of the area */
+
+  /* Write the address */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+  /* Loop on all buffer */
+  while(n-- > 0)
+    {
+      /* Write the read command */
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
+
+      /* Wait until EEprom is ready (should be quick !) */
+      fee_wait(base, 10, 100);
+
+      /* Read the value */
+      *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) |
+	      mmc_in(base, mmroff(0, mmr_fee_data_l)));
+    }
+}
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write bytes from the Frequency EEprom (frequency select cards).
+ * This is a bit complicated, because the frequency eeprom has to
+ * be unprotected and the write enabled.
+ * Jean II
+ */
+static void
+fee_write(u_long	base,	/* i/o port of the card */
+	  u_short	o,	/* destination offset */
+	  u_short *	b,	/* data buffer */
+	  int		n)	/* number of registers */
+{
+  b += n;		/* Position at the end of the area */
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+  /* Ask to read the protected register */
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
+
+  fee_wait(base, 10, 100);
+
+  /* Read the protected register */
+  printk("Protected 2 : %02X-%02X\n",
+	 mmc_in(base, mmroff(0, mmr_fee_data_h)),
+	 mmc_in(base, mmroff(0, mmr_fee_data_l)));
+#endif	/* DOESNT_SEEM_TO_WORK */
+
+  /* Enable protected register */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
+
+  fee_wait(base, 10, 100);
+
+  /* Unprotect area */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+  /* Or use : */
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
+#endif	/* DOESNT_SEEM_TO_WORK */
+
+  fee_wait(base, 10, 100);
+#endif	/* EEPROM_IS_PROTECTED */
+
+  /* Write enable */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
+
+  fee_wait(base, 10, 100);
+
+  /* Write the EEprom address */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+  /* Loop on all buffer */
+  while(n-- > 0)
+    {
+      /* Write the value */
+      mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
+      mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
+
+      /* Write the write command */
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
+
+      /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
+      udelay(10000);
+      fee_wait(base, 10, 100);
+    }
+
+  /* Write disable */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
+
+  fee_wait(base, 10, 100);
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+  /* Reprotect EEprom */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+
+  fee_wait(base, 10, 100);
+#endif	/* EEPROM_IS_PROTECTED */
+}
+#endif	/* WIRELESS_EXT */
+
+/******************* WaveLAN Roaming routines... ********************/
+
+#ifdef WAVELAN_ROAMING	/* Conditional compile, see wavelan_cs.h */
+
+unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
+  
+void wv_roam_init(struct net_device *dev)
+{
+  net_local  *lp= (net_local *)dev->priv;
+
+  /* Do not remove this unless you have a good reason */
+  printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
+	 " device %s !\n", dev->name, dev->name);
+  printk(KERN_NOTICE "Roaming is currently an experimental unsuported feature"
+	 " of the Wavelan driver.\n");
+  printk(KERN_NOTICE "It may work, but may also make the driver behave in"
+	 " erratic ways or crash.\n");
+
+  lp->wavepoint_table.head=NULL;           /* Initialise WavePoint table */
+  lp->wavepoint_table.num_wavepoints=0;
+  lp->wavepoint_table.locked=0;
+  lp->curr_point=NULL;                        /* No default WavePoint */
+  lp->cell_search=0;
+  
+  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
+  lp->cell_timer.function=wl_cell_expiry;
+  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
+  add_timer(&lp->cell_timer);
+  
+  wv_nwid_filter(NWID_PROMISC,lp) ;    /* Enter NWID promiscuous mode */
+  /* to build up a good WavePoint */
+                                           /* table... */
+  printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name);
+}
+ 
+void wv_roam_cleanup(struct net_device *dev)
+{
+  wavepoint_history *ptr,*old_ptr;
+  net_local *lp= (net_local *)dev->priv;
+  
+  printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
+  
+  /* Fixme : maybe we should check that the timer exist before deleting it */
+  del_timer(&lp->cell_timer);          /* Remove cell expiry timer       */
+  ptr=lp->wavepoint_table.head;        /* Clear device's WavePoint table */
+  while(ptr!=NULL)
+    {
+      old_ptr=ptr;
+      ptr=ptr->next;	
+      wl_del_wavepoint(old_ptr,lp);	
+    }
+}
+
+/* Enable/Disable NWID promiscuous mode on a given device */
+void wv_nwid_filter(unsigned char mode, net_local *lp)
+{
+  mm_t                  m;
+  unsigned long         x;
+  
+#ifdef WAVELAN_ROAMING_DEBUG
+  printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name);
+#endif
+  
+  /* Disable interrupts & save flags */
+  x = wv_splhi();
+  
+  m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
+  mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
+  
+  /* ReEnable interrupts & restore flags */
+  wv_splx(x);
+  
+  if(mode==NWID_PROMISC)
+    lp->cell_search=1;
+  else
+	lp->cell_search=0;
+}
+
+/* Find a record in the WavePoint table matching a given NWID */
+wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
+{
+  wavepoint_history	*ptr=lp->wavepoint_table.head;
+  
+  while(ptr!=NULL){
+    if(ptr->nwid==nwid)
+      return ptr;	
+    ptr=ptr->next;
+  }
+  return NULL;
+}
+
+/* Create a new wavepoint table entry */
+wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
+{
+  wavepoint_history *new_wavepoint;
+
+#ifdef WAVELAN_ROAMING_DEBUG	
+  printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid);
+#endif
+  
+  if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS)
+    return NULL;
+  
+  new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC);
+  if(new_wavepoint==NULL)
+    return NULL;
+  
+  new_wavepoint->nwid=nwid;                       /* New WavePoints NWID */
+  new_wavepoint->average_fast=0;                    /* Running Averages..*/
+  new_wavepoint->average_slow=0;
+  new_wavepoint->qualptr=0;                       /* Start of ringbuffer */
+  new_wavepoint->last_seq=seq-1;                /* Last sequence no.seen */
+  memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */
+  
+  new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */
+  new_wavepoint->prev=NULL;
+  
+  if(lp->wavepoint_table.head!=NULL)
+    lp->wavepoint_table.head->prev=new_wavepoint;
+  
+  lp->wavepoint_table.head=new_wavepoint;
+  
+  lp->wavepoint_table.num_wavepoints++;     /* no. of visible wavepoints */
+  
+  return new_wavepoint;
+}
+
+/* Remove a wavepoint entry from WavePoint table */
+void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
+{
+  if(wavepoint==NULL)
+    return;
+  
+  if(lp->curr_point==wavepoint)
+    lp->curr_point=NULL;
+  
+  if(wavepoint->prev!=NULL)
+    wavepoint->prev->next=wavepoint->next;
+  
+  if(wavepoint->next!=NULL)
+    wavepoint->next->prev=wavepoint->prev;
+  
+  if(lp->wavepoint_table.head==wavepoint)
+    lp->wavepoint_table.head=wavepoint->next;
+  
+  lp->wavepoint_table.num_wavepoints--;
+  kfree(wavepoint);
+}
+
+/* Timer callback function - checks WavePoint table for stale entries */ 
+void wl_cell_expiry(unsigned long data)
+{
+  net_local *lp=(net_local *)data;
+  wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point;
+  
+#if WAVELAN_ROAMING_DEBUG > 1
+  printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name);
+#endif
+  
+  if(lp->wavepoint_table.locked)
+    {
+#if WAVELAN_ROAMING_DEBUG > 1
+      printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n");
+#endif
+      
+      lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */
+      add_timer(&lp->cell_timer);
+      return;
+    }
+  
+  while(wavepoint!=NULL)
+    {
+      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
+	{
+#ifdef WAVELAN_ROAMING_DEBUG
+	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
+#endif
+	  
+	  old_point=wavepoint;
+	  wavepoint=wavepoint->next;
+	  wl_del_wavepoint(old_point,lp);
+	}
+      else
+	wavepoint=wavepoint->next;
+    }
+  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
+  add_timer(&lp->cell_timer);
+}
+
+/* Update SNR history of a wavepoint */
+void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)	
+{
+  int i=0,num_missed=0,ptr=0;
+  int average_fast=0,average_slow=0;
+  
+  num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed
+							    any beacons? */
+  if(num_missed)
+    for(i=0;i<num_missed;i++)
+      {
+	wavepoint->sigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */
+	wavepoint->qualptr %=WAVEPOINT_HISTORY;    /* in the ringbuffer. */
+      }
+  wavepoint->last_seen=jiffies;                 /* Add beacon to history */
+  wavepoint->last_seq=seq;	
+  wavepoint->sigqual[wavepoint->qualptr++]=sigqual;          
+  wavepoint->qualptr %=WAVEPOINT_HISTORY;
+  ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY;
+  
+  for(i=0;i<WAVEPOINT_FAST_HISTORY;i++)       /* Update running averages */
+    {
+      average_fast+=wavepoint->sigqual[ptr++];
+      ptr %=WAVEPOINT_HISTORY;
+    }
+  
+  average_slow=average_fast;
+  for(i=WAVEPOINT_FAST_HISTORY;i<WAVEPOINT_HISTORY;i++)
+    {
+      average_slow+=wavepoint->sigqual[ptr++];
+      ptr %=WAVEPOINT_HISTORY;
+    }
+  
+  wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY;
+  wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY;	
+}
+
+/* Perform a handover to a new WavePoint */
+void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
+{
+  ioaddr_t              base = lp->dev->base_addr;  
+  mm_t                  m;
+  unsigned long         x;
+  
+  if(wavepoint==lp->curr_point)          /* Sanity check... */
+    {
+      wv_nwid_filter(!NWID_PROMISC,lp);
+      return;
+    }
+  
+#ifdef WAVELAN_ROAMING_DEBUG
+  printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name);
+#endif
+ 	
+  /* Disable interrupts & save flags */
+  x = wv_splhi();
+  
+  m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
+  m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
+  
+  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
+  
+  /* ReEnable interrupts & restore flags */
+  wv_splx(x);
+  
+  wv_nwid_filter(!NWID_PROMISC,lp);
+  lp->curr_point=wavepoint;
+}
+
+/* Called when a WavePoint beacon is received */
+static inline void wl_roam_gather(device *  dev,
+				  u_char *  hdr,   /* Beacon header */
+				  u_char *  stats) /* SNR, Signal quality 
+						      of packet */
+{
+  wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */
+  unsigned short nwid=ntohs(beacon->nwid);  
+  unsigned short sigqual=stats[2] & MMR_SGNL_QUAL;   /* SNR of beacon */
+  wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
+  net_local *lp=(net_local *)dev->priv;              /* Device info */
+
+#if WAVELAN_ROAMING_DEBUG > 1
+  printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
+  printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
+#endif
+  
+  lp->wavepoint_table.locked=1;                            /* <Mutex> */
+  
+  wavepoint=wl_roam_check(nwid,lp);            /* Find WavePoint table entry */
+  if(wavepoint==NULL)                    /* If no entry, Create a new one... */
+    {
+      wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp);
+      if(wavepoint==NULL)
+	goto out;
+    }
+  if(lp->curr_point==NULL)             /* If this is the only WavePoint, */
+    wv_roam_handover(wavepoint, lp);	         /* Jump on it! */
+  
+  wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history
+							 stats. */
+  
+  if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */
+    if(!lp->cell_search)                  /* WavePoint is getting faint, */
+      wv_nwid_filter(NWID_PROMISC,lp);    /* start looking for a new one */
+  
+  if(wavepoint->average_slow > 
+     lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA)
+    wv_roam_handover(wavepoint, lp);   /* Handover to a better WavePoint */
+  
+  if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */
+    if(lp->cell_search)  /* getting better, drop out of cell search mode */
+      wv_nwid_filter(!NWID_PROMISC,lp);
+  
+out:
+  lp->wavepoint_table.locked=0;                        /* </MUTEX>   :-) */
+}
+
+/* Test this MAC frame a WavePoint beacon */
+static inline int WAVELAN_BEACON(unsigned char *data)
+{
+  wavepoint_beacon *beacon= (wavepoint_beacon *)data;
+  static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00};
+  
+  if(memcmp(beacon,&beacon_template,9)==0)
+    return 1;
+  else
+    return 0;
+}
+#endif	/* WAVELAN_ROAMING */
+
+/************************ I82593 SUBROUTINES *************************/
+/*
+ * Usefull subroutines to manage the Ethernet controler
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to synchronously send a command to the i82593 chip. 
+ * Should be called with interrupts enabled.
+ */
+static int
+wv_82593_cmd(device *	dev,
+	     char *	str,
+	     int	cmd,
+	     int	result)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *)dev->priv;
+  int		status;
+  long		spin;
+  u_long	opri;
+
+  /* Spin until the chip finishes executing its current command (if any) */
+  do
+    {
+      opri = wv_splhi();
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+      wv_splx(opri);
+    }
+  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+
+  /* We are waiting for command completion */
+  wv_wait_completed = TRUE;
+
+  /* Issue the command to the controler */
+  outb(cmd, LCCR(base));
+
+  /* If we don't have to check the result of the command */
+  if(result == SR0_NO_RESULT)
+    {
+      wv_wait_completed = FALSE;
+      return(TRUE);
+    }
+
+  /* Busy wait while the LAN controller executes the command.
+   * Note : wv_wait_completed should be volatile */
+  spin = 0;
+  while(wv_wait_completed && (spin++ < 1000))
+    udelay(10);
+
+  /* If the interrupt handler hasn't be called */
+  if(wv_wait_completed)
+    {
+      outb(OP0_NOP, LCCR(base));
+      status = inb(LCSR(base));
+      if(status & SR0_INTERRUPT)
+	{
+	  /* There was an interrupt : call the interrupt handler */
+#ifdef DEBUG_INTERRUPT_ERROR
+	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
+#endif
+
+	  wavelan_interrupt(dev->irq, (void *) dev,
+			    (struct pt_regs *) NULL);
+	}
+      else
+	{
+	  wv_wait_completed = 0; /* XXX */
+#ifdef DEBUG_INTERRUPT_ERROR
+	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
+		 str, status);
+#endif
+	  /* We probably should reset the controller here */
+	  return(FALSE);
+	}
+    }
+
+  /* Check the return code provided by the interrupt handler against
+   * the expected return code provided by the caller */
+  if((lp->status & SR0_EVENT_MASK) != result)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
+	     str, lp->status);
+#endif
+      return(FALSE);
+    }
+
+  return(TRUE);
+} /* wv_82593_cmd */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a 593 op-code number 7, and obtains the diagnose
+ * status for the WaveLAN.
+ */
+static inline int
+wv_diag(device *	dev)
+{
+  if(wv_82593_cmd(dev, "wv_diag(): diagnose",
+		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
+    return(TRUE);
+
+#ifdef DEBUG_CONFIG_ERROR
+  printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
+#endif
+  return(FALSE);
+} /* wv_diag */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read len bytes from the i82593's ring buffer, starting at
+ * chip address addr. The results read from the chip are stored in buf.
+ * The return value is the address to use for next the call.
+ */
+static int
+read_ringbuf(device *	dev,
+	     int	addr,
+	     char *	buf,
+	     int	len)
+{
+  ioaddr_t	base = dev->base_addr;
+  int		ring_ptr = addr;
+  int		chunk_len;
+  char *	buf_ptr = buf;
+
+#ifdef OLDIES
+  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
+   * quite safe to remove this... */
+
+  /* If buf is NULL, just increment the ring buffer pointer */
+  if(buf == NULL)
+    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
+#endif
+
+  /* Get all the buffer */
+  while(len > 0)
+    {
+      /* Position the Program I/O Register at the ring buffer pointer */
+      outb(ring_ptr & 0xff, PIORL(base));
+      outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base));
+
+      /* First, determine how much we can read without wrapping around the
+	 ring buffer */
+      if((addr + len) < (RX_BASE + RX_SIZE))
+	chunk_len = len;
+      else
+	chunk_len = RX_BASE + RX_SIZE - addr;
+      insb(PIOP(base), buf_ptr, chunk_len);
+      buf_ptr += chunk_len;
+      len -= chunk_len;
+      ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE;
+    }
+  return(ring_ptr);
+} /* read_ringbuf */
+
+/*------------------------------------------------------------------*/
+/*
+ * Reconfigure the i82593, or at least ask for it...
+ * Because wv_82593_config use the transmission buffer, we must do it
+ * when we are sure that there is no transmission, so we do it now
+ * or in wavelan_packet_xmit() (I can't find any better place,
+ * wavelan_interrupt is not an option...), so you may experience
+ * some delay sometime...
+ */
+static inline void
+wv_82593_reconfig(device *	dev)
+{
+  net_local *	lp = (net_local *)dev->priv;
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+
+  /* Check if we can do it now ! */
+  if(!(link->open) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
+    {
+      lp->reconfig_82593 = TRUE;
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "%s: wv_82593_reconfig(): delayed (busy = %ld, link = %d)\n",
+	     dev->name, dev->tbusy, link->open);
+#endif
+    }
+  else
+    {
+      lp->reconfig_82593 = FALSE;
+      wv_82593_config(dev);
+      dev->tbusy = 0;
+    }
+}
+
+#ifdef OLDIES
+/*------------------------------------------------------------------*/
+/*
+ * Dumps the current i82593 receive buffer to the console.
+ */
+static void wavelan_dump(device *dev)
+{
+  ioaddr_t base = dev->base_addr;
+  int i, c;
+
+  /* disable receiver so we can use channel 1 */
+  outb(OP0_RCV_DISABLE, LCCR(base));
+
+  /* reset receive DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+
+  /* dump into receive buffer */
+  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
+
+  /* set read pointer to start of receive buffer */
+  outb(0, PIORL(base));
+  outb(0, PIORH(base));
+
+  printk(KERN_DEBUG "wavelan_cs: dump:\n");
+  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
+  for(i = 0; i < 73; i++){
+    if((i % 16) == 0) {
+      printk("\n0x%02x:", i);
+      if (!i) {
+	printk("   ");
+	continue;
+      }
+    }
+    c = inb(PIOP(base));
+    printk("%02x ", c);
+  }
+  printk("\n");
+
+  /* enable the receiver again */
+  wv_ru_start(dev);
+}
+#endif
+
+/********************* DEBUG & INFO SUBROUTINES *********************/
+/*
+ * This routines are used in the code to show debug informations.
+ * Most of the time, it dump the content of hardware structures...
+ */
+
+#ifdef DEBUG_PSA_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted contents of the Parameter Storage Area.
+ */
+static void
+wv_psa_show(psa_t *	p)
+{
+  printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+  printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
+	 p->psa_io_base_addr_1,
+	 p->psa_io_base_addr_2,
+	 p->psa_io_base_addr_3,
+	 p->psa_io_base_addr_4);
+  printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
+	 p->psa_rem_boot_addr_1,
+	 p->psa_rem_boot_addr_2,
+	 p->psa_rem_boot_addr_3);
+  printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
+  printk("psa_int_req_no: %d\n", p->psa_int_req_no);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 p->psa_unused0[0],
+	 p->psa_unused0[1],
+	 p->psa_unused0[2],
+	 p->psa_unused0[3],
+	 p->psa_unused0[4],
+	 p->psa_unused0[5],
+	 p->psa_unused0[6]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_univ_mac_addr[0],
+	 p->psa_univ_mac_addr[1],
+	 p->psa_univ_mac_addr[2],
+	 p->psa_univ_mac_addr[3],
+	 p->psa_univ_mac_addr[4],
+	 p->psa_univ_mac_addr[5]);
+  printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_local_mac_addr[0],
+	 p->psa_local_mac_addr[1],
+	 p->psa_local_mac_addr[2],
+	 p->psa_local_mac_addr[3],
+	 p->psa_local_mac_addr[4],
+	 p->psa_local_mac_addr[5]);
+  printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
+  printk("psa_comp_number: %d, ", p->psa_comp_number);
+  printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
+  printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
+	 p->psa_feature_select);
+  printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
+  printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
+  printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
+  printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]);
+  printk("psa_nwid_select: %d\n", p->psa_nwid_select);
+  printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select);
+  printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_encryption_key[0],
+	 p->psa_encryption_key[1],
+	 p->psa_encryption_key[2],
+	 p->psa_encryption_key[3],
+	 p->psa_encryption_key[4],
+	 p->psa_encryption_key[5],
+	 p->psa_encryption_key[6],
+	 p->psa_encryption_key[7]);
+  printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
+  printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
+	 p->psa_call_code[0]);
+  printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 p->psa_call_code[0],
+	 p->psa_call_code[1],
+	 p->psa_call_code[2],
+	 p->psa_call_code[3],
+	 p->psa_call_code[4],
+	 p->psa_call_code[5],
+	 p->psa_call_code[6],
+	 p->psa_call_code[7]);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+	 p->psa_reserved[0],
+	 p->psa_reserved[1],
+	 p->psa_reserved[2],
+	 p->psa_reserved[3]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
+  printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
+  printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
+} /* wv_psa_show */
+#endif	/* DEBUG_PSA_SHOW */
+
+#ifdef DEBUG_MMC_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the Modem Management Controller.
+ * This function need to be completed...
+ */
+static void
+wv_mmc_show(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *)dev->priv;
+  mmr_t		m;
+
+  /* Basic check */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+      printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n",
+	     dev->name);
+      return;
+    }
+
+  /* Read the mmc */
+  mmc_out(base, mmwoff(0, mmw_freeze), 1);
+  mmc_read(base, 0, (u_char *)&m, sizeof(m));
+  mmc_out(base, mmwoff(0, mmw_freeze), 0);
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+  /* Don't forget to update statistics */
+  lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+#endif	/* WIRELESS_EXT */
+
+  printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 m.mmr_unused0[0],
+	 m.mmr_unused0[1],
+	 m.mmr_unused0[2],
+	 m.mmr_unused0[3],
+	 m.mmr_unused0[4],
+	 m.mmr_unused0[5],
+	 m.mmr_unused0[6],
+	 m.mmr_unused0[7]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+	 m.mmr_des_avail, m.mmr_des_status);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
+	 m.mmr_unused1[0],
+	 m.mmr_unused1[1],
+	 m.mmr_unused1[2],
+	 m.mmr_unused1[3],
+	 m.mmr_unused1[4]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
+	 m.mmr_dce_status,
+	 (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
+	 "loop test indicated," : "",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
+	 "jabber timer expired," : "");
+  printk(KERN_DEBUG "Dsp ID: %02X\n",
+	 m.mmr_dsp_id);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
+	 m.mmr_unused2[0],
+	 m.mmr_unused2[1]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
+	 (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
+	 (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+  printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
+	 m.mmr_thr_pre_set & MMR_THR_PRE_SET,
+	 (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below");
+  printk(KERN_DEBUG "signal_lvl: %d [%s], ",
+	 m.mmr_signal_lvl & MMR_SIGNAL_LVL,
+	 (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg");
+  printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL,
+	 (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update");
+  printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
+	 (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0");
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
+#endif	/* DEBUG_SHOW_UNUSED */
+} /* wv_mmc_show */
+#endif	/* DEBUG_MMC_SHOW */
+
+#ifdef DEBUG_I82593_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the i82593's receive unit.
+ */
+static void
+wv_ru_show(device *	dev)
+{
+  net_local *lp = (net_local *) dev->priv;
+
+  printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
+  printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
+  /*
+   * Not implemented yet...
+   */
+  printk("\n");
+} /* wv_ru_show */
+#endif	/* DEBUG_I82593_SHOW */
+
+#ifdef DEBUG_DEVICE_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver.
+ */
+static void
+wv_dev_show(device *	dev)
+{
+  printk(KERN_DEBUG "dev:");
+  printk(" start=%d,", dev->start);
+  printk(" tbusy=%ld,", dev->tbusy);
+  printk(" interrupt=%d,", dev->interrupt);
+  printk(" trans_start=%ld,", dev->trans_start);
+  printk(" flags=0x%x,", dev->flags);
+  printk("\n");
+} /* wv_dev_show */
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver's
+ * private information.
+ */
+static void
+wv_local_show(device *	dev)
+{
+  net_local *lp;
+
+  lp = (net_local *)dev->priv;
+
+  printk(KERN_DEBUG "local:");
+  /*
+   * Not implemented yet...
+   */
+  printk("\n");
+} /* wv_local_show */
+#endif	/* DEBUG_DEVICE_SHOW */
+
+#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
+/*------------------------------------------------------------------*/
+/*
+ * Dump packet header (and content if necessary) on the screen
+ */
+static inline void
+wv_packet_info(u_char *		p,		/* Packet to dump */
+	       int		length,		/* Length of the packet */
+	       char *		msg1,		/* Name of the device */
+	       char *		msg2)		/* Name of the function */
+{
+  int		i;
+  int		maxi;
+
+  printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
+	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+  printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
+	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+
+#ifdef DEBUG_PACKET_DUMP
+
+  printk(KERN_DEBUG "data=\"");
+
+  if((maxi = length) > DEBUG_PACKET_DUMP)
+    maxi = DEBUG_PACKET_DUMP;
+  for(i = 14; i < maxi; i++)
+    if(p[i] >= ' ' && p[i] <= '~')
+      printk(" %c", p[i]);
+    else
+      printk("%02X", p[i]);
+  if(maxi < length)
+    printk("..");
+  printk("\"\n");
+  printk(KERN_DEBUG "\n");
+#endif	/* DEBUG_PACKET_DUMP */
+}
+#endif	/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
+
+/*------------------------------------------------------------------*/
+/*
+ * This is the information which is displayed by the driver at startup
+ * There  is a lot of flag to configure it at your will...
+ */
+static inline void
+wv_init_info(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  psa_t		psa;
+  int		i;
+
+  /* Read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+#ifdef DEBUG_PSA_SHOW
+  wv_psa_show(&psa);
+#endif
+#ifdef DEBUG_MMC_SHOW
+  wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82593_SHOW
+  wv_ru_show(dev);
+#endif
+
+#ifdef DEBUG_BASIC_SHOW
+  /* Now, let's go for the basic stuff */
+  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr",
+	 dev->name, base, dev->irq);
+  for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
+    printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+
+  /* Print current network id */
+  if(psa.psa_nwid_select)
+    printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
+  else
+    printk(", nwid off");
+
+  /* If 2.00 card */
+  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+    {
+      unsigned short	freq;
+
+      /* Ask the EEprom to read the frequency from the first area */
+      fee_read(base, 0x00 /* 1st area - frequency... */,
+	       &freq, 1);
+
+      /* Print frequency */
+      printk(", 2.00, %ld", (freq >> 6) + 2400L);
+
+      /* Hack !!! */
+      if(freq & 0x20)
+	printk(".5");
+    }
+  else
+    {
+      printk(", PCMCIA, ");
+      switch (psa.psa_subband)
+	{
+	case PSA_SUBBAND_915:
+	  printk("915");
+	  break;
+	case PSA_SUBBAND_2425:
+	  printk("2425");
+	  break;
+	case PSA_SUBBAND_2460:
+	  printk("2460");
+	  break;
+	case PSA_SUBBAND_2484:
+	  printk("2484");
+	  break;
+	case PSA_SUBBAND_2430_5:
+	  printk("2430.5");
+	  break;
+	default:
+	  printk("???");
+	}
+    }
+
+  printk(" MHz\n");
+#endif	/* DEBUG_BASIC_SHOW */
+
+#ifdef DEBUG_VERSION_SHOW
+  /* Print version information */
+  printk(KERN_NOTICE "%s", version);
+#endif
+} /* wv_init_info */
+
+/********************* IOCTL, STATS & RECONFIG *********************/
+/*
+ * We found here routines that are called by Linux on differents
+ * occasions after the configuration and not for transmitting data
+ * These may be called when the user use ifconfig, /proc/net/dev
+ * or wireless extensions
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the current ethernet statistics. This may be called with the
+ * card open or closed.
+ * Used when the user read /proc/net/dev
+ */
+static en_stats	*
+wavelan_get_stats(device *	dev)
+{
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
+#endif
+
+  return(&((net_local *) dev->priv)->stats);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+
+static void
+wavelan_set_multicast_list(device *	dev)
+{
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
+#endif
+
+#ifdef DEBUG_IOCTL_INFO
+  printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
+	 dev->name, dev->flags, dev->mc_count);
+#endif
+
+  if(dev->flags & IFF_PROMISC)
+    {
+      /*
+       * Enable promiscuous mode: receive all packets.
+       */
+      if(!lp->promiscuous)
+	{
+	  lp->promiscuous = 1;
+	  lp->allmulticast = 0;
+	  lp->mc_count = 0;
+
+	  wv_82593_reconfig(dev);
+
+	  /* Tell the kernel that we are doing a really bad job... */
+	  dev->flags |= IFF_PROMISC;
+	}
+    }
+  else
+    /* If all multicast addresses
+     * or too much multicast addresses for the hardware filter */
+    if((dev->flags & IFF_ALLMULTI) ||
+       (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES))
+      {
+	/*
+	 * Disable promiscuous mode, but active the all multicast mode
+	 */
+	if(!lp->allmulticast)
+	  {
+	    lp->promiscuous = 0;
+	    lp->allmulticast = 1;
+	    lp->mc_count = 0;
+
+	    wv_82593_reconfig(dev);
+
+	    /* Tell the kernel that we are doing a really bad job... */
+	    dev->flags |= IFF_ALLMULTI;
+	  }
+      }
+    else
+      /* If there is some multicast addresses to send */
+      if(dev->mc_list != (struct dev_mc_list *) NULL)
+	{
+	  /*
+	   * Disable promiscuous mode, but receive all packets
+	   * in multicast list
+	   */
+#ifdef MULTICAST_AVOID
+	  if(lp->promiscuous || lp->allmulticast ||
+	     (dev->mc_count != lp->mc_count))
+#endif
+	    {
+	      lp->promiscuous = 0;
+	      lp->allmulticast = 0;
+	      lp->mc_count = dev->mc_count;
+
+	      wv_82593_reconfig(dev);
+	    }
+	}
+      else
+	{
+	  /*
+	   * Switch to normal mode: disable promiscuous mode and 
+	   * clear the multicast list.
+	   */
+	  if(lp->promiscuous || lp->mc_count == 0)
+	    {
+	      lp->promiscuous = 0;
+	      lp->allmulticast = 0;
+	      lp->mc_count = 0;
+
+	      wv_82593_reconfig(dev);
+	    }
+	}
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This function doesn't exist...
+ * (Note : it was a nice way to test the reconfigure stuff...)
+ */
+#ifdef SET_MAC_ADDRESS
+static int
+wavelan_set_mac_address(device *	dev,
+			void *		addr)
+{
+  struct sockaddr *	mac = addr;
+
+  /* Copy the address */
+  memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
+
+  /* Reconfig the beast */
+  wv_82593_reconfig(dev);
+
+  return 0;
+}
+#endif	/* SET_MAC_ADDRESS */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Frequency setting (for hardware able of it)
+ * It's a bit complicated and you don't really want to look into it...
+ * (called in wavelan_ioctl)
+ */
+static inline int
+wv_set_frequency(u_long		base,	/* i/o port of the card */
+		 iw_freq *	frequency)
+{
+  const int	BAND_NUM = 10;	/* Number of bands */
+  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz */
+#ifdef DEBUG_IOCTL_INFO
+  int		i;
+#endif
+
+  /* Setting by frequency */
+  /* Theoritically, you may set any frequency between
+   * the two limits with a 0.5 MHz precision. In practice,
+   * I don't want you to have trouble with local
+   * regulations... */
+  if((frequency->e == 1) &&
+     (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
+    {
+      freq = ((frequency->m / 10000) - 24000L) / 5;
+    }
+
+  /* Setting by channel (same as wfreqsel) */
+  /* Warning : each channel is 22MHz wide, so some of the channels
+   * will interfere... */
+  if((frequency->e == 0) &&
+     (frequency->m >= 0) && (frequency->m < BAND_NUM))
+    {
+      /* Get frequency offset. */
+      freq = channel_bands[frequency->m] >> 1;
+    }
+
+  /* Verify if the frequency is allowed */
+  if(freq != 0L)
+    {
+      u_short	table[10];	/* Authorized frequency table */
+
+      /* Read the frequency table */
+      fee_read(base, 0x71 /* frequency table */,
+	       table, 10);
+
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Frequency table :");
+      for(i = 0; i < 10; i++)
+	{
+	  printk(" %04X",
+		 table[i]);
+	}
+      printk("\n");
+#endif
+
+      /* Look in the table if the frequency is allowed */
+      if(!(table[9 - ((freq - 24) / 16)] &
+	   (1 << ((freq - 24) % 16))))
+	return -EINVAL;		/* not allowed */
+    }
+  else
+    return -EINVAL;
+
+  /* If we get a usable frequency */
+  if(freq != 0L)
+    {
+      unsigned short	area[16];
+      unsigned short	dac[2];
+      unsigned short	area_verify[16];
+      unsigned short	dac_verify[2];
+      /* Corresponding gain (in the power adjust value table)
+       * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
+       * & WCIN062D.DOC, page 6.2.9 */
+      unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
+      int		power_band = 0;		/* Selected band */
+      unsigned short	power_adjust;		/* Correct value */
+
+      /* Search for the gain */
+      power_band = 0;
+      while((freq > power_limit[power_band]) &&
+	    (power_limit[++power_band] != 0))
+	;
+
+      /* Read the first area */
+      fee_read(base, 0x00,
+	       area, 16);
+
+      /* Read the DAC */
+      fee_read(base, 0x60,
+	       dac, 2);
+
+      /* Read the new power adjust value */
+      fee_read(base, 0x6B - (power_band >> 1),
+	       &power_adjust, 1);
+      if(power_band & 0x1)
+	power_adjust >>= 8;
+      else
+	power_adjust &= 0xFF;
+
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      for(i = 0; i < 16; i++)
+	{
+	  printk(" %04X",
+		 area[i]);
+	}
+      printk("\n");
+
+      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+	     dac[0], dac[1]);
+#endif
+
+      /* Frequency offset (for info only...) */
+      area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
+
+      /* Receiver Principle main divider coefficient */
+      area[3] = (freq >> 1) + 2400L - 352L;
+      area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+      /* Transmitter Main divider coefficient */
+      area[13] = (freq >> 1) + 2400L;
+      area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+      /* Others part of the area are flags, bit streams or unused... */
+
+      /* Set the value in the DAC */
+      dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
+      dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
+
+      /* Write the first area */
+      fee_write(base, 0x00,
+		area, 16);
+
+      /* Write the DAC */
+      fee_write(base, 0x60,
+		dac, 2);
+
+      /* We now should verify here that the EEprom writting was ok */
+
+      /* ReRead the first area */
+      fee_read(base, 0x00,
+	       area_verify, 16);
+
+      /* ReRead the DAC */
+      fee_read(base, 0x60,
+	       dac_verify, 2);
+
+      /* Compare */
+      if(memcmp(area, area_verify, 16 * 2) ||
+	 memcmp(dac, dac_verify, 2 * 2))
+	{
+#ifdef DEBUG_IOCTL_ERROR
+	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+#endif
+	  return -EOPNOTSUPP;
+	}
+
+      /* We must download the frequency parameters to the
+       * synthetisers (from the EEprom - area 1)
+       * Note : as the EEprom is auto decremented, we set the end
+       * if the area... */
+      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F);
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
+	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+      /* We must now download the power adjust value (gain) to
+       * the synthetisers (from the EEprom - area 7 - DAC) */
+      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61);
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
+	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+#ifdef DEBUG_IOCTL_INFO
+      /* Verification of what we have done... */
+
+      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      for(i = 0; i < 16; i++)
+	{
+	  printk(" %04X",
+		 area_verify[i]);
+	}
+      printk("\n");
+
+      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+	     dac_verify[0], dac_verify[1]);
+#endif
+
+      return 0;
+    }
+  else
+    return -EINVAL;		/* Bah, never get there... */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Give the list of available frequencies
+ */
+static inline int
+wv_frequency_list(u_long	base,	/* i/o port of the card */
+		  iw_freq *	list,	/* List of frequency to fill */
+		  int		max)	/* Maximum number of frequencies */
+{
+  u_short	table[10];	/* Authorized frequency table */
+  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
+  int		i;		/* index in the table */
+#if WIRELESS_EXT > 7
+  const int	BAND_NUM = 10;	/* Number of bands */
+  int		c = 0;		/* Channel number */
+#endif WIRELESS_EXT
+
+  /* Read the frequency table */
+  fee_read(base, 0x71 /* frequency table */,
+	   table, 10);
+
+  /* Look all frequencies */
+  i = 0;
+  for(freq = 0; freq < 150; freq++)
+    /* Look in the table if the frequency is allowed */
+    if(table[9 - (freq / 16)] & (1 << (freq % 16)))
+      {
+#if WIRELESS_EXT > 7
+	/* Compute approximate channel number */
+	while((((channel_bands[c] >> 1) - 24) < freq) &&
+	      (c < BAND_NUM))
+	  c++;
+	list[i].i = c;	/* Set the list index */
+#endif WIRELESS_EXT
+
+	/* put in the list */
+	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
+	list[i++].e = 1;
+
+	/* Check number */
+	if(i >= max)
+	  return(i);
+      }
+
+  return(i);
+}
+
+#ifdef WIRELESS_SPY
+/*------------------------------------------------------------------*/
+/*
+ * Gather wireless spy statistics : for each packet, compare the source
+ * address with out list, and if match, get the stats...
+ * Sorry, but this function really need wireless extensions...
+ */
+static inline void
+wl_spy_gather(device *	dev,
+	      u_char *	mac,		/* MAC address */
+	      u_char *	stats)		/* Statistics to gather */
+{
+  net_local *	lp = (net_local *) dev->priv;
+  int		i;
+
+  /* Look all addresses */
+  for(i = 0; i < lp->spy_number; i++)
+    /* If match */
+    if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
+      {
+	/* Update statistics */
+	lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
+	lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
+	lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
+	lp->spy_stat[i].updated = 0x7;
+      }
+}
+#endif	/* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+/*------------------------------------------------------------------*/
+/*
+ * This function calculate an histogram on the signal level.
+ * As the noise is quite constant, it's like doing it on the SNR.
+ * We have defined a set of interval (lp->his_range), and each time
+ * the level goes in that interval, we increment the count (lp->his_sum).
+ * With this histogram you may detect if one wavelan is really weak,
+ * or you may also calculate the mean and standard deviation of the level...
+ */
+static inline void
+wl_his_gather(device *	dev,
+	      u_char *	stats)		/* Statistics to gather */
+{
+  net_local *	lp = (net_local *) dev->priv;
+  u_char	level = stats[0] & MMR_SIGNAL_LVL;
+  int		i;
+
+  /* Find the correct interval */
+  i = 0;
+  while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
+    ;
+
+  /* Increment interval counter */
+  (lp->his_sum[i])++;
+}
+#endif	/* HISTOGRAM */
+
+/*------------------------------------------------------------------*/
+/*
+ * Perform ioctl : config & info stuff
+ * This is here that are treated the wireless extensions (iwconfig)
+ */
+static int
+wavelan_ioctl(struct net_device *	dev,	/* Device on wich the ioctl apply */
+	      struct ifreq *	rq,	/* Data passed */
+	      int		cmd)	/* Ioctl number */
+{
+  ioaddr_t		base = dev->base_addr;
+  net_local *		lp = (net_local *)dev->priv;	/* lp is not unused */
+  struct iwreq *	wrq = (struct iwreq *) rq;
+  psa_t			psa;
+  mm_t			m;
+  unsigned long		x;
+  int			ret = 0;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
+#endif
+
+  /* Disable interrupts & save flags */
+  x = wv_splhi();
+
+  /* Look what is the request */
+  switch(cmd)
+    {
+      /* --------------- WIRELESS EXTENSIONS --------------- */
+
+    case SIOCGIWNAME:
+      strcpy(wrq->u.name, "Wavelan");
+      break;
+
+    case SIOCSIWNWID:
+      /* Set NWID in wavelan */
+#if WIRELESS_EXT > 8
+      if(!wrq->u.nwid.disabled)
+	{
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+#else	/* WIRELESS_EXT > 8 */
+      if(wrq->u.nwid.on)
+	{
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
+#endif	/* WIRELESS_EXT > 8 */
+	  psa.psa_nwid_select = 0x01;
+	  psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
+		    (unsigned char *)psa.psa_nwid, 3);
+
+	  /* Set NWID in mmc */
+	  m.w.mmw_netw_id_l = psa.psa_nwid[1];
+	  m.w.mmw_netw_id_h = psa.psa_nwid[0];
+	  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m,
+		    (unsigned char *)&m.w.mmw_netw_id_l, 2);
+	  mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
+	}
+      else
+	{
+	  /* Disable nwid in the psa */
+	  psa.psa_nwid_select = 0x00;
+	  psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
+		    (unsigned char *)&psa.psa_nwid_select, 1);
+
+	  /* Disable nwid in the mmc (no filtering) */
+	  mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      break;
+
+    case SIOCGIWNWID:
+      /* Read the NWID */
+      psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
+	       (unsigned char *)psa.psa_nwid, 3);
+#if WIRELESS_EXT > 8
+      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+      wrq->u.nwid.fixed = 1;	/* Superfluous */
+#else	/* WIRELESS_EXT > 8 */
+      wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.on = psa.psa_nwid_select;
+#endif	/* WIRELESS_EXT > 8 */
+      break;
+
+    case SIOCSIWFREQ:
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	ret = wv_set_frequency(base, &(wrq->u.freq));
+      else
+	ret = -EOPNOTSUPP;
+      break;
+
+    case SIOCGIWFREQ:
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+       * (does it work for everybody ??? - especially old cards...) */
+      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	{
+	  unsigned short	freq;
+
+	  /* Ask the EEprom to read the frequency from the first area */
+	  fee_read(base, 0x00 /* 1st area - frequency... */,
+		   &freq, 1);
+	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+	  wrq->u.freq.e = 1;
+	}
+      else
+	{
+	  psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
+		   (unsigned char *)&psa.psa_subband, 1);
+
+	  if(psa.psa_subband <= 4)
+	    {
+	      wrq->u.freq.m = fixed_bands[psa.psa_subband];
+	      wrq->u.freq.e = (psa.psa_subband != 0);
+	    }
+	  else
+	    ret = -EOPNOTSUPP;
+	}
+      break;
+
+    case SIOCSIWSENS:
+      /* Set the level threshold */
+#if WIRELESS_EXT > 7
+      /* We should complain loudly if wrq->u.sens.fixed = 0, because we
+       * can't set auto mode... */
+      psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+#else	/* WIRELESS_EXT > 7 */
+      psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
+#endif	/* WIRELESS_EXT > 7 */
+      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+	       (unsigned char *)&psa.psa_thr_pre_set, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
+      break;
+
+    case SIOCGIWSENS:
+      /* Read the level threshold */
+      psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+	       (unsigned char *)&psa.psa_thr_pre_set, 1);
+#if WIRELESS_EXT > 7
+      wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
+      wrq->u.sens.fixed = 1;
+#else	/* WIRELESS_EXT > 7 */
+      wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
+#endif	/* WIRELESS_EXT > 7 */
+      break;
+
+#if WIRELESS_EXT > 8
+    case SIOCSIWENCODE:
+      /* Set encryption key */
+      if(!mmc_encr(base))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  /* Check the size of the key */
+	  if(wrq->u.encoding.length != 8)
+	    {
+	      ret = -EINVAL;
+	      break;
+	    }
+
+	  /* Copy the key in the driver */
+	  if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
+			    wrq->u.encoding.length))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  psa.psa_encryption_select = 1;
+	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 8+1);
+
+	  mmc_out(base, mmwoff(0, mmw_encr_enable),
+		  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+	  mmc_write(base, mmwoff(0, mmw_encr_key),
+		    (unsigned char *) &psa.psa_encryption_key, 8);
+	}
+
+      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+	{	/* disable encryption */
+	  psa.psa_encryption_select = 0;
+	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 1);
+
+	  mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      break;
+
+    case SIOCGIWENCODE:
+      /* Read the encryption key */
+      if(!mmc_encr(base))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* only super-user can see encryption key */
+      if(!suser())
+	{
+	  ret = -EPERM;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		   (unsigned char *) &psa.psa_encryption_select, 1+8);
+
+	  /* encryption is enabled ? */
+	  if(psa.psa_encryption_select)
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	  else
+	    wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+	  wrq->u.encoding.flags |= mmc_encr(base);
+
+	  /* Copy the key to the user buffer */
+	  wrq->u.encoding.length = 8;
+	  if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
+	    ret = -EFAULT;
+	}
+      break;
+#endif	/* WIRELESS_EXT > 8 */
+
+#ifdef WAVELAN_ROAMING_EXT
+#if WIRELESS_EXT > 5
+    case SIOCSIWESSID:
+      /* Check if disable */
+      if(wrq->u.data.flags == 0)
+	lp->filter_domains = 0;
+      else
+	/* Basic checking... */
+	if(wrq->u.data.pointer != (caddr_t) 0)
+	  {
+	    char	essid[IW_ESSID_MAX_SIZE + 1];
+	    char *	endp;
+
+	    /* Check the size of the string */
+	    if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
+	      {
+		ret = -E2BIG;
+		break;
+	      }
+
+	    /* Copy the string in the driver */
+	    if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
+	      {
+		ret = -EFAULT;
+		break;
+	      }
+	    essid[IW_ESSID_MAX_SIZE] = '\0';
+
+#ifdef DEBUG_IOCTL_INFO
+	    printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
+#endif	/* DEBUG_IOCTL_INFO */
+
+	    /* Convert to a number (note : Wavelan specific) */
+	    lp->domain_id = simple_strtoul(essid, &endp, 16);
+	    /* Has it worked  ? */
+	    if(endp > essid)
+	      lp->filter_domains = 1;
+	    else
+	      {
+		lp->filter_domains = 0;
+		ret = -EINVAL;
+	      }
+	  }
+      break;
+
+    case SIOCGIWESSID:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  char		essid[IW_ESSID_MAX_SIZE + 1];
+
+	  /* Is the domain ID active ? */
+	  wrq->u.data.flags = lp->filter_domains;
+
+	  /* Copy Domain ID into a string (Wavelan specific) */
+	  /* Sound crazy, be we can't have a snprintf in the kernel !!! */
+	  sprintf(essid, "%lX", lp->domain_id);
+	  essid[IW_ESSID_MAX_SIZE] = '\0';
+
+	  /* Set the length */
+	  wrq->u.data.length = strlen(essid) + 1;
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
+	    ret = -EFAULT;
+	}
+      break;
+
+    case SIOCSIWAP:
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
+	     wrq->u.ap_addr.sa_data[0],
+	     wrq->u.ap_addr.sa_data[1],
+	     wrq->u.ap_addr.sa_data[2],
+	     wrq->u.ap_addr.sa_data[3],
+	     wrq->u.ap_addr.sa_data[4],
+	     wrq->u.ap_addr.sa_data[5]);
+#endif	/* DEBUG_IOCTL_INFO */
+
+      ret = -EOPNOTSUPP;	/* Not supported yet */
+      break;
+
+    case SIOCGIWAP:
+      /* Should get the real McCoy instead of own Ethernet address */
+      memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
+      wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+
+      ret = -EOPNOTSUPP;	/* Not supported yet */
+      break;
+#endif	/* WIRELESS_EXT > 5 */
+#endif	/* WAVELAN_ROAMING_EXT */
+
+#if WIRELESS_EXT > 8
+#ifdef WAVELAN_ROAMING
+    case SIOCSIWMODE:
+      switch(wrq->u.mode)
+	{
+	case IW_MODE_ADHOC:
+	  if(do_roaming)
+	    {
+	      wv_roam_cleanup(dev);
+	      do_roaming = 0;
+	    }
+	  break;
+	case IW_MODE_INFRA:
+	  if(!do_roaming)
+	    {
+	      wv_roam_init(dev);
+	      do_roaming = 1;
+	    }
+	  break;
+	default:
+	  ret = -EINVAL;
+	}
+      break;
+
+    case SIOCGIWMODE:
+      if(do_roaming)
+	wrq->u.mode = IW_MODE_INFRA;
+      else
+	wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#endif	/* WAVELAN_ROAMING */
+#endif /* WIRELESS_EXT > 8 */
+
+    case SIOCGIWRANGE:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_range	range;
+
+	  /* Set the length (useless : its constant...) */
+	  wrq->u.data.length = sizeof(struct iw_range);
+
+	  /* Set information in the range struct */
+	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
+	  range.min_nwid = 0x0000;
+	  range.max_nwid = 0xFFFF;
+
+	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+	  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	    {
+	      range.num_channels = 10;
+	      range.num_frequency = wv_frequency_list(base, range.freq,
+						      IW_MAX_FREQUENCIES);
+	    }
+	  else
+	    range.num_channels = range.num_frequency = 0;
+
+	  range.sensitivity = 0x3F;
+	  range.max_qual.qual = MMR_SGNL_QUAL;
+	  range.max_qual.level = MMR_SIGNAL_LVL;
+	  range.max_qual.noise = MMR_SILENCE_LVL;
+
+#if WIRELESS_EXT > 7
+	  range.num_bitrates = 1;
+	  range.bitrate[0] = 2000000;	/* 2 Mb/s */
+#endif /* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+	  /* Encryption supported ? */
+	  if(mmc_encr(base))
+	    {
+	      range.encoding_size[0] = 8;	/* DES = 64 bits key */
+	      range.num_encoding_sizes = 1;
+	      range.max_encoding_tokens = 1;	/* Only one key possible */
+	    }
+	  else
+	    {
+	      range.num_encoding_sizes = 0;
+	      range.max_encoding_tokens = 0;
+	    }
+#endif /* WIRELESS_EXT > 8 */
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, &range,
+			  sizeof(struct iw_range)))
+	    ret = -EFAULT;
+	}
+      break;
+
+    case SIOCGIWPRIV:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_priv_args	priv[] =
+	  {	/* cmd,		set_args,	get_args,	name */
+	    { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
+	    { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
+	    { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,	0, "sethisto" },
+	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
+	    { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" },
+	    { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
+	  };
+
+	  /* Set the number of ioctl available */
+	  wrq->u.data.length = 6;
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+		       sizeof(priv)))
+	    ret = -EFAULT;
+	}
+      break;
+
+#ifdef WIRELESS_SPY
+    case SIOCSIWSPY:
+      /* Set the spy list */
+
+      /* Check the number of addresses */
+      if(wrq->u.data.length > IW_MAX_SPY)
+	{
+	  ret = -E2BIG;
+	  break;
+	}
+      lp->spy_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(lp->spy_number > 0)
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses to the driver */
+	  if(copy_from_user(address, wrq->u.data.pointer,
+			    sizeof(struct sockaddr) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy addresses to the lp structure */
+	  for(i = 0; i < lp->spy_number; i++)
+	    {
+	      memcpy(lp->spy_address[i], address[i].sa_data,
+		     WAVELAN_ADDR_SIZE);
+	    }
+
+	  /* Reset structure... */
+	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+	  for(i = 0; i < wrq->u.data.length; i++)
+	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		   lp->spy_address[i][0],
+		   lp->spy_address[i][1],
+		   lp->spy_address[i][2],
+		   lp->spy_address[i][3],
+		   lp->spy_address[i][4],
+		   lp->spy_address[i][5]);
+#endif	/* DEBUG_IOCTL_INFO */
+	}
+
+      break;
+
+    case SIOCGIWSPY:
+      /* Get the spy list and spy stats */
+
+      /* Set the number of addresses */
+      wrq->u.data.length = lp->spy_number;
+
+      /* If the user want to have the addresses back... */
+      if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses from the lp structure */
+	  for(i = 0; i < lp->spy_number; i++)
+	    {
+	      memcpy(address[i].sa_data, lp->spy_address[i],
+		     WAVELAN_ADDR_SIZE);
+	      address[i].sa_family = ARPHRD_ETHER;
+	    }
+
+	  /* Copy addresses to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, address,
+		       sizeof(struct sockaddr) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy stats to the user buffer (just after) */
+	  if(copy_to_user(wrq->u.data.pointer +
+		       (sizeof(struct sockaddr) * lp->spy_number),
+		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset updated flags */
+	  for(i = 0; i < lp->spy_number; i++)
+	    lp->spy_stat[i].updated = 0x0;
+	}	/* if(pointer != NULL) */
+
+      break;
+#endif	/* WIRELESS_SPY */
+
+      /* ------------------ PRIVATE IOCTL ------------------ */
+
+    case SIOCSIPQTHR:
+      if(!suser())
+	{
+	  ret = -EPERM;
+	  break;
+	}
+      psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
+      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+	       (unsigned char *)&psa.psa_quality_thr, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
+      break;
+
+    case SIOCGIPQTHR:
+      psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+	       (unsigned char *)&psa.psa_quality_thr, 1);
+      *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+      break;
+
+#ifdef WAVELAN_ROAMING
+    case SIOCSIPROAM:
+      /* Note : should check if user == root */
+      if(do_roaming && (*wrq->u.name)==0)
+	wv_roam_cleanup(dev);
+      else if(do_roaming==0 && (*wrq->u.name)!=0)
+	wv_roam_init(dev);
+
+      do_roaming = (*wrq->u.name);
+	  
+      break;
+
+    case SIOCGIPROAM:
+      *(wrq->u.name) = do_roaming;
+      break;
+#endif	/* WAVELAN_ROAMING */
+
+#ifdef HISTOGRAM
+    case SIOCSIPHISTO:
+      /* Verif if the user is root */
+      if(!suser())
+	{
+	  ret = -EPERM;
+	}
+
+      /* Check the number of intervals */
+      if(wrq->u.data.length > 16)
+	{
+	  ret = -E2BIG;
+	  break;
+	}
+      lp->his_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(lp->his_number > 0)
+	{
+	  /* Copy interval ranges to the driver */
+	  if(copy_from_user(lp->his_range, wrq->u.data.pointer,
+			 sizeof(char) * lp->his_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset structure... */
+	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
+	}
+      break;
+
+    case SIOCGIPHISTO:
+      /* Set the number of intervals */
+      wrq->u.data.length = lp->his_number;
+
+      /* Give back the distribution statistics */
+      if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  /* Copy data to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
+		       sizeof(long) * lp->his_number))
+	    ret = -EFAULT;
+
+	}	/* if(pointer != NULL) */
+      break;
+#endif	/* HISTOGRAM */
+
+      /* ------------------- OTHER IOCTL ------------------- */
+
+    default:
+      ret = -EOPNOTSUPP;
+    }
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(x);
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
+#endif
+  return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get wireless statistics
+ * Called by /proc/net/wireless...
+ */
+static iw_stats *
+wavelan_get_wireless_stats(device *	dev)
+{
+  ioaddr_t		base = dev->base_addr;
+  net_local *		lp = (net_local *) dev->priv;
+  mmr_t			m;
+  iw_stats *		wstats;
+  unsigned long		x;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
+#endif
+
+  /* Disable interrupts & save flags */
+  x = wv_splhi();
+
+  if(lp == (net_local *) NULL)
+    return (iw_stats *) NULL;
+  wstats = &lp->wstats;
+
+  /* Get data from the mmc */
+  mmc_out(base, mmwoff(0, mmw_freeze), 1);
+
+  mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
+  mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2);
+  mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4);
+
+  mmc_out(base, mmwoff(0, mmw_freeze), 0);
+
+  /* Copy data to wireless stuff */
+  wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
+  wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
+  wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
+  wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
+  wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) |
+			  ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) |
+			  ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
+  wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+  wstats->discard.code = 0L;
+  wstats->discard.misc = 0L;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(x);
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
+#endif
+  return &lp->wstats;
+}
+#endif	/* WIRELESS_EXT */
+
+/************************* PACKET RECEPTION *************************/
+/*
+ * This part deal with receiving the packets.
+ * The interrupt handler get an interrupt when a packet has been
+ * successfully received and called this part...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the starting address of the frame pointed to by the receive
+ * frame pointer and verify that the frame seem correct
+ * (called by wv_packet_rcv())
+ */
+static inline int
+wv_start_of_frame(device *	dev,
+		  int		rfp,	/* end of frame */
+		  int		wrap)	/* start of buffer */
+{
+  ioaddr_t	base = dev->base_addr;
+  int		rp;
+  int		len;
+
+  rp = (rfp - 5 + RX_SIZE) % RX_SIZE;
+  outb(rp & 0xff, PIORL(base));
+  outb(((rp >> 8) & PIORH_MASK), PIORH(base));
+  len = inb(PIOP(base));
+  len |= inb(PIOP(base)) << 8;
+
+  /* Sanity checks on size */
+  /* Frame too big */
+  if(len > MAXDATAZ + 100)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n",
+	     dev->name, rfp, len);
+#endif
+      return(-1);
+    }
+  
+  /* Frame too short */
+  if(len < 7)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n",
+	     dev->name, rfp, len);
+#endif
+      return(-1);
+    }
+  
+  /* Wrap around buffer */
+  if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE))	/* magic formula ! */
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",
+	     dev->name, wrap, rfp, len);
+#endif
+      return(-1);
+    }
+
+  return((rp - len + RX_SIZE) % RX_SIZE);
+} /* wv_start_of_frame */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does the actual copy of data (including the ethernet
+ * header structure) from the WaveLAN card to an sk_buff chain that
+ * will be passed up to the network interface layer. NOTE: We
+ * currently don't handle trailer protocols (neither does the rest of
+ * the network interface), so if that is needed, it will (at least in
+ * part) be added here.  The contents of the receive ring buffer are
+ * copied to a message chain that is then passed to the kernel.
+ *
+ * Note: if any errors occur, the packet is "dropped on the floor"
+ * (called by wv_packet_rcv())
+ */
+static inline void
+wv_packet_read(device *		dev,
+	       int		fd_p,
+	       int		sksize)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  struct sk_buff *	skb;
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
+	 dev->name, fd_p, sksize);
+#endif
+
+  /* Allocate some buffer for the new packet */
+  if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n",
+	     dev->name, sksize);
+#endif
+      lp->stats.rx_dropped++;
+      /*
+       * Not only do we want to return here, but we also need to drop the
+       * packet on the floor to clear the interrupt.
+       */
+      return;
+    }
+
+  skb->dev = dev;
+
+  skb_reserve(skb, 2);
+  fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize);
+  skb->protocol = eth_type_trans(skb, dev);
+
+#ifdef DEBUG_RX_INFO
+  /* Another glitch : Due to the way the GET_PACKET macro is written,
+   * we are not sure to have the same thing in skb->data. On the other
+   * hand, skb->mac.raw is not defined everywhere...
+   * For versions between 1.2.13 and those where skb->mac.raw appear,
+   * I don't have a clue...
+   */
+  wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+#endif	/* DEBUG_RX_INFO */
+     
+  /* Statistics gathering & stuff associated.
+   * It seem a bit messy with all the define, but it's really simple... */
+  if(
+#ifdef WIRELESS_SPY
+     (lp->spy_number > 0) ||
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+     (lp->his_number > 0) ||
+#endif	/* HISTOGRAM */
+#ifdef WAVELAN_ROAMING
+     (do_roaming) ||
+#endif	/* WAVELAN_ROAMING */
+     0)
+    {
+      u_char	stats[3];	/* Signal level, Noise level, Signal quality */
+
+      /* read signal level, silence level and signal quality bytes */
+      fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE,
+			  stats, 3);
+#ifdef DEBUG_RX_INFO
+      printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
+	     dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F);
+#endif
+
+#ifdef WAVELAN_ROAMING
+      if(do_roaming)
+	if(WAVELAN_BEACON(skb->data))
+	  wl_roam_gather(dev, skb->data, stats);
+#endif	/* WAVELAN_ROAMING */
+	  
+      /* Spying stuff */
+#ifdef WIRELESS_SPY
+      /* Same as above */
+      wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+      wl_his_gather(dev, stats);
+#endif	/* HISTOGRAM */
+    }
+
+  /*
+   * Hand the packet to the Network Module
+   */
+  netif_rx(skb);
+
+  /* Keep stats up to date */
+  lp->stats.rx_packets++;
+  lp->stats.rx_bytes += skb->len;
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
+#endif
+  return;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called by the interrupt handler to initiate a
+ * packet transfer from the card to the network interface layer above
+ * this driver.  This routine checks if a buffer has been successfully
+ * received by the WaveLAN card.  If so, the routine wv_packet_read is
+ * called to do the actual transfer of the card's data including the
+ * ethernet header into a packet consisting of an sk_buff chain.
+ * (called by wavelan_interrupt())
+ */
+static inline void
+wv_packet_rcv(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  int		newrfp;
+  int		rp;
+  int		len;
+  int		f_start;
+  int		status;
+  int		i593_rfp;
+  int		stat_ptr;
+  u_char	c[4];
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name);
+#endif
+
+  /* Get the new receive frame pointer from the i82593 chip */
+  outb(CR0_STATUS_2 | OP0_NOP, LCCR(base));
+  i593_rfp = inb(LCSR(base));
+  i593_rfp |= inb(LCSR(base)) << 8;
+  i593_rfp %= RX_SIZE;
+
+  /* Get the new receive frame pointer from the WaveLAN card.
+   * It is 3 bytes more than the increment of the i82593 receive
+   * frame pointer, for each packet. This is because it includes the
+   * 3 roaming bytes added by the mmc.
+   */
+  newrfp = inb(RPLL(base));
+  newrfp |= inb(RPLH(base)) << 8;
+  newrfp %= RX_SIZE;
+
+#ifdef DEBUG_RX_INFO
+  printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+	 dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+
+#ifdef DEBUG_RX_ERROR
+  /* If no new frame pointer... */
+  if(lp->overrunning || newrfp == lp->rfp)
+    printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+	   dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+
+  /* Read all frames (packets) received */
+  while(newrfp != lp->rfp)
+    {
+      /* A frame is composed of the packet, followed by a status word,
+       * the length of the frame (word) and the mmc info (SNR & qual).
+       * It's because the length is at the end that we can only scan
+       * frames backward. */
+
+      /* Find the first frame by skipping backwards over the frames */
+      rp = newrfp;	/* End of last frame */
+      while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) &&
+	    (f_start != -1))
+	  rp = f_start;
+
+      /* If we had a problem */
+      if(f_start == -1)
+	{
+#ifdef DEBUG_RX_ERROR
+	  printk(KERN_INFO "wavelan_cs: cannot find start of frame ");
+	  printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+		 i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+	  lp->rfp = rp;		/* Get to the last usable frame */
+	  continue;
+	}
+
+      /* f_start point to the beggining of the first frame received
+       * and rp to the beggining of the next one */
+
+      /* Read status & length of the frame */
+      stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE;
+      stat_ptr = read_ringbuf(dev, stat_ptr, c, 4);
+      status = c[0] | (c[1] << 8);
+      len = c[2] | (c[3] << 8);
+
+      /* Check status */
+      if((status & RX_RCV_OK) != RX_RCV_OK)
+	{
+	  lp->stats.rx_errors++;
+	  if(status & RX_NO_SFD)
+	    lp->stats.rx_frame_errors++;
+	  if(status & RX_CRC_ERR)
+	    lp->stats.rx_crc_errors++;
+	  if(status & RX_OVRRUN)
+	    lp->stats.rx_over_errors++;
+
+#ifdef DEBUG_RX_FAIL
+	  printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n",
+		 dev->name, status);
+#endif
+	}
+      else
+	/* Read the packet and transmit to Linux */
+	wv_packet_read(dev, f_start, len - 2);
+
+      /* One frame has been processed, skip it */
+      lp->rfp = rp;
+    }
+
+  /*
+   * Update the frame stop register, but set it to less than
+   * the full 8K to allow space for 3 bytes of signal strength
+   * per packet.
+   */
+  lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
+  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
+  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name);
+#endif
+}
+
+/*********************** PACKET TRANSMISSION ***********************/
+/*
+ * This part deal with sending packet through the wavelan
+ * We copy the packet to the send buffer and then issue the send
+ * command to the i82593. The result of this operation will be
+ * checked in wavelan_interrupt()
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine fills in the appropriate registers and memory
+ * locations on the WaveLAN card and starts the card off on
+ * the transmit.
+ * (called in wavelan_packet_xmit())
+ */
+static inline void
+wv_packet_write(device *	dev,
+		void *		buf,
+		short		length)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		x;
+  int			clen = length;
+  register u_short	xmtdata_base = TX_BASE;
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
+#endif
+
+  x = wv_splhi();
+
+  /* Check if we need some padding */
+  if(clen < ETH_ZLEN)
+    clen = ETH_ZLEN;
+
+  /* Write the length of data buffer followed by the buffer */
+  outb(xmtdata_base & 0xff, PIORL(base));
+  outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(clen & 0xff, PIOP(base));	/* lsb */
+  outb(clen >> 8, PIOP(base));  	/* msb */
+
+  /* Send the data */
+  outsb(PIOP(base), buf, clen);
+
+  /* Indicate end of transmit chain */
+  outb(OP0_NOP, PIOP(base));
+  /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */
+  outb(OP0_NOP, PIOP(base));
+
+  /* Reset the transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  /* Send the transmit command */
+  wv_82593_cmd(dev, "wv_packet_write(): transmit",
+	       OP0_TRANSMIT, SR0_NO_RESULT);
+
+  /* Keep stats up to date */
+  lp->stats.tx_bytes += length;
+
+  /* If watchdog not already active, activate it... */
+  if(lp->watchdog.prev == (timer_list *) NULL)
+    {
+      /* set timer to expire in WATCHDOG_JIFFIES */
+      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+      add_timer(&lp->watchdog);
+    }
+
+  wv_splx(x); 
+
+#ifdef DEBUG_TX_INFO
+  wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
+#endif	/* DEBUG_TX_INFO */
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called when we want to send a packet (NET3 callback)
+ * In this routine, we check if the the harware is ready to accept
+ * the packet. We also prevent reentrance. Then, we call the function
+ * to send the packet...
+ */
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
+{
+  net_local *	lp = (net_local *)dev->priv;
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
+#endif
+
+  /* This flag indicate that the hardware can't perform a transmission.
+   * Theoritically, NET3 check it before sending a packet to the driver,
+   * but in fact it never do that and pool continuously.
+   * As the watchdog will abort too long transmissions, we are quite safe...
+   */
+  if(dev->tbusy)
+    return(1);
+
+  /*
+   * For ethernet, fill in the header.
+   */
+
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
+#ifdef DEBUG_TX_ERROR
+    printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
+#endif
+  else
+    {
+      /* If somebody has asked to reconfigure the controler, we can do it now */
+      if(lp->reconfig_82593)
+	{
+	  lp->reconfig_82593 = FALSE;
+	  wv_82593_config(dev);
+	}
+
+#ifdef DEBUG_TX_ERROR
+      if(skb->next)
+	printk(KERN_INFO "skb has next\n");
+#endif
+ 
+      wv_packet_write(dev, skb->data, skb->len);
+    }
+
+  dev_kfree_skb(skb);
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+#endif
+  return(0);
+}
+
+/********************** HARDWARE CONFIGURATION **********************/
+/*
+ * This part do the real job of starting and configuring the hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to initialize the Modem Management Controller.
+ * (called by wv_hw_config())
+ */
+static inline int
+wv_mmc_init(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  psa_t		psa;
+  mmw_t		m;
+  int		configured;
+  int		i;		/* Loop counter */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
+#endif
+
+  /* Read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+  /*
+   * Check the first three octets of the MAC addr for the manufacturer's code.
+   * Note: If you get the error message below, you've got a
+   * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on
+   * how to configure your card...
+   */
+  for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+    if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) &&
+       (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) &&
+       (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2]))
+      break;
+
+  /* If we have not found it... */
+  if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3))
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n",
+	     dev->name, psa.psa_univ_mac_addr[0],
+	     psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]);
+#endif
+      return FALSE;
+    }
+
+  /* Get the MAC address */
+  memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE);
+
+#ifdef USE_PSA_CONFIG
+  configured = psa.psa_conf_status & 1;
+#else
+  configured = 0;
+#endif
+
+  /* Is the PSA is not configured */
+  if(!configured)
+    {
+      /* User will be able to configure NWID after (with iwconfig) */
+      psa.psa_nwid[0] = 0;
+      psa.psa_nwid[1] = 0;
+
+      /* As NWID is not set : no NWID checking */
+      psa.psa_nwid_select = 0;
+
+      /* Disable encryption */
+      psa.psa_encryption_select = 0;
+
+      /* Set to standard values
+       * 0x04 for AT,
+       * 0x01 for MCA,
+       * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
+       */
+      if (psa.psa_comp_number & 1)
+	psa.psa_thr_pre_set = 0x01;
+      else
+	psa.psa_thr_pre_set = 0x04;
+      psa.psa_quality_thr = 0x03;
+
+      /* It is configured */
+      psa.psa_conf_status |= 1;
+
+#ifdef USE_PSA_CONFIG
+      /* Write the psa */
+      psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
+		(unsigned char *)psa.psa_nwid, 4);
+      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+		(unsigned char *)&psa.psa_thr_pre_set, 1);
+      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+		(unsigned char *)&psa.psa_quality_thr, 1);
+      psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa,
+		(unsigned char *)&psa.psa_conf_status, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+#endif	/* USE_PSA_CONFIG */
+    }
+
+  /* Zero the mmc structure */
+  memset(&m, 0x00, sizeof(m));
+
+  /* Copy PSA info to the mmc */
+  m.mmw_netw_id_l = psa.psa_nwid[1];
+  m.mmw_netw_id_h = psa.psa_nwid[0];
+  
+  if(psa.psa_nwid_select & 1)
+    m.mmw_loopt_sel = 0x00;
+  else
+    m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
+
+  memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, 
+	 sizeof(m.mmw_encr_key));
+
+  if(psa.psa_encryption_select)
+    m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
+  else
+    m.mmw_encr_enable = 0;
+
+  m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
+  m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
+
+  /*
+   * Set default modem control parameters.
+   * See NCR document 407-0024326 Rev. A.
+   */
+  m.mmw_jabber_enable = 0x01;
+  m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+  m.mmw_ifs = 0x20;
+  m.mmw_mod_delay = 0x04;
+  m.mmw_jam_time = 0x38;
+
+  m.mmw_des_io_invert = 0;
+  m.mmw_freeze = 0;
+  m.mmw_decay_prm = 0;
+  m.mmw_decay_updat_prm = 0;
+
+  /* Write all info to mmc */
+  mmc_write(base, 0, (u_char *)&m, sizeof(m));
+
+  /* The following code start the modem of the 2.00 frequency
+   * selectable cards at power on. It's not strictly needed for the
+   * following boots...
+   * The original patch was by Joe Finney for the PCMCIA driver, but
+   * I've cleaned it a bit and add documentation.
+   * Thanks to Loeke Brederveld from Lucent for the info.
+   */
+
+  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+   * (does it work for everybody ??? - especially old cards...) */
+  /* Note : WFREQSEL verify that it is able to read from EEprom
+   * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
+   * is 0xA (Xilinx version) or 0xB (Ariadne version).
+   * My test is more crude but do work... */
+  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+    {
+      /* We must download the frequency parameters to the
+       * synthetisers (from the EEprom - area 1)
+       * Note : as the EEprom is auto decremented, we set the end
+       * if the area... */
+      m.mmw_fee_addr = 0x0F;
+      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
+		(unsigned char *)&m.mmw_fee_ctrl, 2);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+#ifdef DEBUG_CONFIG_INFO
+      /* The frequency was in the last word downloaded... */
+      mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m,
+	       (unsigned char *)&m.mmw_fee_data_l, 2);
+
+      /* Print some info for the user */
+      printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+	     dev->name,
+	     ((m.mmw_fee_data_h << 4) |
+	      (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
+#endif
+
+      /* We must now download the power adjust value (gain) to
+       * the synthetisers (from the EEprom - area 7 - DAC) */
+      m.mmw_fee_addr = 0x61;
+      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
+		(unsigned char *)&m.mmw_fee_ctrl, 2);
+
+      /* Wait until the download is finished */
+    }	/* if 2.00 card */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to gracefully turn off reception, and wait for any commands
+ * to complete.
+ * (called in wv_ru_start() and wavelan_close() and wavelan_event())
+ */
+static int
+wv_ru_stop(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  unsigned long	opri;
+  int		status;
+  int		spin;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
+#endif
+
+  /* First, send the LAN controller a stop receive command */
+  wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
+	       OP0_STOP_RCV, SR0_NO_RESULT);
+
+  /* Then, spin until the receive unit goes idle */
+  spin = 0;
+  do
+    {
+      udelay(10);
+      opri = wv_splhi();
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+      wv_splx(opri);
+    }
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+
+  /* Now, spin until the chip finishes executing its current command */
+  do
+    {
+      udelay(10);
+      opri = wv_splhi();
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+      wv_splx(opri);
+    }
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+
+  /* If there was a problem */
+  if(spin > 300)
+    {
+#ifdef DEBUG_CONFIG_ERROR
+      printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
+	     dev->name);
+#endif
+      return FALSE;
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name);
+#endif
+  return TRUE;
+} /* wv_ru_stop */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine starts the receive unit running.  First, it checks if
+ * the card is actually ready. Then the card is instructed to receive
+ * packets again.
+ * (called in wv_hw_reset() & wavelan_open())
+ */
+static int
+wv_ru_start(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
+#endif
+
+  /*
+   * We need to start from a quiescent state. To do so, we could check
+   * if the card is already running, but instead we just try to shut
+   * it down. First, we disable reception (in case it was already enabled).
+   */
+  if(!wv_ru_stop(dev))
+    return FALSE;
+
+  /* Now we know that no command is being executed. */
+
+  /* Set the receive frame pointer and stop pointer */
+  lp->rfp = 0;
+  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
+
+  /* Reset ring management.  This sets the receive frame pointer to 1 */
+  outb(OP1_RESET_RING_MNGMT, LCCR(base));
+
+  /* but I set it to 3 bytes per packet less than 8K */
+  lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
+  outb(OP1_INT_ENABLE, LCCR(base));
+  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
+
+  /* Reset receive DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write_slow(base, HACR_DEFAULT);
+
+  /* Receive DMA on channel 1 */
+  wv_82593_cmd(dev, "wv_ru_start(): rcv-enable",
+	       CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT);
+
+#ifdef DEBUG_I82593_SHOW
+  {
+    int	status;
+    int	opri;
+    int	i = 0;
+
+    /* spin until the chip starts receiving */
+    do
+      {
+	opri = wv_splhi();
+	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+	status = inb(LCSR(base));
+	wv_splx(opri);
+	if(i++ > 10000)
+	  break;
+      }
+    while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
+	  ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY));
+    printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n",
+	   (status & SR3_RCV_STATE_MASK), i);
+  }
+#endif
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a standard config of the WaveLAN controler (i82593).
+ * In the ISA driver, this is integrated in wavelan_hardware_reset()
+ * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit())
+ */
+static int
+wv_82593_config(device *	dev)
+{
+  ioaddr_t			base = dev->base_addr;
+  net_local *			lp = (net_local *) dev->priv;
+  struct i82593_conf_block	cfblk;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
+#endif
+
+  /* Create & fill i82593 config block
+   *
+   * Now conform to Wavelan document WCIN085B
+   */
+  memset(&cfblk, 0x00, sizeof(struct i82593_conf_block));
+  cfblk.d6mod = FALSE;  	/* Run in i82593 advanced mode */
+  cfblk.fifo_limit = 5;         /* = 56 B rx and 40 B tx fifo thresholds */
+  cfblk.forgnesi = FALSE;       /* 0=82C501, 1=AMD7992B compatibility */
+  cfblk.fifo_32 = 1;
+  cfblk.throttle_enb = FALSE;
+  cfblk.contin = TRUE;          /* enable continuous mode */
+  cfblk.cntrxint = FALSE;       /* enable continuous mode receive interrupts */
+  cfblk.addr_len = WAVELAN_ADDR_SIZE;
+  cfblk.acloc = TRUE;           /* Disable source addr insertion by i82593 */
+  cfblk.preamb_len = 0;         /* 2 bytes preamble (SFD) */
+  cfblk.loopback = FALSE;
+  cfblk.lin_prio = 0;   	/* conform to 802.3 backoff algoritm */
+  cfblk.exp_prio = 5;	        /* conform to 802.3 backoff algoritm */
+  cfblk.bof_met = 1;	        /* conform to 802.3 backoff algoritm */
+  cfblk.ifrm_spc = 0x20;	/* 32 bit times interframe spacing */
+  cfblk.slottim_low = 0x20;	/* 32 bit times slot time */
+  cfblk.slottim_hi = 0x0;
+  cfblk.max_retr = 15;
+  cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE);	/* Promiscuous mode */
+  cfblk.bc_dis = FALSE;         /* Enable broadcast reception */
+  cfblk.crs_1 = TRUE;		/* Transmit without carrier sense */
+  cfblk.nocrc_ins = FALSE;	/* i82593 generates CRC */	
+  cfblk.crc_1632 = FALSE;	/* 32-bit Autodin-II CRC */
+  cfblk.crs_cdt = FALSE;	/* CD not to be interpreted as CS */
+  cfblk.cs_filter = 0;  	/* CS is recognized immediately */
+  cfblk.crs_src = FALSE;	/* External carrier sense */
+  cfblk.cd_filter = 0;  	/* CD is recognized immediately */
+  cfblk.min_fr_len = ETH_ZLEN >> 2;     /* Minimum frame length 64 bytes */
+  cfblk.lng_typ = FALSE;	/* Length field > 1500 = type field */
+  cfblk.lng_fld = TRUE; 	/* Disable 802.3 length field check */
+  cfblk.rxcrc_xf = TRUE;	/* Don't transfer CRC to memory */
+  cfblk.artx = TRUE;		/* Disable automatic retransmission */
+  cfblk.sarec = TRUE;		/* Disable source addr trig of CD */
+  cfblk.tx_jabber = TRUE;	/* Disable jabber jam sequence */
+  cfblk.hash_1 = FALSE; 	/* Use bits 0-5 in mc address hash */
+  cfblk.lbpkpol = TRUE; 	/* Loopback pin active high */
+  cfblk.fdx = FALSE;		/* Disable full duplex operation */
+  cfblk.dummy_6 = 0x3f; 	/* all ones */
+  cfblk.mult_ia = FALSE;	/* No multiple individual addresses */
+  cfblk.dis_bof = FALSE;	/* Disable the backoff algorithm ?! */
+  cfblk.dummy_1 = TRUE; 	/* set to 1 */
+  cfblk.tx_ifs_retrig = 3;	/* Hmm... Disabled */
+#ifdef MULTICAST_ALL
+  cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE);	/* Allow all multicasts */
+#else
+  cfblk.mc_all = FALSE;		/* No multicast all mode */
+#endif
+  cfblk.rcv_mon = 0;		/* Monitor mode disabled */
+  cfblk.frag_acpt = TRUE;	/* Do not accept fragments */
+  cfblk.tstrttrs = FALSE;	/* No start transmission threshold */
+  cfblk.fretx = TRUE;		/* FIFO automatic retransmission */
+  cfblk.syncrqs = FALSE; 	/* Synchronous DRQ deassertion... */
+  cfblk.sttlen = TRUE;  	/* 6 byte status registers */
+  cfblk.rx_eop = TRUE;  	/* Signal EOP on packet reception */
+  cfblk.tx_eop = TRUE;  	/* Signal EOP on packet transmission */
+  cfblk.rbuf_size = RX_SIZE>>11;	/* Set receive buffer size */
+  cfblk.rcvstop = TRUE; 	/* Enable Receive Stop Register */
+
+#ifdef DEBUG_I82593_SHOW
+  {
+    u_char *c = (u_char *) &cfblk;
+    int i;
+    printk(KERN_DEBUG "wavelan_cs: config block:");
+    for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++)
+      {
+	if((i % 16) == 0) printk("\n" KERN_DEBUG);
+	printk("%02x ", *c);
+      }
+    printk("\n");
+  }
+#endif
+
+  /* Copy the config block to the i82593 */
+  outb(TX_BASE & 0xff, PIORL(base));
+  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base));    /* lsb */
+  outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base));	/* msb */
+  outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block));
+
+  /* reset transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
+		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
+    return(FALSE);
+
+  /* Initialize adapter's ethernet MAC address */
+  outb(TX_BASE & 0xff, PIORL(base));
+  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(WAVELAN_ADDR_SIZE, PIOP(base));	/* byte count lsb */
+  outb(0, PIOP(base));			/* byte count msb */
+  outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE);
+
+  /* reset transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
+		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
+    return(FALSE);
+
+#ifdef WAVELAN_ROAMING
+    /* If roaming is enabled, join the "Beacon Request" multicast group... */
+    /* But only if it's not in there already! */
+  if(do_roaming)
+    dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1);
+#endif	/* WAVELAN_ROAMING */
+
+  /* If any multicast address to set */
+  if(lp->mc_count)
+    {
+      struct dev_mc_list *	dmi;
+      int			addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
+
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
+	     dev->name, lp->mc_count);
+      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+	printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+	       dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+#endif
+
+      /* Initialize adapter's ethernet multicast addresses */
+      outb(TX_BASE & 0xff, PIORL(base));
+      outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+      outb(addrs_len & 0xff, PIOP(base));	/* byte count lsb */
+      outb((addrs_len >> 8), PIOP(base));	/* byte count msb */
+      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+	outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen);
+
+      /* reset transmit DMA pointer */
+      hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+      hacr_write(base, HACR_DEFAULT);
+      if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
+		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
+	return(FALSE);
+      lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
+#endif
+  return(TRUE);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Access Configuration Register, perform a software reset,
+ * and then re-enable the card's software.
+ *
+ * If I understand correctly : reset the pcmcia interface of the
+ * wavelan.
+ * (called by wv_config())
+ */
+static inline int
+wv_pcmcia_reset(device *	dev)
+{
+  int		i;
+  conf_reg_t	reg = { 0, CS_READ, CISREG_COR, 0 };
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
+#endif
+
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+      
+#ifdef DEBUG_CONFIG_INFO
+  printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n",
+	 dev->name, (u_int) reg.Value);
+#endif
+
+  reg.Action = CS_WRITE;
+  reg.Value = reg.Value | COR_SW_RESET;
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+      
+  reg.Action = CS_WRITE;
+  reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wavelan_hw_config() is called after a CARD_INSERTION event is
+ * received, to configure the wavelan hardware.
+ * Note that the reception will be enabled in wavelan->open(), so the
+ * device is configured but idle...
+ * Performs the following actions:
+ * 	1. A pcmcia software reset (using wv_pcmcia_reset())
+ *	2. A power reset (reset DMA)
+ *	3. Reset the LAN controller
+ *	4. Initialize the radio modem (using wv_mmc_init)
+ *	5. Configure LAN controller (using wv_82593_config)
+ *	6. Perform a diagnostic on the LAN controller
+ * (called by wavelan_event() & wv_hw_reset())
+ */
+static int
+wv_hw_config(device *	dev)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
+#endif
+
+#ifdef STRUCT_CHECK
+  if(wv_structuct_check() != (char *) NULL)
+    {
+      printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n",
+	     dev->name, wv_structuct_check());
+      return FALSE;
+    }
+#endif	/* STRUCT_CHECK == 1 */
+
+  /* Reset the pcmcia interface */
+  if(wv_pcmcia_reset(dev) == FALSE)
+    return FALSE;
+
+  /* Power UP the module + reset the modem + reset host adapter
+   * (in fact, reset DMA channels) */
+  hacr_write_slow(base, HACR_RESET);
+  hacr_write(base, HACR_DEFAULT);
+
+  /* Check if the the module has been powered up... */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+	     dev->name);
+#endif
+      return FALSE;
+    }
+
+  /* initialize the modem */
+  if(wv_mmc_init(dev) == FALSE)
+    return FALSE;
+
+  /* reset the LAN controller (i82593) */
+  outb(OP0_RESET, LCCR(base));
+  udelay(1000L);	/* A bit crude ! */
+
+  /* Initialize the LAN controler */
+  if((wv_82593_config(dev) == FALSE) ||
+     (wv_diag(dev) == FALSE))
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+#endif
+      return FALSE;
+    }
+
+  /* 
+   * insert code for loopback test here
+   */
+
+  /* The device is now configured */
+  lp->configured = 1;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Totally reset the wavelan and restart it.
+ * Performs the following actions:
+ * 	1. Call wv_hw_config()
+ *	2. Start the LAN controller's receive unit
+ * (called by wavelan_event(), wavelan_watchdog() and wavelan_open())
+ */
+static inline void
+wv_hw_reset(device *	dev)
+{
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
+#endif
+
+  /* If watchdog was activated, kill it ! */
+  if(lp->watchdog.prev != (timer_list *) NULL)
+    del_timer(&lp->watchdog);
+
+  lp->nresets++;
+  lp->configured = 0;
+  
+  /* Call wv_hw_config() for most of the reset & init stuff */
+  if(wv_hw_config(dev) == FALSE)
+    return;
+
+  /* start receive unit */
+  wv_ru_start(dev);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wv_pcmcia_config() is called after a CARD_INSERTION event is
+ * received, to configure the PCMCIA socket, and to make the ethernet
+ * device available to the system.
+ * (called by wavelan_event())
+ */
+static inline int
+wv_pcmcia_config(dev_link_t *	link)
+{
+  client_handle_t	handle;
+  tuple_t		tuple;
+  cisparse_t		parse;
+  struct net_device *	dev;
+  int			i;
+  u_char		buf[64];
+  win_req_t		req;
+  memreq_t		mem;
+
+  handle = link->handle;
+  dev = (device *) link->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link);
+#endif
+
+  /*
+   * This reads the card's CONFIG tuple to find its configuration
+   * registers.
+   */
+  do
+    {
+      tuple.Attributes = 0;
+      tuple.DesiredTuple = CISTPL_CONFIG;
+      i = CardServices(GetFirstTuple, handle, &tuple);
+      if(i != CS_SUCCESS)
+	break;
+      tuple.TupleData = (cisdata_t *)buf;
+      tuple.TupleDataMax = 64;
+      tuple.TupleOffset = 0;
+      i = CardServices(GetTupleData, handle, &tuple);
+      if(i != CS_SUCCESS)
+	break;
+      i = CardServices(ParseTuple, handle, &tuple, &parse);
+      if(i != CS_SUCCESS)
+	break;
+      link->conf.ConfigBase = parse.config.base;
+      link->conf.Present = parse.config.rmask[0];
+    }
+  while(0);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, ParseTuple, i);
+      link->state &= ~DEV_CONFIG_PENDING;
+      return FALSE;
+    }
+    
+  /* Configure card */
+  link->state |= DEV_CONFIG;
+  do
+    {
+      i = CardServices(RequestIO, link->handle, &link->io);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestIO, i);
+	  break;
+	}
+
+      /*
+       * Now allocate an interrupt line.  Note that this does not
+       * actually assign a handler to the interrupt.
+       */
+      i = CardServices(RequestIRQ, link->handle, &link->irq);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestIRQ, i);
+	  break;
+	}
+
+      /*
+       * This actually configures the PCMCIA socket -- setting up
+       * the I/O windows and the interrupt mapping.
+       */
+      link->conf.ConfigIndex = 1;
+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestConfiguration, i);
+	  break;
+	}
+
+      /*
+       * Allocate a 4K memory window.  Note that the dev_link_t
+       * structure provides space for one window handle -- if your
+       * device needs several windows, you'll need to keep track of
+       * the handles in your private data structure, link->priv.
+       */
+      req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+      req.Base = 0; req.Size = 0x1000;
+      req.AccessSpeed = mem_speed;
+      link->win = (window_handle_t)link->handle;
+      i = CardServices(RequestWindow, &link->win, &req);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestWindow, i);
+	  break;
+	}
+
+      dev->rmem_start = dev->mem_start =
+	  (u_long)ioremap(req.Base, 0x1000);
+      dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
+
+      mem.CardOffset = 0; mem.Page = 0;
+      i = CardServices(MapMemPage, link->win, &mem);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, MapMemPage, i);
+	  break;
+	}
+
+      /* Feed device with this info... */
+      dev->irq = link->irq.AssignedIRQ;
+      dev->base_addr = link->io.BasePort1;
+      dev->tbusy = 0;
+
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
+	     (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr);
+#endif
+
+      i = register_netdev(dev);
+      if(i != 0)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n");
+#endif
+	  break;
+	}
+    }
+  while(0);		/* Humm... Disguised goto !!! */
+
+  link->state &= ~DEV_CONFIG_PENDING;
+  /* If any step failed, release any partially configured state */
+  if(i != 0)
+    {
+      wv_pcmcia_release((u_long) link);
+      return FALSE;
+    }
+
+  /* ???? Could you explain me this, Dave ? */
+  link->dev = &((net_local *) dev->priv)->node;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * After a card is removed, wv_pcmcia_release() will unregister the net
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+wv_pcmcia_release(u_long	arg)	/* Address of the interface struct */
+{
+  dev_link_t *	link = (dev_link_t *) arg;
+  device *	dev = (device *) link->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
+#endif
+
+  /* If the device is currently in use, we won't release until it is
+   * actually closed. */
+  if(link->open)
+    {
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n",
+	     dev->name);
+#endif
+      link->state |= DEV_STALE_CONFIG;
+      return;
+    }
+
+  /* Don't bother checking to see if these succeed or not */
+  iounmap((u_char *)dev->mem_start);
+  CardServices(ReleaseWindow, link->win);
+  CardServices(ReleaseConfiguration, link->handle);
+  CardServices(ReleaseIO, link->handle, &link->io);
+  CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
+#endif
+} /* wv_pcmcia_release */
+
+/*------------------------------------------------------------------*/
+/*
+ * Sometimes, netwave_detach can't be performed following a call from
+ * cardmgr (device still open, pcmcia_release not done) and the device
+ * is put in a STALE_LINK state and remains in memory.
+ *
+ * This function run through our current list of device and attempt
+ * another time to remove them. We hope that since last time the
+ * device has properly been closed.
+ *
+ * (called by wavelan_attach() & cleanup_module())
+ */
+static void
+wv_flush_stale_links(void)
+{
+  dev_link_t *	link;		/* Current node in linked list */
+  dev_link_t *	next;		/* Next node in linked list */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list);
+#endif
+
+  /* Go through the list */
+  for (link = dev_list; link; link = next)
+    {
+      next = link->next;
+
+      /* Check if in need of being removed */
+      if((link->state & DEV_STALE_LINK) ||
+	 (! (link->state & DEV_PRESENT)))
+	wavelan_detach(link);
+
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "<- wv_flush_stale_links()\n");
+#endif
+}
+
+/************************ INTERRUPT HANDLING ************************/
+
+/*
+ * This function is the interrupt handler for the WaveLAN card. This
+ * routine will be called whenever: 
+ *	1. A packet is received.
+ *	2. A packet has successfully been transfered and the unit is
+ *	   ready to transmit another packet.
+ *	3. A command has completed execution.
+ */
+static void
+wavelan_interrupt(int		irq,
+		  void *	dev_id,
+		  struct pt_regs * regs)
+{
+  device *	dev;
+  net_local *	lp;
+  ioaddr_t	base;
+  int		status0;
+  u_int		tx_status;
+
+  if((dev = (device *)dev_id) == (device *) NULL)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
+	     irq);
+#endif
+      return;
+    }
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+#endif
+
+  lp = (net_local *) dev->priv;
+  base = dev->base_addr;
+
+  /* Prevent reentrance. What should we do here ? */
+#ifdef DEBUG_INTERRUPT_ERROR
+  if(dev->interrupt)
+    printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
+	   dev->name);
+#endif
+  dev->interrupt = 1;
+
+  /* Treat all pending interrupts */
+  while(1)
+    {
+      /* ---------------- INTERRUPT CHECKING ---------------- */
+      /*
+       * Look for the interrupt and verify the validity
+       */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
+      status0 = inb(LCSR(base));
+
+#ifdef DEBUG_INTERRUPT_INFO
+      printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, 
+	     (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT);
+      if(status0&SR0_INTERRUPT)
+	{
+	  printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" :
+		 ((status0 & SR0_EXECUTION) ? "cmd" :
+		  ((status0 & SR0_RECEPTION) ? "recv" : "unknown")),
+		 (status0 & SR0_EVENT_MASK));
+	}
+      else
+	printk("\n");
+#endif
+
+      /* Return if no actual interrupt from i82593 (normal exit) */
+      if(!(status0 & SR0_INTERRUPT))
+	break;
+
+      /* If interrupt is both Rx and Tx or none...
+       * This code in fact is there to catch the spurious interrupt
+       * when you remove the wavelan pcmcia card from the socket */
+      if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) ||
+	 ((status0 & SR0_BOTH_RX_TX) == 0x0))
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n",
+		 dev->name, status0);
+#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  break;
+	}
+
+      lp->status = status0;	/* Save current status (for commands) */
+
+      /* ----------------- RECEIVING PACKET ----------------- */
+      /*
+       * When the wavelan signal the reception of a new packet,
+       * we call wv_packet_rcv() to copy if from the buffer and
+       * send it to NET3
+       */
+      if(status0 & SR0_RECEPTION)
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name);
+#endif
+
+	  if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT)
+	    {
+#ifdef DEBUG_INTERRUPT_ERROR
+	      printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n",
+		     dev->name);
+#endif
+	      lp->stats.rx_over_errors++;
+	      lp->overrunning = 1;
+      	    }
+
+	  /* Get the packet */
+	  wv_packet_rcv(dev);
+	  lp->overrunning = 0;
+
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  continue;
+    	}
+
+      /* ---------------- COMMAND COMPLETION ---------------- */
+      /*
+       * Interrupts issued when the i82593 has completed a command.
+       * Most likely : transmission done
+       */
+
+      /* If we are already waiting elsewhere for the command to complete */
+      if(wv_wait_completed)
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
+		 dev->name);
+#endif
+
+	  /* Signal command completion */
+	  wv_wait_completed = 0;
+
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  continue;
+    	}
+
+      /* If a transmission has been done */
+      if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
+	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
+	 (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
+	{
+#ifdef DEBUG_TX_ERROR
+	  if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
+	    printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n",
+		   dev->name);
+#endif
+
+	  /* If watchdog was activated, kill it ! */
+	  if(lp->watchdog.prev != (timer_list *) NULL)
+	    del_timer(&lp->watchdog);
+
+	  /* Get transmission status */
+	  tx_status = inb(LCSR(base));
+	  tx_status |= (inb(LCSR(base)) << 8);
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n",
+		 dev->name);
+	  {
+	    u_int	rcv_bytes;
+	    u_char	status3;
+	    rcv_bytes = inb(LCSR(base));
+	    rcv_bytes |= (inb(LCSR(base)) << 8);
+	    status3 = inb(LCSR(base));
+	    printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n",
+		   tx_status, rcv_bytes, (u_int) status3);
+	  }
+#endif
+	  /* Check for possible errors */
+	  if((tx_status & TX_OK) != TX_OK)
+	    {
+	      lp->stats.tx_errors++;
+
+	      if(tx_status & TX_FRTL)
+		{
+#ifdef DEBUG_TX_ERROR
+		  printk(KERN_INFO "%s: wv_interrupt(): frame too long\n",
+			 dev->name);
+#endif
+		}
+	      if(tx_status & TX_UND_RUN)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n",
+			 dev->name);
+#endif
+		  lp->stats.tx_aborted_errors++;
+		}
+	      if(tx_status & TX_LOST_CTS)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name);
+#endif
+		  lp->stats.tx_carrier_errors++;
+		}
+	      if(tx_status & TX_LOST_CRS)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n",
+			 dev->name);
+#endif
+		  lp->stats.tx_carrier_errors++;
+		}
+	      if(tx_status & TX_HRT_BEAT)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name);
+#endif
+		  lp->stats.tx_heartbeat_errors++;
+		}
+	      if(tx_status & TX_DEFER)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n",
+			 dev->name);
+#endif
+		}
+	      /* Ignore late collisions since they're more likely to happen
+	       * here (the WaveLAN design prevents the LAN controller from
+	       * receiving while it is transmitting). We take action only when
+	       * the maximum retransmit attempts is exceeded.
+	       */
+	      if(tx_status & TX_COLL)
+		{
+		  if(tx_status & TX_MAX_COL)
+		    {
+#ifdef DEBUG_TX_FAIL
+		      printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n",
+			     dev->name);
+#endif
+		      if(!(tx_status & TX_NCOL_MASK))
+			{
+			  lp->stats.collisions += 0x10;
+			}
+		    }
+		}
+	    }	/* if(!(tx_status & TX_OK)) */
+
+	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
+	  lp->stats.tx_packets++;
+
+	  dev->tbusy = FALSE;
+	  mark_bh(NET_BH);
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
+    	} 
+      else	/* if interrupt = transmit done or retransmit done */
+	{
+#ifdef DEBUG_INTERRUPT_ERROR
+	  printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n",
+		 status0);
+#endif
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
+    	}
+    }
+  dev->interrupt = FALSE;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
+#endif
+} /* wv_interrupt */
+
+/*------------------------------------------------------------------*/
+/*
+ * Watchdog : when we start a transmission, we set a timer in the
+ * kernel.  If the transmission complete, this timer is disabled. If
+ * it expire, it try to unlock the hardware.
+ *
+ * Note : this watchdog doesn't work on the same principle as the
+ * watchdog in the ISA driver. I make it this way because the overhead
+ * of add_timer() and del_timer() is nothing and that it avoid calling
+ * the watchdog, saving some CPU... If you want to apply the same
+ * watchdog to the ISA driver, you should be a bit carefull, because
+ * of the many transmit buffers...
+ * This watchdog is also move clever, it try to abort the current
+ * command before reseting everything...
+ */
+static void
+wavelan_watchdog(u_long		a)
+{
+  device *		dev;
+  net_local *		lp;
+  ioaddr_t		base;
+  int			spin;
+
+  dev = (device *) a;
+  base = dev->base_addr;
+  lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
+#endif
+
+#ifdef DEBUG_INTERRUPT_ERROR
+  printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
+	 dev->name);
+#endif
+
+  /* We are waiting for command completion */
+  wv_wait_completed = TRUE;
+
+  /* Ask to abort the current command */
+  outb(OP0_ABORT, LCCR(base));
+
+  /* Busy wait while the LAN controller executes the command.
+   * Note : wv_wait_completed should be volatile */
+  spin = 0;
+  while(wv_wait_completed && (spin++ < 250))
+    udelay(10);
+
+  /* If the interrupt handler hasn't be called or invalid status */
+  if((wv_wait_completed) ||
+     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+    {
+      /* It seem that it wasn't enough */
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n",
+	     dev->name);
+#endif
+      wv_hw_reset(dev);
+    }
+
+#ifdef DEBUG_PSA_SHOW
+  {
+    psa_t		psa;
+    psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+    wv_psa_show(&psa);
+  }
+#endif
+#ifdef DEBUG_MMC_SHOW
+  wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82593_SHOW
+  wv_ru_show(dev);
+#endif
+
+  /* We are no more waiting for something... */
+  dev->tbusy = 0;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
+#endif
+}
+
+/********************* CONFIGURATION CALLBACKS *********************/
+/*
+ * Here are the functions called by the pcmcia package (cardmgr) and
+ * linux networking (NET3) for initialization, configuration and
+ * deinstallations of the Wavelan Pcmcia Hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Configure and start up the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "open" the device.
+ */
+static int
+wavelan_open(device *	dev)
+{
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  net_local *	lp = (net_local *)dev->priv;
+  ioaddr_t	base = dev->base_addr;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
+	 (unsigned int) dev);
+#endif
+
+  /* Check if the modem is powered up (wavelan_close() power it down */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+      /* Power up (power up time is 250us) */
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n",
+		 dev->name);
+#endif
+	  return FALSE;
+	}
+    }
+
+  /* Start reception and declare the driver ready */
+  if(!lp->configured)
+    return FALSE;
+  if(!wv_ru_start(dev))
+    wv_hw_reset(dev);		/* If problem : reset */
+  dev->interrupt = 0;
+  dev->start = 1;
+  dev->tbusy = 0;   
+
+  /* Mark the device as used */
+  link->open++;
+  MOD_INC_USE_COUNT;
+
+#ifdef WAVELAN_ROAMING
+  if(do_roaming)
+    wv_roam_init(dev);
+#endif	/* WAVELAN_ROAMING */
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Shutdown the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "close" the device.
+ */
+static int
+wavelan_close(device *	dev)
+{
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  net_local *	lp = (net_local *)dev->priv;
+  ioaddr_t	base = dev->base_addr;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
+	 (unsigned int) dev);
+#endif
+
+  /* If the device isn't open, then nothing to do */
+  if(!link->open)
+    {
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name);
+#endif
+      return 0;
+    }
+
+#ifdef WAVELAN_ROAMING
+  /* Cleanup of roaming stuff... */
+  if(do_roaming)
+    wv_roam_cleanup(dev);
+#endif	/* WAVELAN_ROAMING */
+
+  /* If watchdog was activated, kill it ! */
+  if(lp->watchdog.prev != (timer_list *) NULL)
+    del_timer(&lp->watchdog);
+
+  link->open--;
+  MOD_DEC_USE_COUNT;
+
+  /* If the card is still present */
+  if(dev->start)
+    {
+      dev->tbusy = 1;
+      dev->start = 0;
+
+      /* Stop receiving new messages and wait end of transmission */
+      wv_ru_stop(dev);
+
+      /* Power down the module */
+      hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT));
+    }
+  else
+    /* The card is no more there (flag is activated in wv_pcmcia_release) */
+    if(link->state & DEV_STALE_CONFIG)
+      wv_pcmcia_release((u_long)link);
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * We never need to do anything when a wavelan device is "initialized"
+ * by the net software, because we only register already-found cards.
+ */
+static int
+wavelan_init(device *	dev)
+{
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<>wavelan_init()\n");
+#endif
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wavelan_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device (one interface).  The device
+ * is registered with Card Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a
+ * card insertion event.
+ */
+static dev_link_t *
+wavelan_attach(void)
+{
+  client_reg_t	client_reg;	/* Register with cardmgr */
+  dev_link_t *	link;		/* Info for cardmgr */
+  device *	dev;		/* Interface generic data */
+  net_local *	lp;		/* Interface specific data */
+  int		i, ret;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "-> wavelan_attach()\n");
+#endif
+
+  /* Perform some cleanup */
+  wv_flush_stale_links();
+
+  /* Initialize the dev_link_t structure */
+  link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  memset(link, 0, sizeof(struct dev_link_t));
+
+  /* Unused for the Wavelan */
+  link->release.function = &wv_pcmcia_release;
+  link->release.data = (u_long) link;
+
+  /* The io structure describes IO port mapping */
+  link->io.NumPorts1 = 8;
+  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+  link->io.IOAddrLines = 3;
+
+  /* Interrupt setup */
+  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+  if (irq_list[0] == -1)
+    link->irq.IRQInfo2 = irq_mask;
+  else
+    for (i = 0; i < 4; i++)
+      link->irq.IRQInfo2 |= 1 << irq_list[i];
+  link->irq.Handler = wavelan_interrupt;
+
+  /* General socket configuration */
+  link->conf.Attributes = CONF_ENABLE_IRQ;
+  link->conf.Vcc = 50;
+  link->conf.IntType = INT_MEMORY_AND_IO;
+
+  /* Chain drivers */
+  link->next = dev_list;
+  dev_list = link;
+
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  memset(dev, 0x00, sizeof(struct net_device));
+  link->priv = link->irq.Instance = dev;
+
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  memset(lp, 0x00, sizeof(net_local));
+
+  /* Init specific data */
+  wv_wait_completed = 0;
+  lp->status = FALSE;
+  lp->configured = 0;
+  lp->reconfig_82593 = FALSE;
+  lp->nresets = 0;
+
+  /* Set the watchdog timer */
+  lp->watchdog.function = wavelan_watchdog;
+  lp->watchdog.data = (unsigned long) dev;
+
+  /* back links */
+  lp->link = link;
+  lp->dev = dev;
+
+  /* Standard setup for generic data */
+  ether_setup(dev);
+
+  /* wavelan NET3 callbacks */
+  dev->init = &wavelan_init;
+  dev->open = &wavelan_open;
+  dev->stop = &wavelan_close;
+  dev->hard_start_xmit = &wavelan_packet_xmit;
+  dev->get_stats = &wavelan_get_stats;
+  dev->set_multicast_list = &wavelan_set_multicast_list;
+#ifdef SET_MAC_ADDRESS
+  dev->set_mac_address = &wavelan_set_mac_address;
+#endif	/* SET_MAC_ADDRESS */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+  dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
+  dev->get_wireless_stats = wavelan_get_wireless_stats;
+#endif
+
+  /* Other specific data */
+  /* Provide storage area for device name */
+  dev->name = ((net_local *)dev->priv)->node.dev_name;
+  dev->tbusy = 1;
+  dev->mtu = WAVELAN_MTU;
+
+  /* Register with Card Services */
+  client_reg.dev_info = &dev_info;
+  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+  client_reg.EventMask = 
+    CS_EVENT_REGISTRATION_COMPLETE |
+    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+  client_reg.event_handler = &wavelan_event;
+  client_reg.Version = 0x0210;
+  client_reg.event_callback_args.client_data = link;
+
+#ifdef DEBUG_CONFIG_INFO
+  printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n");
+#endif
+
+  ret = CardServices(RegisterClient, &link->handle, &client_reg);
+  if(ret != 0)
+    {
+      cs_error(link->handle, RegisterClient, ret);
+      wavelan_detach(link);
+      return NULL;
+    }
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<- wavelan_attach()\n");
+#endif
+
+  return link;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This deletes a driver "instance".  The device is de-registered with
+ * Card Services.  If it has been released, all local data structures
+ * are freed.  Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void
+wavelan_detach(dev_link_t *	link)
+{
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link);
+#endif
+
+  /*
+   * If the device is currently configured and active, we won't
+   * actually delete it yet.  Instead, it is marked so that when the
+   * release() function is called, that will trigger a proper
+   * detach().
+   */
+  if(link->state & DEV_CONFIG)
+    {
+      /* Some others haven't done their job : give them another chance */
+      wv_pcmcia_release((u_long) link);
+      if(link->state & DEV_STALE_CONFIG)
+	{
+#ifdef DEBUG_CONFIG_INFO
+	  printk(KERN_DEBUG "wavelan_detach: detach postponed,"
+		 " '%s' still locked\n", link->dev->dev_name);
+#endif
+	  link->state |= DEV_STALE_LINK;
+	  return;
+	}
+    }
+
+  /* Break the link with Card Services */
+  if(link->handle)
+    CardServices(DeregisterClient, link->handle);
+    
+  /* Remove the interface data from the linked list */
+  if(dev_list == link)
+    dev_list = link->next;
+  else
+    {
+      dev_link_t *	prev = dev_list;
+
+      while((prev != (dev_link_t *) NULL) && (prev->next != link))
+	prev = prev->next;
+
+      if(prev == (dev_link_t *) NULL)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n");
+#endif
+	  return;
+	}
+
+      prev->next = link->next;
+    }
+
+  /* Free pieces */
+  if(link->priv)
+    {
+      device *	dev = (device *) link->priv;
+
+      /* Remove ourselves from the kernel list of ethernet devices */
+      /* Warning : can't be called from interrupt, timer or wavelan_close() */
+      if(link->dev != NULL)
+	unregister_netdev(dev);
+      link->dev = NULL;
+
+      if(dev->priv)
+	{
+	  /* Sound strange, but safe... */
+	  ((net_local *) dev->priv)->link = (dev_link_t *) NULL;
+	  ((net_local *) dev->priv)->dev = (device *) NULL;
+	  kfree(dev->priv);
+	}
+      kfree(link->priv);
+    }
+  kfree(link);
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<- wavelan_detach()\n");
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * The card status event handler. Mostly, this schedules other stuff
+ * to run after an event is received. A CARD_REMOVAL event also sets
+ * some flags to discourage the net drivers from trying to talk to the
+ * card any more.
+ */
+static int
+wavelan_event(event_t		event,		/* The event received */
+	      int		priority,
+	      event_callback_args_t *	args)
+{
+  dev_link_t *	link = (dev_link_t *) args->client_data;
+  device *	dev = (device *) link->priv;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "->wavelan_event(): %s\n",
+	 ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" :
+	  ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" :
+	   ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" :
+	    ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" :
+	     ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" :
+	      ((event == CS_EVENT_PM_RESUME) ? "pm resume" :
+	       ((event == CS_EVENT_CARD_RESET) ? "card reset" :
+		"unknown"))))))));
+#endif
+
+    switch(event)
+      {
+      case CS_EVENT_REGISTRATION_COMPLETE:
+#ifdef DEBUG_CONFIG_INFO
+	printk(KERN_DEBUG "wavelan_cs: registration complete\n");
+#endif
+	break;
+
+      case CS_EVENT_CARD_REMOVAL:
+	/* Oups ! The card is no more there */
+	link->state &= ~DEV_PRESENT;
+	if(link->state & DEV_CONFIG)
+	  {
+	    /* Accept no more transmissions */
+      	    dev->tbusy = 1; dev->start = 0;
+
+	    /* Release the card */
+	    wv_pcmcia_release((u_long) link);
+	  }
+	break;
+
+      case CS_EVENT_CARD_INSERTION:
+	/* Reset and configure the card */
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	if(wv_pcmcia_config(link) &&
+	   wv_hw_config(dev))
+	  wv_init_info(dev);
+	else
+	  dev->irq = 0;
+	break;
+
+      case CS_EVENT_PM_SUSPEND:
+	/* NB: wavelan_close will be called, but too late, so we are
+	 * obliged to close nicely the wavelan here. David, could you
+	 * close the device before suspending them ? And, by the way,
+	 * could you, on resume, add a "route add -net ..." after the
+	 * ifconfig up ??? Thanks... */
+
+	/* Stop receiving new messages and wait end of transmission */
+	wv_ru_stop(dev);
+
+	/* Power down the module */
+	hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT));
+
+	/* The card is now suspended */
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+      case CS_EVENT_RESET_PHYSICAL:
+    	if(link->state & DEV_CONFIG)
+	  {
+      	    if(link->open)
+	      {
+		dev->tbusy = 1;
+		dev->start = 0;
+	      }
+      	    CardServices(ReleaseConfiguration, link->handle);
+	  }
+	break;
+
+      case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+      case CS_EVENT_CARD_RESET:
+	if(link->state & DEV_CONFIG)
+	  {
+      	    CardServices(RequestConfiguration, link->handle, &link->conf);
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
+	      {
+		wv_hw_reset(dev);
+		dev->tbusy = 0;
+		dev->start = 1;
+	      }
+	  }
+	break;
+    }
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<-wavelan_event()\n");
+#endif
+  return 0;
+}
+
+/****************************** MODULE ******************************/
+/*
+ * Module entry points : insertion & removal
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Module insertion : initialisation of the module.
+ * Register the card with cardmgr...
+ */
+static int __init
+init_wavelan_cs(void)
+{
+  servinfo_t	serv;
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "-> init_wavelan_cs()\n");
+#ifdef DEBUG_VERSION_SHOW
+  printk(KERN_DEBUG "%s", version);
+#endif
+#endif
+
+  CardServices(GetCardServicesInfo, &serv);
+  if(serv.Revision != CS_RELEASE_CODE)
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n");
+#endif
+      return -1;
+    }
+
+  register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach);
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "<- init_wavelan_cs()\n");
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Module removal
+ */
+static void __exit
+exit_wavelan_cs(void)
+{
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "-> cleanup_module()\n");
+#endif
+#ifdef DEBUG_BASIC_SHOW
+  printk(KERN_NOTICE "wavelan_cs: unloading\n");
+#endif
+
+  /* Do some cleanup of the device list */
+  wv_flush_stale_links();
+
+  /* If there remain some devices... */
+#ifdef DEBUG_CONFIG_ERRORS
+  if(dev_list != NULL)
+    {
+      /* Honestly, if this happen we are in a deep s**t */
+      printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n");
+      printk(KERN_INFO "Please flush your disks and reboot NOW !\n");
+    }
+#endif
+
+  unregister_pccard_driver(&dev_info);
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "<- cleanup_module()\n");
+#endif
+}
+
+module_init(init_wavelan_cs);
+module_exit(exit_wavelan_cs);
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.3.22/linux/drivers/net/pcmcia/wavelan_cs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,773 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ *
+ * This file contain all definition and declarations necessary for the
+ * wavelan pcmcia driver. This file is a private header, so it should
+ * be included only on wavelan_cs.c !!!
+ */
+
+#ifndef WAVELAN_CS_H
+#define WAVELAN_CS_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * This driver provide a Linux interface to the Wavelan Pcmcia hardware
+ * The Wavelan is a product of Lucent (http://www.wavelan.com/).
+ * This division was formerly part of NCR and then AT&T.
+ * Wavelan are also distributed by DEC (RoamAbout DS)...
+ *
+ * To know how to use this driver, read the PCMCIA HOWTO.
+ * If you want to exploit the many other fonctionalities, look comments
+ * in the code...
+ *
+ * This driver is the result of the effort of many peoples (see below).
+ */
+
+/* ------------------------ SPECIFIC NOTES ------------------------ */
+/*
+ * Web page
+ * --------
+ *	I try to maintain a web page with the Wireless LAN Howto at :
+ *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
+ *
+ * Debugging and options
+ * ---------------------
+ *	You will find below a set of '#define" allowing a very fine control
+ *	on the driver behaviour and the debug messages printed.
+ *	The main options are :
+ *	o WAVELAN_ROAMING, for the experimental roaming support.
+ *	o SET_PSA_CRC, to have your card correctly recognised by
+ *	  an access point and the Point-to-Point diagnostic tool.
+ *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
+ *	  (otherwise we always start afresh with some defaults)
+ *
+ * wavelan_cs.o is darn too big
+ * -------------------------
+ *	That's true ! There is a very simple way to reduce the driver
+ *	object by 33% (yes !). Comment out the following line :
+ *		#include <linux/wireless.h>
+ *	Other compile options can also reduce the size of it...
+ *
+ * MAC address and hardware detection :
+ * ----------------------------------
+ *	The detection code of the wavelan chech that the first 3
+ *	octets of the MAC address fit the company code. This type of
+ *	detection work well for AT&T cards (because the AT&T code is
+ *	hardcoded in wavelan.h), but of course will fail for other
+ *	manufacturer.
+ *
+ *	If you are sure that your card is derived from the wavelan,
+ *	here is the way to configure it :
+ *	1) Get your MAC address
+ *		a) With your card utilities (wfreqsel, instconf, ...)
+ *		b) With the driver :
+ *			o compile the kernel with DEBUG_CONFIG_INFO enabled
+ *			o Boot and look the card messages
+ *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
+ *	3) Compile & verify
+ *	4) Send me the MAC code - I will include it in the next version...
+ *
+ */
+
+/* --------------------- WIRELESS EXTENSIONS --------------------- */
+/*
+ * This driver is the first one to support "wireless extensions".
+ * This set of extensions provide you some way to control the wireless
+ * caracteristics of the hardware in a standard way and support for
+ * applications for taking advantage of it (like Mobile IP).
+ *
+ * You will need to enable the CONFIG_NET_RADIO define in the kernel
+ * configuration to enable the wireless extensions (this is the one
+ * giving access to the radio network device choice).
+ *
+ * It might also be a good idea as well to fetch the wireless tools to
+ * configure the device and play a bit.
+ */
+
+/* ---------------------------- FILES ---------------------------- */
+/*
+ * wavelan_cs.c :	The actual code for the driver - C functions
+ *
+ * wavelan_cs.h :	Private header : local types / vars for the driver
+ *
+ * wavelan.h :		Description of the hardware interface & structs
+ *
+ * i82593.h :		Description if the Ethernet controler
+ */
+
+/* --------------------------- HISTORY --------------------------- */
+/*
+ * The history of the Wavelan drivers is as complicated as history of
+ * the Wavelan itself (NCR -> AT&T -> Lucent).
+ *
+ * All started with Anders Klemets <klemets@paul.rutgers.edu>,
+ * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * Welling <welling@paul.rutgers.edu> had also worked on it.
+ * Keith Moore modify this for the Pcmcia hardware.
+ * 
+ * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
+ * and add specific Pcmcia support (there is currently no equivalent
+ * of the PCMCIA package under BSD...).
+ *
+ * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to FreeBSD.
+ *
+ * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ *
+ * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * (with help of the BSDI PCMCIA driver) for PCMCIA.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
+ * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
+ * Pcmcia package (+ bug corrections).
+ *
+ * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
+ * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * for Wireless Extensions and full support of frequency selection
+ * cards. Now, I'm doing the same to the Pcmcia driver + some
+ * reorganisation.
+ * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
+ * much needed informations on the Wavelan hardware.
+ */
+
+/* By the way : for the copyright & legal stuff :
+ * Almost everybody wrote code under GNU or BSD license (or alike),
+ * and want that their original copyright remain somewhere in the
+ * code (for myself, I go with the GPL).
+ * Nobody want to take responsibility for anything, except the fame...
+ */
+
+/* --------------------------- CREDITS --------------------------- */
+/*
+ * Credits:
+ *    Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and
+ *	Loeke Brederveld of Lucent for providing extremely useful
+ *	information about WaveLAN PCMCIA hardware
+ *
+ *    This driver is based upon several other drivers, in particular:
+ *	David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
+ *	Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
+ *	Anders Klemets' PCMCIA WaveLAN adapter driver
+ *	Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
+ *
+ * Additional Credits:
+ *
+ *    This software was originally developed under Linux 1.2.3
+ *	(Slackware 2.0 distribution).
+ *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
+ *	HP OmniBook 4000 & 5500.
+ *
+ *    It is based on other device drivers and information either written
+ *    or supplied by:
+ *	James Ashton (jaa101@syseng.anu.edu.au),
+ *	Ajay Bakre (bakre@paul.rutgers.edu),
+ *	Donald Becker (becker@super.org),
+ *	Jim Binkley <jrb@cs.pdx.edu>,
+ *	Loeke Brederveld <lbrederv@wavelan.com>,
+ *	Allan Creighton (allanc@cs.su.oz.au),
+ *	Brent Elphick <belphick@uwaterloo.ca>,
+ *	Joe Finney <joe@comp.lancs.ac.uk>,
+ *	Matthew Geier (matthew@cs.su.oz.au),
+ *	Remo di Giovanni (remo@cs.su.oz.au),
+ *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
+ *	David Hinds <dhinds@hyper.stanford.edu>,
+ *	Jan Hoogendoorn (c/o marteijn@lucent.com),
+ *      Bruce Janson <bruce@cs.usyd.edu.au>,
+ *	Anthony D. Joseph <adj@lcs.mit.edu>,
+ *	Anders Klemets (klemets@paul.rutgers.edu),
+ *	Yunzhou Li <yunzhou@strat.iol.unh.edu>,
+ *	Marc Meertens (mmeertens@lucent.com),
+ *	Keith Moore,
+ *	Robert Morris (rtm@das.harvard.edu),
+ *	Ian Parkin (ian@cs.su.oz.au),
+ *	John Rosenberg (johnr@cs.su.oz.au),
+ *	George Rossi (george@phm.gov.au),
+ *	Arthur Scott (arthur@cs.su.oz.au),
+ *	Stanislav Sinyagin <stas@isf.ru>
+ *	Peter Storey,
+ *	Jean Tourrilhes <jt@hpl.hp.com>,
+ *	Girish Welling (welling@paul.rutgers.edu)
+ *	Clark Woodworth <clark@hiway1.exit109.com>
+ *	Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ */
+
+/* ------------------------- IMPROVEMENTS ------------------------- */
+/*
+ * I proudly present :
+ *
+ * Changes made in 2.8.22 :
+ * ----------------------
+ *	- improved wv_set_multicast_list
+ *	- catch spurious interrupt
+ *	- correct release of the device
+ *
+ * Changes mades in release :
+ * ------------------------
+ *	- Reorganisation of the code, function name change
+ *	- Creation of private header (wavelan_cs.h)
+ *	- Reorganised debug messages
+ *	- More comments, history, ...
+ *	- Configure earlier (in "insert" instead of "open")
+ *        and do things only once
+ *	- mmc_init : configure the PSA if not done
+ *	- mmc_init : 2.00 detection better code for 2.00 init
+ *	- better info at startup
+ *	- Correct a HUGE bug (volatile & uncalibrated busy loop)
+ *	  in wv_82593_cmd => config speedup
+ *	- Stop receiving & power down on close (and power up on open)
+ *	  use "ifconfig down" & "ifconfig up ; route add -net ..."
+ *	- Send packets : add watchdog instead of pooling
+ *	- Receive : check frame wrap around & try to recover some frames
+ *	- wavelan_set_multicast_list : avoid reset
+ *	- add wireless extensions (ioctl & get_wireless_stats)
+ *	  get/set nwid/frequency on fly, info for /proc/net/wireless
+ *	- Supress useless stuff from lp (net_local), but add link
+ *	- More inlines
+ *	- Lot of others minor details & cleanups
+ *
+ * Changes made in second release :
+ * ------------------------------
+ *	- Optimise wv_85893_reconfig stuff, fix potential problems
+ *	- Change error values for ioctl
+ *	- Non blocking wv_ru_stop() + call wv_reset() in case of problems
+ *	- Remove development printk from wavelan_watchdog()
+ *	- Remove of the watchdog to wavelan_close instead of wavelan_release
+ *	  fix potential problems...
+ *	- Start debugging suspend stuff (but it's still a bit weird)
+ *	- Debug & optimize dump header/packet in Rx & Tx (debug)
+ *	- Use "readb" and "writeb" to be kernel 2.1 compliant
+ *	- Better handling of bogus interrupts
+ *	- Wireless extension : SETSPY and GETSPY
+ *	- Remove old stuff (stats - for those needing it, just ask me...)
+ *	- Make wireless extensions optional
+ *
+ * Changes made in third release :
+ * -----------------------------
+ *	- cleanups & typos
+ *	- modif wireless ext (spy -> only one pointer)
+ *	- new private ioctl to set/get quality & level threshold
+ *	- Init : correct default value of level threshold for pcmcia
+ *	- kill watchdog in hw_reset
+ *	- more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
+ *	- Add message level (debug stuff in /var/adm/debug & errors not
+ *	  displayed at console and still in /var/adm/messages)
+ *
+ * Changes made in fourth release :
+ * ------------------------------
+ *	- multicast support (yes !) thanks to Yongguang Zhang.
+ *
+ * Changes made in fifth release (2.9.0) :
+ * -------------------------------------
+ *	- Revisited multicast code (it was mostly wrong).
+ *	- protect code in wv_82593_reconfig with dev->tbusy (oups !)
+ *
+ * Changes made in sixth release (2.9.1a) :
+ * --------------------------------------
+ *	- Change the detection code for multi manufacturer code support
+ *	- Correct bug (hang kernel) in init when we were "rejecting" a card 
+ *
+ * Changes made in seventh release (2.9.1b) :
+ * ----------------------------------------
+ *	- Update to wireless extensions changes
+ *	- Silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made in eigth release :
+ * -----------------------------
+ *	- Small bug in debug code (probably not the last one...)
+ *	- 1.2.13 support (thanks to Clark Woodworth)
+ *
+ * Changes made for release in 2.9.2b :
+ * ----------------------------------
+ *	- Level threshold is now a standard wireless extension (version 4 !)
+ *	- modules parameters types for kernel > 2.1.17
+ *	- updated man page
+ *	- Others cleanup from David Hinds
+ *
+ * Changes made for release in 2.9.5 :
+ * ---------------------------------
+ *	- byte count stats (courtesy of David Hinds)
+ *	- Remove dev_tint stuff (courtesy of David Hinds)
+ *	- Others cleanup from David Hinds
+ *	- Encryption setting from Brent Elphick (thanks a lot !)
+ *	- 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
+ *
+ * Changes made for release in 2.9.6 :
+ * ---------------------------------
+ *	- fix bug : no longuer disable watchdog in case of bogus interrupt
+ *	- increase timeout in config code for picky hardware
+ *	- mask unused bits in status (Wireless Extensions)
+ *
+ * Changes integrated by Justin Seger <jseger@MIT.EDU> & David Hinds :
+ * -----------------------------------------------------------------
+ *	- Roaming "hack" from Joe Finney <joe@comp.lancs.ac.uk>
+ *	- PSA CRC code from Bob Gray <rgray@bald.cs.dartmouth.edu>
+ *	- Better initialisation of the i82593 controller
+ *	  from Joseph K. O'Sullivan <josullvn+@cs.cmu.edu>
+ *
+ * Changes made for release in 3.0.10 :
+ * ----------------------------------
+ *	- Fix eject "hang" of the driver under 2.2.X :
+ *		o create wv_flush_stale_links()
+ *		o Rename wavelan_release to wv_pcmcia_release & move up
+ *		o move unregister_netdev to wavelan_detach()
+ *		o wavelan_release() no longer call wavelan_detach()
+ *		o Supress "release" timer
+ *		o Other cleanups & fixes
+ *	- New MAC address in the probe
+ *	- Reorg PSA_CRC code (endian neutral & cleaner)
+ *	- Correct initialisation of the i82593 from Lucent manual
+ *	- Put back the watchdog, with larger timeout
+ *	- TRANSMIT_NO_CRC is a "normal" error, so recover from it
+ *	  from Derrick J Brashear <shadow@dementia.org>
+ *	- Better handling of TX and RX normal failure conditions
+ *	- #ifdef out all the roaming code
+ *	- Add ESSID & "AP current address" ioctl stubs
+ *	- General cleanup of the code
+ *
+ * Changes made for release in 3.0.13 :
+ * ----------------------------------
+ *	- Re-enable compilation of roaming code by default, but with
+ *	  do_roaming = 0
+ *	- Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather
+ *	  at the demand of John Carol Langford <jcl@gs176.sp.cs.cmu.edu>
+ *	- Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff.
+ *
+ * Changes made for release in 3.0.15 :
+ * ----------------------------------
+ *	- Change e-mail and web page addresses
+ *	- Watchdog timer is now correctly expressed in HZ, not in jiffies
+ *	- Add channel number to the list of frequencies in range
+ *	- Add the (short) list of bit-rates in range
+ *	- Developp a new sensitivity... (sens.value & sens.fixed)
+ *
+ * Changes made for release in 3.1.2 :
+ * ---------------------------------
+ *	- Fix check for root permission (break instead of exit)
+ *	- New nwid & encoding setting (Wireless Extension 9)
+ *
+ * Wishes & dreams:
+ * ----------------
+ *	- Cleanup and integrate the roaming code
+ *	  (std debug, set DomainID, decay avg and co...)
+ */
+
+/***************************** INCLUDES *****************************/
+
+/* Linux headers that we need */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>		/* Wireless extensions */
+#endif
+
+/* Pcmcia headers that we need */
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/version.h>
+
+/* Wavelan declarations */
+#include "i82593.h"	/* Definitions for the Intel chip */
+
+#include "wavelan.h"	/* Others bits of the hardware */
+
+/************************** DRIVER OPTIONS **************************/
+/*
+ * `#define' or `#undef' the following constant to change the behaviour
+ * of the driver...
+ */
+#define WAVELAN_ROAMING		/* Include experimental roaming code */
+#undef WAVELAN_ROAMING_EXT	/* Enable roaming wireless extensions */
+#undef SET_PSA_CRC		/* Set the CRC in PSA (slower) */
+#define USE_PSA_CONFIG		/* Use info from the PSA */
+#undef STRUCT_CHECK		/* Verify padding of structures */
+#undef EEPROM_IS_PROTECTED	/* Doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical) */
+#undef SET_MAC_ADDRESS		/* Experimental */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+/* Warning : these stuff will slow down the driver... */
+#define WIRELESS_SPY		/* Enable spying addresses */
+#undef HISTOGRAM		/* Enable histogram of sig level... */
+#endif
+
+/****************************** DEBUG ******************************/
+
+#undef DEBUG_MODULE_TRACE	/* Module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE	/* Calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE	/* Calls to handler */
+#undef DEBUG_INTERRUPT_INFO	/* type of interrupt & so on */
+#define DEBUG_INTERRUPT_ERROR	/* problems */
+#undef DEBUG_CONFIG_TRACE	/* Trace the config functions */
+#undef DEBUG_CONFIG_INFO	/* What's going on... */
+#define DEBUG_CONFIG_ERRORS	/* Errors on configuration */
+#undef DEBUG_TX_TRACE		/* Transmission calls */
+#undef DEBUG_TX_INFO		/* Header of the transmited packet */
+#undef DEBUG_TX_FAIL		/* Normal failure conditions */
+#define DEBUG_TX_ERROR		/* Unexpected conditions */
+#undef DEBUG_RX_TRACE		/* Transmission calls */
+#undef DEBUG_RX_INFO		/* Header of the transmited packet */
+#undef DEBUG_RX_FAIL		/* Normal failure conditions */
+#define DEBUG_RX_ERROR		/* Unexpected conditions */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
+#undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
+#undef DEBUG_IOCTL_INFO		/* Various debug info */
+#define DEBUG_IOCTL_ERROR	/* What's going wrong */
+#define DEBUG_BASIC_SHOW	/* Show basic startup info */
+#undef DEBUG_VERSION_SHOW	/* Print version info */
+#undef DEBUG_PSA_SHOW		/* Dump psa to screen */
+#undef DEBUG_MMC_SHOW		/* Dump mmc to screen */
+#undef DEBUG_SHOW_UNUSED	/* Show also unused fields */
+#undef DEBUG_I82593_SHOW	/* Show i82593 status */
+#undef DEBUG_DEVICE_SHOW	/* Show device parameters */
+
+/************************ CONSTANTS & MACROS ************************/
+
+#ifdef DEBUG_VERSION_SHOW
+static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+#endif
+
+/* Watchdog temporisation */
+#define	WATCHDOG_JIFFIES	(256*HZ/100)
+
+/* Fix a bug in some old wireless extension definitions */
+#ifndef IW_ESSID_MAX_SIZE
+#define IW_ESSID_MAX_SIZE	32
+#endif
+
+/* ------------------------ PRIVATE IOCTL ------------------------ */
+
+#define SIOCSIPQTHR	SIOCDEVPRIVATE		/* Set quality threshold */
+#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1	/* Get quality threshold */
+#define SIOCSIPROAM     SIOCDEVPRIVATE + 2      /* Set roaming state */
+#define SIOCGIPROAM     SIOCDEVPRIVATE + 3      /* Get roaming state */
+
+#define SIOCSIPHISTO	SIOCDEVPRIVATE + 6	/* Set histogram ranges */
+#define SIOCGIPHISTO	SIOCDEVPRIVATE + 7	/* Get histogram values */
+
+/*************************** WaveLAN Roaming  **************************/
+#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
+
+#define WAVELAN_ROAMING_DEBUG	 0	/* 1 = Trace of handover decisions */
+					/* 2 = Info on each beacon rcvd... */
+#define MAX_WAVEPOINTS		7	/* Max visible at one time */
+#define WAVEPOINT_HISTORY	5	/* SNR sample history slow search */
+#define WAVEPOINT_FAST_HISTORY	2	/* SNR sample history fast search */
+#define SEARCH_THRESH_LOW	10	/* SNR to enter cell search */
+#define SEARCH_THRESH_HIGH	13	/* SNR to leave cell search */
+#define WAVELAN_ROAMING_DELTA	1	/* Hysteresis value (+/- SNR) */
+#define CELL_TIMEOUT		2*HZ	/* in jiffies */
+
+#define FAST_CELL_SEARCH	1	/* Boolean values... */
+#define NWID_PROMISC		1	/* for code clarity. */
+
+typedef struct wavepoint_beacon
+{
+  unsigned char		dsap,		/* Unused */
+			ssap,		/* Unused */
+			ctrl,		/* Unused */
+			O,U,I,		/* Unused */
+			spec_id1,	/* Unused */
+			spec_id2,	/* Unused */
+			pdu_type,	/* Unused */
+			seq;		/* WavePoint beacon sequence number */
+  unsigned short	domain_id,	/* WavePoint Domain ID */
+			nwid;		/* WavePoint NWID */
+} wavepoint_beacon;
+
+typedef struct wavepoint_history
+{
+  unsigned short	nwid;		/* WavePoint's NWID */
+  int			average_slow;	/* SNR running average */
+  int			average_fast;	/* SNR running average */
+  unsigned char	  sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */
+  unsigned char		qualptr;	/* Index into ringbuffer */
+  unsigned char		last_seq;	/* Last seq. no seen for WavePoint */
+  struct wavepoint_history *next;	/* Next WavePoint in table */
+  struct wavepoint_history *prev;	/* Previous WavePoint in table */
+  unsigned long		last_seen;	/* Time of last beacon recvd, jiffies */
+} wavepoint_history;
+
+struct wavepoint_table
+{
+  wavepoint_history	*head;		/* Start of ringbuffer */
+  int			num_wavepoints;	/* No. of WavePoints visible */
+  unsigned char		locked;		/* Table lock */
+};
+
+#endif	/* WAVELAN_ROAMING */
+
+/****************************** TYPES ******************************/
+
+/* Shortcuts */
+typedef struct net_device	device;
+typedef struct net_device_stats	en_stats;
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef struct iw_freq		iw_freq;
+typedef struct net_local	net_local;
+typedef struct timer_list	timer_list;
+
+/* Basic types */
+typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
+
+/*
+ * Static specific data for the interface.
+ *
+ * For each network interface, Linux keep data in two structure. "device"
+ * keep the generic data (same format for everybody) and "net_local" keep
+ * the additional specific data.
+ * Note that some of this specific data is in fact generic (en_stats, for
+ * example).
+ */
+struct net_local
+{
+  dev_node_t 	node;		/* ???? What is this stuff ???? */
+  device *	dev;		/* Reverse link... */
+  dev_link_t *	link;		/* pcmcia structure */
+  en_stats	stats;		/* Ethernet interface statistics */
+  int		nresets;	/* Number of hw resets */
+  u_char	configured;	/* If it is configured */
+  u_char	reconfig_82593;	/* Need to reconfigure the controler */
+  u_char	promiscuous;	/* Promiscuous mode */
+  u_char	allmulticast;	/* All Multicast mode */
+  int		mc_count;	/* Number of multicast addresses */
+  timer_list	watchdog;	/* To avoid blocking state */
+
+  u_char        status;		/* Current i82593 status */
+  int   	stop;		/* Current i82593 Stop Hit Register */
+  int   	rfp;		/* Last DMA machine receive pointer */
+  int		overrunning;	/* Receiver overrun flag */
+
+#ifdef WIRELESS_EXT
+  iw_stats	wstats;		/* Wireless specific stats */
+#endif
+
+#ifdef WIRELESS_SPY
+  int		spy_number;		/* Number of addresses to spy */
+  mac_addr	spy_address[IW_MAX_SPY];	/* The addresses to spy */
+  iw_qual	spy_stat[IW_MAX_SPY];		/* Statistics gathered */
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+  int		his_number;		/* Number of intervals */
+  u_char	his_range[16];		/* Boundaries of interval ]n-1; n] */
+  u_long	his_sum[16];		/* Sum in interval */
+#endif	/* HISTOGRAM */
+#ifdef WAVELAN_ROAMING
+  u_long	domain_id;	/* Domain ID we lock on for roaming */
+  int		filter_domains;	/* Check Domain ID of beacon found */
+ struct wavepoint_table	wavepoint_table;	/* Table of visible WavePoints*/
+  wavepoint_history *	curr_point;		/* Current wavepoint */
+  int			cell_search;		/* Searching for new cell? */
+  struct timer_list	cell_timer;		/* Garbage collection */
+#endif	/* WAVELAN_ROAMING */
+};
+
+/**************************** PROTOTYPES ****************************/
+
+#ifdef WAVELAN_ROAMING
+/* ---------------------- ROAMING SUBROUTINES -----------------------*/
+
+wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp);
+wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp);
+void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp);
+void wl_cell_expiry(unsigned long data);
+wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp);
+void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq);
+void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp);
+void wv_nwid_filter(unsigned char mode, net_local *lp);
+void wv_roam_init(struct net_device *dev);
+void wv_roam_cleanup(struct net_device *dev);
+#endif	/* WAVELAN_ROAMING */
+
+/* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline unsigned long	/* flags */
+	wv_splhi(void);		/* Disable interrupts */
+static inline void
+	wv_splx(unsigned long);	/* ReEnable interrupts : flags */
+static void
+	cs_error(client_handle_t, /* Report error to cardmgr */
+		 int,
+		 int);
+/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
+static inline u_char		/* data */
+	hasr_read(u_long);	/* Read the host interface : base address */
+static inline void
+	hacr_write(u_long,	/* Write to host interface : base address */
+		   u_char),	/* data */
+	hacr_write_slow(u_long,
+		   u_char);
+static void
+	psa_read(device *,	/* Read the Parameter Storage Area */
+		 int,		/* offset in PSA */
+		 u_char *,	/* buffer to fill */
+		 int),		/* size to read */
+	psa_write(device *,	/* Write to the PSA */
+		  int,		/* Offset in psa */
+		  u_char *,	/* Buffer in memory */
+		  int);		/* Length of buffer */
+static inline void
+	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control */
+		u_short,
+		u_char),
+	mmc_write(u_long,	/* Write n bytes to the MMC */
+		  u_char,
+		  u_char *,
+		  int);
+static inline u_char		/* Read 1 byte from the MMC */
+	mmc_in(u_long,
+	       u_short);
+static inline void
+	mmc_read(u_long,	/* Read n bytes from the MMC */
+		 u_char,
+		 u_char *,
+		 int),
+	fee_wait(u_long,	/* Wait for frequency EEprom : base address */
+		 int,		/* Base delay to wait for */
+		 int);		/* Number of time to wait */
+static void
+	fee_read(u_long,	/* Read the frequency EEprom : base address */
+		 u_short,	/* destination offset */
+		 u_short *,	/* data buffer */
+		 int);		/* number of registers */
+/* ---------------------- I82593 SUBROUTINES ----------------------- */
+static int
+	wv_82593_cmd(device *,	/* synchronously send a command to i82593 */ 
+		     char *,
+		     int,
+		     int);
+static inline int
+	wv_diag(device *);	/* Diagnostique the i82593 */
+static int
+	read_ringbuf(device *,	/* Read a receive buffer */
+		     int,
+		     char *,
+		     int);
+static inline void
+	wv_82593_reconfig(device *);	/* Reconfigure the controler */
+/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
+static inline void
+	wv_init_info(device *);	/* display startup info */
+/* ------------------- IOCTL, STATS & RECONFIG ------------------- */
+static en_stats	*
+	wavelan_get_stats(device *);	/* Give stats /proc/net/dev */
+/* ----------------------- PACKET RECEPTION ----------------------- */
+static inline int
+	wv_start_of_frame(device *,	/* Seek beggining of current frame */
+			  int,	/* end of frame */
+			  int);	/* start of buffer */
+static inline void
+	wv_packet_read(device *,	/* Read a packet from a frame */
+		       int,
+		       int),
+	wv_packet_rcv(device *);	/* Read all packets waiting */
+/* --------------------- PACKET TRANSMISSION --------------------- */
+static inline void
+	wv_packet_write(device *,	/* Write a packet to the Tx buffer */
+			void *,
+			short);
+static int
+	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet */
+			    device *);
+/* -------------------- HARDWARE CONFIGURATION -------------------- */
+static inline int
+	wv_mmc_init(device *);	/* Initialize the modem */
+static int
+	wv_ru_stop(device *),	/* Stop the i82593 receiver unit */
+	wv_ru_start(device *);	/* Start the i82593 receiver unit */
+static int
+	wv_82593_config(device *);	/* Configure the i82593 */
+static inline int
+	wv_pcmcia_reset(device *);	/* Reset the pcmcia interface */
+static int
+	wv_hw_config(device *);	/* Reset & configure the whole hardware */
+static inline void
+	wv_hw_reset(device *);	/* Same, + start receiver unit */
+static inline int
+	wv_pcmcia_config(dev_link_t *);	/* Configure the pcmcia interface */
+static void
+	wv_pcmcia_release(u_long),	/* Remove a device */
+	wv_flush_stale_links(void);	/* "detach" all possible devices */
+/* ---------------------- INTERRUPT HANDLING ---------------------- */
+static void
+wavelan_interrupt(int,	/* Interrupt handler */
+		  void *,
+		  struct pt_regs *);
+static void
+	wavelan_watchdog(u_long);	/* Transmission watchdog */
+/* ------------------- CONFIGURATION CALLBACKS ------------------- */
+static int
+	wavelan_open(device *),		/* Open the device */
+	wavelan_close(device *),	/* Close the device */
+	wavelan_init(device *);		/* Do nothing */
+static dev_link_t *
+	wavelan_attach(void);		/* Create a new device */
+static void
+	wavelan_detach(dev_link_t *);	/* Destroy a removed device */
+static int
+	wavelan_event(event_t,		/* Manage pcmcia events */
+		      int,
+		      event_callback_args_t *);
+
+/**************************** VARIABLES ****************************/
+
+static dev_info_t dev_info = "wavelan_cs";
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
+
+/* WARNING : the following variable MUST be volatile
+ * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
+static volatile int	wv_wait_completed = 0;
+
+/*
+ * Parameters that can be set with 'insmod'
+ * The exact syntax is 'insmod wavelan_cs.o <var>=<value>'
+ */
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */
+static int	irq_mask = 0xdeb8;
+static int 	irq_list[4] = { -1 };
+
+/* Shared memory speed, in ns */
+static int	mem_speed = 0;
+
+/* New module interface */
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(mem_speed, "i");
+
+#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
+/* Enable roaming mode ? No ! Please keep this to 0 */
+static int	do_roaming = 0;
+MODULE_PARM(do_roaming, "i");
+#endif	/* WAVELAN_ROAMING */
+
+#endif	/* WAVELAN_CS_H */
+
diff -u --recursive --new-file v2.3.22/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- v2.3.22/linux/drivers/net/pcmcia/xirc2ps_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Wed Oct 20 21:33:12 1999
@@ -0,0 +1,2364 @@
+/* [xirc2ps_cs.c wk 14.04.97] (1.31 1998/12/09 19:32:55)
+ * Xircom Creditcard Ethernet Adapter IIps driver
+ *
+ * This driver works for the CE2, CEM28, CEM33, CE3 and CEM56 cards.
+ * The CEM56 has some problems, but it works.
+ * The CEII card with the 14k4 modem and other old cards do not work.
+ *
+ * Written by Werner Koch (werner.koch@guug.de),
+ * based on David Hinds skeleton driver.
+ *
+ * You can get the latest driver revision from
+ *	"http://www.d.shuttle.de/isil/xircom/xirc2ps.html"
+ *
+ * Please report bugs to: "xircom-bugs@isil.d.shuttle.de"
+ *
+ * A bug fix for the CEM56 to use modem and ethernet simultaneously
+ * was provided by Koen Van Herck (Koen.Van.Herck@xircom.com).
+ *
+ * If your card locks up you should use the option "lockup_hack=1";
+ * this may solve the problem but violates a kernel timing convention
+ * (Thanks to David Luyer).
+ *
+ * Thanks to David Hinds for the PCMCIA package, Donald Becker for some
+ * advice, Xircom for providing specs and help, 4PC GmbH Duesseldorf for
+ * providing some hardware and last not least to all folks who helped to
+ * develop this driver.
+ *
+ * For those, who are willing to do alpha testing of drivers, I have setup
+ * the mailing list "xircom-devel@isil.d.shuttle.de" (To subscribe send a
+ * message containing the word "subscribe" in the subject or somewhere at
+ * the beginning of a line to "xircom-devel-request@isil.d.shuttle.de").
+ *
+ ************************************************************************
+ * Copyright (c) 1997,1998 Werner Koch (dd9jn)
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * It is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *
+ * ALTERNATIVELY, this driver may be distributed under the terms of
+ * the following license, in which case the provisions of this license
+ * are required INSTEAD OF the GNU General Public License.  (This clause
+ * is necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Enable the bug fix for CEM56 to use modem and ethernet simultaneously */
+#define CEM56_FIX
+
+#if !defined(PCMCIA_DEBUG) && 0
+  #define PCMCIA_DEBUG 4
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+
+#ifndef MANFID_XIRCOM
+  #define MANFID_XIRCOM 	   0x0105
+#endif
+#ifndef MANFID_COMPAQ
+  #define MANFID_COMPAQ 	   0x0138
+  #define MANFID_COMPAQ2	   0x0183  /* is this correct? */
+#endif
+#ifndef MANFID_INTEL
+  #define MANFID_INTEL		   0x0089
+#endif
+
+#include <pcmcia/ds.h>
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT	((400*HZ)/1000)
+
+/****************
+ * Some constants used to access the hardware
+ */
+
+/* Register offsets and value constans */
+#define XIRCREG_CR  0	/* Command register (wr) */
+enum xirc_cr {
+    TransmitPacket = 0x01,
+    SoftReset = 0x02,
+    EnableIntr = 0x04,
+    ForceIntr  = 0x08,
+    ClearTxFIFO = 0x10,
+    ClearRxOvrun = 0x20,
+    RestartTx	 = 0x40
+};
+#define XIRCREG_ESR 0	/* Ethernet status register (rd) */
+enum xirc_esr {
+    FullPktRcvd = 0x01, /* full packet in receive buffer */
+    PktRejected = 0x04, /* a packet has been rejected */
+    TxPktPend = 0x08,	/* TX Packet Pending */
+    IncorPolarity = 0x10,
+    MediaSelect = 0x20	/* set if TP, clear if AUI */
+};
+#define XIRCREG_PR  1	/* Page Register select */
+#define XIRCREG_EDP 4	/* Ethernet Data Port Register */
+#define XIRCREG_ISR 6	/* Ethernet Interrupt Status Register */
+enum xirc_isr {
+    TxBufOvr = 0x01,	/* TX Buffer Overflow */
+    PktTxed  = 0x02,	/* Packet Transmitted */
+    MACIntr  = 0x04,	/* MAC Interrupt occured */
+    TxResGrant = 0x08,	/* Tx Reservation Granted */
+    RxFullPkt = 0x20,	/* Rx Full Packet */
+    RxPktRej  = 0x40,	/* Rx Packet Rejected */
+    ForcedIntr= 0x80	/* Forced Interrupt */
+};
+#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/
+#define XIRCREG1_IMR1 13
+#define XIRCREG0_TSO  8  /* Transmit Space Open Register (on page 0)*/
+#define XIRCREG0_TRS  10 /* Transmit reservation Size Register (page 0)*/
+#define XIRCREG0_DO   12 /* Data Offset Register (page 0) (wr) */
+#define XIRCREG0_RSR  12 /* Receive Status Register (page 0) (rd) */
+enum xirc_rsr {
+    PhyPkt = 0x01,	/* set:physical packet, clear: multicast packet */
+    BrdcstPkt = 0x02,	/* set if it is a broadcast packet */
+    PktTooLong = 0x04,	/* set if packet length > 1518 */
+    AlignErr = 0x10,	/* incorrect CRC and last octet not complete */
+    CRCErr = 0x20,	/* incorrect CRC and last octet is complete */
+    PktRxOk = 0x80	/* received ok */
+};
+#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */
+#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */
+#define XIRCREG1_ECR 14 /* ethernet configurationn register */
+enum xirc_ecr {
+    FullDuplex = 0x04,	/* enable full duplex mode */
+    LongTPMode = 0x08,	/* adjust for longer lengths of TP cable */
+    DisablePolCor = 0x10,/* disable auto polarity correction */
+    DisableLinkPulse = 0x20, /* disable link pulse generation */
+    DisableAutoTx = 0x40, /* disable auto-transmit */
+};
+#define XIRCREG2_RBS 8	/* receive buffer start register */
+#define XIRCREG2_LED 10 /* LED Configuration register */
+/* values for the leds:    Bits 2-0 for led 1
+ *  0 disabled		   Bits 5-3 for led 2
+ *  1 collision
+ *  2 noncollision
+ *  3 link_detected
+ *  4 incor_polarity
+ *  5 jabber
+ *  6 auto_assertion
+ *  7 rx_tx_activity
+ */
+#define XIRCREG2_MSR 12 /* Mohawk specific register */
+
+#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */
+#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */
+#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/
+#define XIRCREG4_BOV 10 /* Bonding Version Register */
+#define XIRCREG4_LMA 12 /* Local Memory Address Register */
+#define XIRCREG4_LMD 14 /* Local Memory Data Port */
+/* MAC register can only by accessed with 8 bit operations */
+#define XIRCREG40_CMD0 8    /* Command Register (wr) */
+enum xirc_cmd { 	    /* Commands */
+    Transmit = 0x01,
+    EnableRecv = 0x04,
+    DisableRecv = 0x08,
+    Abort = 0x10,
+    Online = 0x20,
+    IntrAck = 0x40,
+    Offline = 0x80
+};
+#define XIRCREG5_RHSA0	10  /* Rx Host Start Address */
+#define XIRCREG40_RXST0 9   /* Receive Status Register */
+#define XIRCREG40_TXST0 11  /* Transmit Status Register 0 */
+#define XIRCREG40_TXST1 12  /* Transmit Status Register 10 */
+#define XIRCREG40_RMASK0 13  /* Receive Mask Register */
+#define XIRCREG40_TMASK0 14  /* Transmit Mask Register 0 */
+#define XIRCREG40_TMASK1 15  /* Transmit Mask Register 0 */
+#define XIRCREG42_SWC0	8   /* Software Configuration 0 */
+#define XIRCREG42_SWC1	9   /* Software Configuration 1 */
+#define XIRCREG42_BOC	10  /* Back-Off Configuration */
+#define XIRCREG44_TDR0	8   /* Time Domain Reflectometry 0 */
+#define XIRCREG44_TDR1	9   /* Time Domain Reflectometry 1 */
+#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */
+#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */
+#define XIRCREG45_REV	 15 /* Revision Register (rd) */
+#define XIRCREG50_IA	8   /* Individual Address (8-13) */
+
+static char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" };
+
+/****************
+ * All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+ * you do not define PCMCIA_DEBUG at all, all the debug code will be
+ * left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+ * be present but disabled -- but it can then be enabled for specific
+ * modules at load time with a 'pc_debug=#' option to insmod.
+ */
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#endif
+static char *version =
+"xirc2ps_cs.c 1.31 1998/12/09 19:32:55 (dd9jn+kvh)";
+	    /* !--- CVS revision */
+#define KDBG_XIRC KERN_DEBUG   "xirc2ps_cs: "
+#define KERR_XIRC KERN_ERR     "xirc2ps_cs: "
+#define KWRN_XIRC KERN_WARNING "xirc2ps_cs: "
+#define KNOT_XIRC KERN_NOTICE  "xirc2ps_cs: "
+#define KINF_XIRC KERN_INFO    "xirc2ps_cs: "
+
+/* card types */
+#define XIR_UNKNOWN  0	/* unknown: not supported */
+#define XIR_CE	     1	/* (prodid 1) different hardware: not supported */
+#define XIR_CE2      2	/* (prodid 2) */
+#define XIR_CE3      3	/* (prodid 3) */
+#define XIR_CEM      4	/* (prodid 1) different hardware: not supported */
+#define XIR_CEM2     5	/* (prodid 2) */
+#define XIR_CEM3     6	/* (prodid 3) */
+#define XIR_CEM33    7	/* (prodid 4) */
+#define XIR_CEM56M   8	/* (prodid 5) */
+#define XIR_CEM56    9	/* (prodid 6) */
+#define XIR_CM28    10	/* (prodid 3) modem only: not supported here */
+#define XIR_CM33    11	/* (prodid 4) modem only: not supported here */
+#define XIR_CM56    12	/* (prodid 5) modem only: not supported here */
+#define XIR_CG	    13	/* (prodid 1) GSM modem only: not supported */
+#define XIR_CBE     14	/* (prodid 1) cardbus ethernet: not supported */
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+static int if_port = 0;
+MODULE_PARM(if_port, "i");
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_long irq_mask = 0xdeb8;
+MODULE_PARM(irq_mask, "i");
+
+static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
+
+static int do_sound = 1;
+MODULE_PARM(do_sound, "i");
+
+static int card_type = 0;
+MODULE_PARM(card_type, "i");  /* dummy, not used anymore */
+
+static int lockup_hack = 0;
+MODULE_PARM(lockup_hack, "i");  /* anti lockup hack */
+
+/*====================================================================*/
+
+/* We do not process more than these number of bytes during one
+ * interrupt. (Of course we receive complete packets, so this is not
+ * an exact value).
+ * Something between 2000..22000; first value gives best interrupt latency,
+ * the second enables the usage of the complete on-chip buffer. We use the
+ * high value as the initial value.
+ */
+static unsigned maxrx_bytes = 22000;
+
+/* MII management prototypes */
+static void mii_idle(ioaddr_t ioaddr);
+static void mii_putbit(ioaddr_t ioaddr, unsigned data);
+static int  mii_getbit( ioaddr_t ioaddr );
+static void mii_wbits(ioaddr_t ioaddr, unsigned data, int len);
+static unsigned mii_rd(ioaddr_t ioaddr,	u_char phyaddr, u_char phyreg);
+static void mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg,
+				   unsigned data, int len);
+
+/*
+ * The event() function is this driver's Card Services event handler.
+ * It will be called by Card Services when an appropriate card status
+ * event is received.  The config() and release() entry points are
+ * used to configure or release a socket, in response to card insertion
+ * and ejection events.  They are invoked from the event handler.
+ */
+
+static int has_ce2_string(dev_link_t * link);
+static void xirc2ps_config(dev_link_t * link);
+static void xirc2ps_release(u_long arg);
+static int xirc2ps_event(event_t event, int priority,
+			 event_callback_args_t * args);
+
+/****************
+ * The attach() and detach() entry points are used to create and destroy
+ * "instances" of the driver, where each instance represents everything
+ * needed to manage one actual PCMCIA card.
+ */
+
+static dev_link_t *xirc2ps_attach(void);
+static void xirc2ps_detach(dev_link_t *);
+
+/****************
+ * You'll also need to prototype all the functions that will actually
+ * be used to talk to your device.  See 'pcmem_cs' for a good example
+ * of a fully self-sufficient driver; the other drivers rely more or
+ * less on other parts of the kernel.
+ */
+
+static void xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/*
+ * The dev_info variable is the "key" that is used to match up this
+ * device driver with appropriate cards, through the card configuration
+ * database.
+ */
+
+static dev_info_t dev_info = "xirc2ps_cs";
+
+/****************
+ * A linked list of "instances" of the device.  Each actual
+ * PCMCIA card corresponds to one device instance, and is described
+ * by one dev_link_t structure (defined in ds.h).
+ *
+ * You may not want to use a linked list for this -- for example, the
+ * memory card driver uses an array of dev_link_t pointers, where minor
+ * device numbers are used to derive the corresponding array index.
+ */
+
+static dev_link_t *dev_list = NULL;
+
+/****************
+ * A dev_link_t structure has fields for most things that are needed
+ * to keep track of a socket, but there will usually be some device
+ * specific information that also needs to be kept track of.  The
+ * 'priv' pointer in a dev_link_t structure can be used to point to
+ * a device-specific private data structure, like this.
+ *
+ * A driver needs to provide a dev_node_t structure for each device
+ * on a card.  In some cases, there is only one device per card (for
+ * example, ethernet cards, modems).  In other cases, there may be
+ * many actual or logical devices (SCSI adapters, memory cards with
+ * multiple partitions).  The dev_node_t structures need to be kept
+ * in a linked list starting at the 'dev' field of a dev_link_t
+ * structure.  We allocate them in the card's private data structure,
+ * because they generally can't be allocated dynamically.
+ */
+
+typedef struct local_info_t {
+    dev_node_t node;
+    struct enet_statistics stats;
+    int card_type;
+    int probe_port;
+    int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */
+    int mohawk;  /* a CE3 type card */
+    int dingo;	 /* a CEM56 type card */
+    int modem;	 /* is a multi function card (i.e with a modem) */
+    caddr_t dingo_ccr; /* only used for CEM56 cards */
+    int suspended;
+    unsigned last_ptr_value; /* last packets transmitted value */
+    const char *manf_str;
+} local_info_t;
+
+/****************
+ * Some more prototypes
+ */
+static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct enet_statistics *do_get_stats(struct net_device *dev);
+static void set_addresses(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static int do_init(struct net_device *dev);
+static int set_card_type( dev_link_t *link, const void *s );
+static int do_config(struct net_device *dev, struct ifmap *map);
+static int do_open(struct net_device *dev);
+static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void hardreset(struct net_device *dev);
+static void do_reset(struct net_device *dev, int full);
+static int init_mii(struct net_device *dev);
+static void do_powerdown(struct net_device *dev);
+static int do_stop(struct net_device *dev);
+
+/*=============== Helper functions =========================*/
+static void
+flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    xirc2ps_detach(link);
+    }
+}
+
+static void
+cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+static int
+get_tuple_data(int fn, client_handle_t handle, tuple_t *tuple )
+{
+    int err;
+
+    if( (err=CardServices(fn, handle, tuple)) )
+	return err;
+    return CardServices(GetTupleData, handle, tuple);
+}
+
+static int
+get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+    int err;
+
+    if( (err=get_tuple_data(fn, handle, tuple)) )
+	return err;
+    return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c)  get_tuple(GetNextTuple, a, b, c)
+
+#define SelectPage(pgnr)   outb((pgnr), ioaddr + XIRCREG_PR)
+#define GetByte(reg)	   ((unsigned)inb(ioaddr + (reg)))
+#define GetWord(reg)	   ((unsigned)inw(ioaddr + (reg)))
+#define PutByte(reg,value) outb((value), ioaddr+(reg))
+#define PutWord(reg,value) outw((value), ioaddr+(reg))
+
+static void
+busy_loop(u_long len)
+{
+    u_long timeout = jiffies + len;
+    u_long flags;
+
+    save_flags(flags);
+    sti();
+    while(timeout >= jiffies)
+	;
+    restore_flags(flags);
+}
+
+/*====== Functions used for debugging =================================*/
+#if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */
+static void
+PrintRegisters(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+
+    if(pc_debug > 1) {
+	int i, page;
+
+	printk(KDBG_XIRC "Register  common: ");
+	for(i = 0; i < 8; i++ )
+	    printk(" %2.2x", GetByte(i) );
+	printk("\n");
+	for(page = 0; page <= 8; page++) {
+	    printk(KDBG_XIRC "Register page %2x: ", page);
+	    SelectPage(page);
+	    for(i = 8; i < 16; i++)
+		printk(" %2.2x", GetByte(i));
+	    printk("\n");
+	}
+	for(page=0x40 ; page <= 0x5f; page++) {
+	    if( page == 0x43 || (page >= 0x46 && page <= 0x4f)
+		|| (page >= 0x51 && page <=0x5e) )
+		continue;
+	    printk(KDBG_XIRC "Register page %2x: ", page);
+	    SelectPage(page);
+	    for(i = 8; i < 16; i++)
+		printk(" %2.2x", GetByte(i));
+	    printk("\n");
+	}
+    }
+}
+#endif /* PCMCIA_DEBUG */
+
+/*============== MII Management functions ===============*/
+
+/****************
+ * Turn around for read
+ */
+static void
+mii_idle(ioaddr_t ioaddr)
+{
+    PutByte(XIRCREG2_GPR2, 0x04|0 ); /* drive MDCK low */
+    udelay(1);
+    PutByte(XIRCREG2_GPR2, 0x04|1 ); /* and drive MDCK high */
+    udelay(1);
+}
+
+/****************
+ * Write a bit to MDI/O
+ */
+static void
+mii_putbit(ioaddr_t ioaddr, unsigned data)
+{
+  #if 1
+    if( data ) {
+	PutByte(XIRCREG2_GPR2, 0x0c|2|0 ); /* set MDIO */
+	udelay(1);
+	PutByte(XIRCREG2_GPR2, 0x0c|2|1 ); /* and drive MDCK high */
+	udelay(1);
+    }
+    else {
+	PutByte(XIRCREG2_GPR2, 0x0c|0|0 ); /* clear MDIO */
+	udelay(1);
+	PutByte(XIRCREG2_GPR2, 0x0c|0|1 ); /* and drive MDCK high */
+	udelay(1);
+    }
+  #else
+    if( data ) {
+	PutWord(XIRCREG2_GPR2-1, 0x0e0e );
+	udelay(1);
+	PutWord(XIRCREG2_GPR2-1, 0x0f0f );
+	udelay(1);
+    }
+    else {
+	PutWord(XIRCREG2_GPR2-1, 0x0c0c );
+	udelay(1);
+	PutWord(XIRCREG2_GPR2-1, 0x0d0d );
+	udelay(1);
+    }
+  #endif
+}
+
+/****************
+ * Get a bit from MDI/O
+ */
+static int
+mii_getbit( ioaddr_t ioaddr )
+{
+    unsigned d;
+
+    PutByte(XIRCREG2_GPR2, 4|0 ); /* drive MDCK low */
+    udelay(1);
+    d = GetByte(XIRCREG2_GPR2); /* read MDIO */
+    PutByte(XIRCREG2_GPR2, 4|1 ); /* drive MDCK high again */
+    udelay(1);
+    return d & 0x20; /* read MDIO */
+}
+
+static void
+mii_wbits(ioaddr_t ioaddr, unsigned data, int len)
+{
+    unsigned m = 1 << (len-1);
+    for( ; m; m >>= 1)
+	mii_putbit( ioaddr, data & m );
+}
+
+static unsigned
+mii_rd(ioaddr_t ioaddr,	u_char phyaddr, u_char phyreg)
+{
+    int i;
+    unsigned data=0, m;
+
+    SelectPage(2);
+    for( i=0; i < 32; i++ )		/* 32 bit preamble */
+	mii_putbit(ioaddr, 1);
+    mii_wbits(ioaddr, 0x06, 4); 	/* Start and opcode for read */
+    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
+    mii_wbits(ioaddr, phyreg, 5);	/* PHY register to read */
+    mii_idle(ioaddr);			/* turn around */
+    mii_getbit( ioaddr);
+
+    for( m = 1<<15; m; m >>= 1 )
+	if( mii_getbit( ioaddr ) )
+	    data |= m;
+    mii_idle(ioaddr);
+    return data;
+}
+
+static void
+mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len)
+{
+    int i;
+
+    SelectPage(2);
+    for( i=0; i < 32; i++ )		/* 32 bit preamble */
+	mii_putbit(ioaddr, 1);
+    mii_wbits(ioaddr, 0x05, 4); 	/* Start and opcode for write */
+    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
+    mii_wbits(ioaddr, phyreg, 5);	/* PHY Register to write */
+    mii_putbit(ioaddr, 1);		/* turn around */
+    mii_putbit(ioaddr, 0);
+    mii_wbits(ioaddr, data, len);	/* And write the data */
+    mii_idle(ioaddr);
+}
+
+#ifdef PCMCIA_DEBUG
+static void
+mii_dump(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+
+    /* Note that registers 14, 1d,1e and 1f are reserved and should
+     * not be read according to the DP83840A specs.
+     */
+    printk(KERN_DEBUG "%s: MII register dump:\n", dev->name);
+    for(i=0; i < 32; i++ ) {
+	if( !(i % 8) ) {
+	    if( i )
+		printk("\n");
+	    printk(KERN_DEBUG "%s:", dev->name );
+	}
+	printk(" %04x", mii_rd(ioaddr, 0, i) );
+    }
+    printk("\n");
+}
+#endif
+
+/*============= Main bulk of functions	=========================*/
+
+/****************
+ * xirc2ps_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device.  The device is registered
+ * with Card Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a
+ * card insertion event.
+ */
+
+static dev_link_t *
+xirc2ps_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    local_info_t *local;
+    int err;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "attach()\n");
+  #endif
+    flush_stale_links();
+
+    /* Initialize the dev_link_t structure */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &xirc2ps_release;
+    link->release.data = (u_long) link;
+
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Allocate space for a device structure */
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev, 0, sizeof(struct net_device));
+    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    memset(local, 0, sizeof(local_info_t));
+    dev->priv = local;
+
+    /* Fill in card specific entries */
+    dev->hard_start_xmit = &do_start_xmit;
+    dev->set_config = &do_config;
+    dev->get_stats = &do_get_stats;
+    dev->do_ioctl = &do_ioctl;
+    dev->set_multicast_list = &set_multicast_list;
+    ether_setup(dev);
+    dev->name = local->node.dev_name;
+    dev->init = &do_init;
+    dev->open = &do_open;
+    dev->stop = &do_stop;
+    dev->tbusy = 1;
+    link->priv = dev;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &xirc2ps_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    if( (err = CardServices(RegisterClient, &link->handle, &client_reg)) ) {
+	cs_error(link->handle, RegisterClient, err);
+	xirc2ps_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* xirc2ps_attach */
+
+/****************
+ *  This deletes a driver "instance".  The device is de-registered
+ *  with Card Services.  If it has been released, all local data
+ *  structures are freed.  Otherwise, the structures will be freed
+ *  when the device is released.
+ */
+
+static void
+xirc2ps_detach(dev_link_t * link)
+{
+    dev_link_t **linkp;
+    long flags;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "detach(0x%p)\n", link);
+  #endif
+
+    /* Locate device structure */
+    for( linkp = &dev_list; *linkp; linkp = &(*linkp)->next )
+	if( *linkp == link)
+	    break;
+    if( !*linkp ) {
+      #ifdef PCMCIA_DEBUG
+	printk(KDBG_XIRC "detach(0x%p): dev_link lost\n", link );
+      #endif
+	return;
+    }
+
+    save_flags(flags);
+    cli();
+    if( link->state & DEV_RELEASE_PENDING ) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+
+    /*
+     * If the device is currently configured and active, we won't
+     * actually delete it yet.	Instead, it is marked so that when
+     * the release() function is called, that will trigger a proper
+     * detach().
+     */
+    if(link->state & DEV_CONFIG) {
+      #ifdef PCMCIA_DEBUG
+	printk(KDBG_XIRC "detach postponed, '%s' "
+			  "still locked\n", link->dev->dev_name);
+      #endif
+	link->state |= DEV_STALE_LINK;
+	return;
+    }
+
+    /* Break the link with Card Services */
+    if(link->handle)
+	CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if(link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev != NULL)
+	    unregister_netdev(dev);
+	if( dev->priv )
+	    kfree(dev->priv);
+	kfree(link->priv);
+    }
+    kfree(link);
+
+} /* xirc2ps_detach */
+
+/****************
+ * Detect the type of the card. s is the buffer with the data of tuple 0x20
+ * Returns: 0 := not supported
+ *		       mediaid=11 and prodid=47
+ * Media-Id bits:
+ *  Ethernet	    0x01
+ *  Tokenring	    0x02
+ *  Arcnet	    0x04
+ *  Wireless	    0x08
+ *  Modem	    0x10
+ *  GSM only	    0x20
+ * Prod-Id bits:
+ *  Pocket	    0x10
+ *  External	    0x20
+ *  Creditcard	    0x40
+ *  Cardbus	    0x80
+ *
+ */
+static int
+set_card_type( dev_link_t *link, const void *s )
+{
+    struct net_device *dev = link->priv;
+    local_info_t *local = dev->priv;
+  #ifdef PCMCIA_DEBUG
+    unsigned cisrev = ((const unsigned char *)s)[2];
+  #endif
+    unsigned mediaid= ((const unsigned char *)s)[3];
+    unsigned prodid = ((const unsigned char *)s)[4];
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "cisrev=%02x mediaid=%02x prodid=%02x\n",
+			  cisrev, mediaid, prodid );
+  #endif
+
+    local->mohawk = 0;
+    local->dingo = 0;
+    local->modem = 0;
+    local->card_type = XIR_UNKNOWN;
+    if( !(prodid & 0x40) ) {
+	printk(KNOT_XIRC "Ooops: Not a creditcard\n");
+	return 0;
+    }
+    if( !(mediaid & 0x01) ) {
+	printk(KNOT_XIRC "Not an Ethernet card\n");
+	return 0;
+    }
+    if( mediaid & 0x10 ) {
+	local->modem = 1;
+	switch( prodid & 15 ) {
+	  case 1: local->card_type = XIR_CEM   ; break;
+	  case 2: local->card_type = XIR_CEM2  ; break;
+	  case 3: local->card_type = XIR_CEM3  ; break;
+	  case 4: local->card_type = XIR_CEM33 ; break;
+	  case 5: local->card_type = XIR_CEM56M;
+		  local->mohawk = 1;
+		  break;
+	  case 6:
+	  case 7: /* 7 is the RealPort 10/56 */
+		  local->card_type = XIR_CEM56 ;
+		  local->mohawk = 1;
+		  local->dingo = 1;
+		  break;
+	}
+    }
+    else {
+	switch( prodid & 15 ) {
+	  case 1: local->card_type = has_ce2_string(link)? XIR_CE2 : XIR_CE ;
+		  break;
+	  case 2: local->card_type = XIR_CE2; break;
+	  case 3: local->card_type = XIR_CE3;
+		  local->mohawk = 1;
+		  break;
+	}
+    }
+    if( local->card_type == XIR_CE || local->card_type == XIR_CEM ) {
+	printk(KNOT_XIRC "Sorry, this is an old CE card\n");
+	return 0;
+    }
+    if( local->card_type == XIR_UNKNOWN )
+	printk(KNOT_XIRC "Warning: Unknown card (mediaid=%02x prodid=%02x)\n",
+				  mediaid, prodid );
+
+    return 1;
+}
+
+/****************
+ * There are some CE2 cards out which claim to be a CE card.
+ * This function looks for a "CE2" in the 3rd version field.
+ * Returns: true if this is a CE2
+ */
+static int
+has_ce2_string(dev_link_t * link)
+{
+    client_handle_t handle = link->handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[256];
+
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = 254;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 2 ) {
+	if( strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2") )
+	    return 1;
+    }
+    return 0;
+}
+
+/****************
+ * xirc2ps_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * ethernet device available to the system.
+ */
+static void
+xirc2ps_config(dev_link_t * link)
+{
+    client_handle_t handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    struct net_device *dev;
+    local_info_t *local;
+    ioaddr_t ioaddr;
+    int err, i;
+    u_char buf[64];
+    cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+
+    handle = link->handle;
+    dev = link->priv;
+    local = dev->priv;
+    local->dingo_ccr = 0;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "config(0x%p)\n", link);
+  #endif
+
+    /*
+     * This reads the card's CONFIG tuple to find its configuration
+     * registers.
+     */
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+
+    /* Is this a valid	card */
+    tuple.DesiredTuple = CISTPL_MANFID;
+    if( (err=first_tuple(handle, &tuple, &parse))) {
+	printk(KNOT_XIRC "manfid not found in CIS\n");
+	goto failure;
+    }
+
+    switch( parse.manfid.manf ) {
+      case MANFID_XIRCOM:
+	local->manf_str = "Xircom";
+	#ifdef PCMCIA_DEBUG
+	  if(pc_debug)
+	    printk(KDBG_XIRC "found xircom card\n");
+	#endif
+	break;
+      case MANFID_ACCTON:
+	local->manf_str = "Accton";
+	#ifdef PCMCIA_DEBUG
+	  if(pc_debug)
+	    printk(KDBG_XIRC "found Accton card\n");
+	#endif
+	break;
+      case MANFID_COMPAQ:
+      case MANFID_COMPAQ2:
+	local->manf_str = "Compaq";
+	#ifdef PCMCIA_DEBUG
+	  if(pc_debug)
+	    printk(KDBG_XIRC "found Compaq card\n");
+	#endif
+	break;
+      case MANFID_INTEL:
+	local->manf_str = "Intel";
+	#ifdef PCMCIA_DEBUG
+	  if(pc_debug)
+	    printk(KDBG_XIRC "found Intel card\n");
+	#endif
+	break;
+      default:
+	printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n",
+						 (unsigned)parse.manfid.manf);
+	goto failure;
+    }
+
+    if( !set_card_type(link, buf ) ) {
+	printk(KNOT_XIRC "this card is not supported\n");
+	goto failure;
+    }
+
+    /* get configuration stuff */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    if( (err=first_tuple(handle, &tuple, &parse)))
+	goto cis_error;
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present =    parse.config.rmask[0];
+
+    /* get the ethernet address from the CIS */
+    tuple.DesiredTuple = CISTPL_FUNCE;
+    for( err = first_tuple(handle, &tuple, &parse); !err;
+			     err = next_tuple(handle, &tuple, &parse) ) {
+	/* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries:
+	 * the first one with a length of zero the second correct -
+	 * so I skip all entries with length 0 */
+	if( parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID
+	    && ((cistpl_lan_node_id_t *)parse.funce.data)->nb )
+	    break;
+    }
+    if( err ) { /* not found: try to get the node-id from tuple 0x89 */
+	tuple.DesiredTuple = 0x89;  /* data layout looks like tuple 0x22 */
+	if( !(err = get_tuple_data(GetFirstTuple, handle, &tuple )) ) {
+	    if( tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID )
+		memcpy( &parse, buf, 8 );
+	    else
+		err = -1;
+	}
+    }
+    if( err ) { /* another try	(James Lehmer's CE2 version 4.1)*/
+	tuple.DesiredTuple = CISTPL_FUNCE;
+	for( err = first_tuple(handle, &tuple, &parse); !err;
+				 err = next_tuple(handle, &tuple, &parse) ) {
+	    if( parse.funce.type == 0x02 && parse.funce.data[0] == 1
+		&& parse.funce.data[1] == 6 && tuple.TupleDataLen == 13 ) {
+		buf[1] = 4;
+		memcpy( &parse, buf+1, 8 );
+		break;
+	    }
+	}
+    }
+    if( err ) {
+	printk(KNOT_XIRC "node-id not found in CIS\n");
+	goto failure;
+    }
+    node_id = (cistpl_lan_node_id_t *)parse.funce.data;
+    if( node_id->nb != 6 ) {
+	printk(KNOT_XIRC "malformed node-id in CIS\n");
+	goto failure;
+    }
+    for( i=0; i < 6; i++ )
+	dev->dev_addr[i] = node_id->id[i];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    link->io.IOAddrLines =10;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    link->irq.Attributes = IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    if( irq_list[0] == -1 )
+	link->irq.IRQInfo2 = irq_mask;
+    else {
+	for( i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    }
+    link->irq.Handler = xirc2ps_interrupt;
+    link->irq.Instance = dev;
+    if( local->modem ) {
+	int pass;
+
+	if( do_sound ) {
+	    link->conf.Attributes |= CONF_ENABLE_SPKR;
+	    link->conf.Status |= CCSR_AUDIO_ENA;
+	}
+	link->irq.Attributes |= IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED ;
+	link->io.NumPorts2 = 8;
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	if( local->dingo ) {
+	    /* Take the Modem IO port from the CIS and scan for a free
+	     * Ethernet port */
+	    link->io.NumPorts1 = 16; /* no Mako stuff anymore */
+	    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	    for( err = first_tuple(handle, &tuple, &parse); !err;
+				 err = next_tuple(handle, &tuple, &parse) ) {
+		if( cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8 ) {
+		    for(ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+			link->conf.ConfigIndex = cf->index ;
+			link->io.BasePort2 = cf->io.win[0].base;
+			link->io.BasePort1 = ioaddr;
+			if( !(err=CardServices(RequestIO, link->handle,
+								&link->io)) )
+			    goto port_found;
+		    }
+		}
+	    }
+	}
+	else {
+	    link->io.NumPorts1 = 18;
+	    /* We do 2 passes here: The first one uses the regular mapping and
+	     * the second tries again, thereby considering that the 32 ports are
+	     * mirrored every 32 bytes. Actually we use a mirrored port for
+	     * the Mako if (on the first pass) the COR bit 5 is set.
+	     */
+	    for( pass=0; pass < 2; pass++ ) {
+		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+		for( err = first_tuple(handle, &tuple, &parse); !err;
+				     err = next_tuple(handle, &tuple, &parse) ){
+		    if( cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8 ){
+			link->conf.ConfigIndex = cf->index ;
+			link->io.BasePort2 = cf->io.win[0].base;
+			link->io.BasePort1 = link->io.BasePort2
+				    + (pass ? ( cf->index & 0x20 ? -24:8 )
+					    : ( cf->index & 0x20 ?   8:-24) );
+			if( !(err=CardServices(RequestIO, link->handle,
+								&link->io)))
+			    goto port_found;
+		    }
+		}
+	    }
+	    /* if special option:
+	     * try to configure as Ethernet only.
+	     * .... */
+	}
+	printk(KNOT_XIRC "no ports available\n");
+    }
+    else {
+	link->irq.Attributes |= IRQ_TYPE_EXCLUSIVE;
+	link->io.NumPorts1 = 16;
+	for(ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+	    link->io.BasePort1 = ioaddr;
+	    if( !(err=CardServices(RequestIO, link->handle, &link->io)) )
+		goto port_found;
+	}
+	link->io.BasePort1 = 0; /* let CS decide */
+	if( (err=CardServices(RequestIO, link->handle, &link->io)) ) {
+	    cs_error(link->handle, RequestIO, err);
+	    goto config_error;
+	}
+    }
+  port_found:
+    if( err )
+	 goto config_error;
+
+    /****************
+     * Now allocate an interrupt line.	Note that this does not
+     * actually assign a handler to the interrupt.
+     */
+    if( (err=CardServices(RequestIRQ, link->handle, &link->irq))) {
+	cs_error(link->handle, RequestIRQ, err);
+	goto config_error;
+    }
+
+    /****************
+     * This actually configures the PCMCIA socket -- setting up
+     * the I/O windows and the interrupt mapping.
+     */
+    if( (err=CardServices(RequestConfiguration,
+					link->handle, &link->conf)) ) {
+	cs_error(link->handle, RequestConfiguration, err);
+	goto config_error;
+    }
+
+    if( local->dingo ) {
+      #ifdef CEM56_FIX
+	conf_reg_t reg;
+      #endif
+	win_req_t req;
+	memreq_t mem;
+
+      #ifdef CEM56_FIX
+	/* Reset the modem's BAR to the correct value
+	 * This is necessary because in the RequestConfiguration call,
+	 * the base address of the ethernet port (BasePort1) is written
+	 * to the BAR registers of the modem.
+	 */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_IOBASE_0;
+	reg.Value = link->io.BasePort2 & 0xff;
+	if( (err = CardServices(AccessConfigurationRegister, link->handle,
+							     &reg )) ) {
+	    cs_error(link->handle, AccessConfigurationRegister, err);
+	    goto config_error;
+	}
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_IOBASE_1;
+	reg.Value = (link->io.BasePort2 >> 8) & 0xff;
+	if( (err = CardServices(AccessConfigurationRegister, link->handle,
+							      &reg )) ) {
+	    cs_error(link->handle, AccessConfigurationRegister, err);
+	    goto config_error;
+	}
+     #endif
+
+	/* There is no config entry for the Ethernet part which
+	 * is at 0x0800. So we allocate a window into the attribute
+	 * memory and write direct to the CIS registers
+	 */
+	req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+	req.Base = 0;
+	req.Size = 0x1000; /* 4k window */
+	req.AccessSpeed = 0;
+	link->win = (window_handle_t)link->handle;
+	if( (err = CardServices(RequestWindow, &link->win, &req )) ) {
+	    cs_error(link->handle, RequestWindow, err);
+	    goto config_error;
+	}
+	local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800;
+	mem.CardOffset = 0x0;
+	mem.Page = 0;
+	if( (err = CardServices(MapMemPage, link->win, &mem) ) ) {
+	    cs_error(link->handle, MapMemPage, err);
+	    goto config_error;
+	}
+
+	/* Setup the CCRs; there are no infos in the CIS about the Ethernet
+	 * part.
+	 */
+	writeb(0x47, local->dingo_ccr + CISREG_COR );
+	ioaddr = link->io.BasePort1;
+	writeb( ioaddr & 0xff	  , local->dingo_ccr + CISREG_IOBASE_0 );
+	writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1 );
+
+      #if 0
+	{
+	    u_char tmp;
+	    printk(KERN_INFO "ECOR:" );
+	    for(i=0; i < 7; i++ ) {
+		tmp = readb(local->dingo_ccr + i*2 );
+		printk(" %02x", tmp );
+	    }
+	    printk("\n" );
+	    printk(KERN_INFO "DCOR:" );
+	    for(i=0; i < 4; i++ ) {
+		tmp = readb(local->dingo_ccr + 0x20 + i*2 );
+		printk(" %02x", tmp );
+	    }
+	    printk("\n" );
+	    printk(KERN_INFO "SCOR:" );
+	    for(i=0; i < 10; i++ ) {
+		tmp = readb(local->dingo_ccr + 0x40 + i*2 );
+		printk(" %02x", tmp );
+	    }
+	    printk("\n" );
+	}
+      #endif
+
+	writeb( 0x01		  , local->dingo_ccr + 0x20 );
+	writeb( 0x0c		  , local->dingo_ccr + 0x22 );
+	writeb( 0x00		  , local->dingo_ccr + 0x24 );
+	writeb( 0x00		  , local->dingo_ccr + 0x26 );
+	writeb( 0x00		  , local->dingo_ccr + 0x28 );
+    }
+
+    /* The if_port symbol can be set when the module is loaded */
+    local->probe_port=0;
+    if( !if_port ) {
+	local->probe_port=1;
+	dev->if_port = 1;
+    }
+    else if( (if_port >= 1 && if_port <= 2) || (local->mohawk && if_port==4) )
+	dev->if_port = if_port;
+    else
+	printk(KERN_NOTICE "xirc2ps_cs: invalid if_port requested\n");
+
+    /* we can now register the device with the net subsystem */
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    dev->tbusy = 0;
+    if( (err=register_netdev(dev)) ) {
+	printk(KERN_NOTICE "xirc2ps_cs: register_netdev() failed\n");
+	goto config_error;
+    }
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev = &local->node;
+
+    if( local->dingo )
+	do_reset(dev, 1); /* a kludge to make the cem56 work */
+
+    /* give some infos about the hardware */
+    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr",
+	 dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq );
+    for(i = 0; i < 6; i++)
+	printk("%c%02X", i?':':' ', dev->dev_addr[i]);
+    printk("\n");
+
+    return;
+
+  config_error:
+    link->state &= ~DEV_CONFIG_PENDING;
+    xirc2ps_release((u_long)link);
+    return;
+
+  cis_error:
+    printk(KERN_NOTICE "xirc2ps_cs: unable to parse CIS\n");
+  failure:
+    link->state &= ~DEV_CONFIG_PENDING;
+} /* xirc2ps_config */
+
+/****************
+ * After a card is removed, xirc2ps_release() will unregister the net
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+xirc2ps_release( u_long arg)
+{
+    dev_link_t *link = (dev_link_t *) arg;
+    struct net_device *dev = link->priv;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "release(0x%p)\n", link);
+  #endif
+
+    /*
+     * If the device is currently in use, we won't release until it
+     * is actually closed.
+     */
+    if(link->open) {
+      #ifdef PCMCIA_DEBUG
+	if(pc_debug)
+	    printk(KDBG_XIRC "release postponed, '%s' "
+			      "still open\n", link->dev->dev_name);
+      #endif
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    if( link->win ) {
+	local_info_t *local = dev->priv;
+	if( local->dingo )
+	    iounmap( local->dingo_ccr - 0x0800 );
+	CardServices(ReleaseWindow, link->win );
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* xirc2ps_release */
+
+/*====================================================================*/
+
+/****************
+ * The card status event handler.  Mostly, this schedules other
+ * stuff to run after an event is received.  A CARD_REMOVAL event
+ * also sets some flags to discourage the net drivers from trying
+ * to talk to the card any more.
+ *
+ * When a CARD_REMOVAL event is received, we immediately set a flag
+ * to block future accesses to this device.  All the functions that
+ * actually access the device should check this flag to make sure
+ * the card is still present.
+ */
+
+static int
+xirc2ps_event(event_t event, int priority,
+	      event_callback_args_t * args)
+{
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+    local_info_t *lp = dev? dev->priv : NULL;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "event(%d)\n", (int)event );
+  #endif
+
+    switch (event) {
+      case CS_EVENT_REGISTRATION_COMPLETE:
+	 #ifdef PCMCIA_DEBUG
+	  if(pc_debug)
+	      printk(KDBG_XIRC "registration complete\n");
+	 #endif
+	  break;
+      case CS_EVENT_CARD_REMOVAL:
+	  link->state &= ~DEV_PRESENT;
+	  if(link->state & DEV_CONFIG) {
+	      dev->tbusy = 1; dev->start = 0;
+	      link->release.expires = jiffies + HZ / 20;
+	      add_timer(&link->release);
+	  }
+	  break;
+      case CS_EVENT_CARD_INSERTION:
+	  link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	  xirc2ps_config(link);
+	  break;
+      case CS_EVENT_PM_SUSPEND:
+	  link->state |= DEV_SUSPEND;
+	  /* Fall through... */
+      case CS_EVENT_RESET_PHYSICAL:
+	  if(link->state & DEV_CONFIG) {
+	      if(link->open) {
+		  dev->tbusy = 1; dev->start = 0;
+		  lp->suspended=1;
+		  do_powerdown(dev);
+	      }
+	      CardServices(ReleaseConfiguration, link->handle);
+	  }
+	  break;
+      case CS_EVENT_PM_RESUME:
+	  link->state &= ~DEV_SUSPEND;
+	  /* Fall through... */
+      case CS_EVENT_CARD_RESET:
+	  if(link->state & DEV_CONFIG) {
+	     CardServices(RequestConfiguration, link->handle, &link->conf);
+	     if( link->open) {
+		 do_reset(dev,1);
+		 lp->suspended=0;
+		 dev->tbusy = 0; dev->start = 1;
+	     }
+	  }
+	  break;
+    }
+    return 0;
+} /* xirc2ps_event */
+
+/*====================================================================*/
+
+/****************
+ * This is the Interrupt service route.
+ */
+static void
+xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    local_info_t *lp;
+    ioaddr_t ioaddr;
+    u_char saved_page;
+    unsigned bytes_rcvd;
+    unsigned int_status, eth_status, rx_status, tx_status;
+    unsigned rsr, pktlen;
+    ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days
+				  * is this something to worry about?
+				  * -- on a laptop?
+				  */
+
+    if( !dev->start )
+       return;
+
+    if( dev->interrupt ) {
+	printk(KERR_XIRC "re-entering isr on irq %d (dev=%p)\n", irq, dev);
+	return;
+    }
+    dev->interrupt = 1;
+    lp = dev->priv;
+    ioaddr = dev->base_addr;
+    if( lp->mohawk ) { /* must disable the interrupt */
+	PutByte(XIRCREG_CR, 0 );
+    }
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug > 6 )
+	printk(KERN_DEBUG "%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr);
+  #endif
+
+    saved_page = GetByte(XIRCREG_PR);
+    /* Read the ISR to see whats the cause for the interrupt.
+     * This also clears the interrupt flags on CE2 cards
+     */
+    int_status = GetByte(XIRCREG_ISR);
+    bytes_rcvd = 0;
+  loop_entry:
+    if( int_status == 0xff ) { /* card may be ejected */
+      #ifdef PCMCIA_DEBUG
+	if( pc_debug > 3 )
+	    printk(KERN_DEBUG "%s: interrupt %d for dead card\n", dev->name, irq );
+      #endif
+	goto leave;
+    }
+    eth_status = GetByte(XIRCREG_ESR);
+
+    SelectPage(0x40);
+    rx_status  = GetByte(XIRCREG40_RXST0);
+    PutByte(XIRCREG40_RXST0, (~rx_status & 0xff) );
+    tx_status = GetByte(XIRCREG40_TXST0);
+    tx_status |= GetByte(XIRCREG40_TXST1) << 8;
+    PutByte(XIRCREG40_TXST0, 0 );
+    PutByte(XIRCREG40_TXST1, 0 );
+
+  #ifdef PCMCIA_DEBUG
+    if( pc_debug > 3 )
+	printk(KERN_DEBUG "%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n",
+		    dev->name, int_status, eth_status, rx_status, tx_status );
+  #endif
+
+    /***** receive section ******/
+    SelectPage(0);
+    while( eth_status & FullPktRcvd ) {
+	rsr = GetByte(XIRCREG0_RSR);
+	if( bytes_rcvd > maxrx_bytes && (rsr & PktRxOk) ) {
+	    /* too many bytes received during this int, drop the rest of the
+	     * packets */
+	    lp->stats.rx_dropped++;
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 3 )
+		printk(KNOT_XIRC "%s: RX drop, too much done\n", dev->name);
+	  #endif
+	    PutWord(XIRCREG0_DO, 0x8000 ); /* issue cmd: skip_rx_packet */
+	}
+	else if( rsr & PktRxOk ) {
+	    struct sk_buff *skb;
+
+	    pktlen = GetWord(XIRCREG0_RBC);
+	    bytes_rcvd += pktlen;
+
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 5 )
+		printk(KDBG_XIRC "rsr=%#02x packet_length=%u\n", rsr, pktlen );
+	  #endif
+
+	    skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */
+	    if( !skb ) {
+	      #ifdef PCMCIA_DEBUG
+		if( pc_debug )
+		    printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n",
+								     pktlen );
+	      #endif
+		lp->stats.rx_dropped++;
+	    }
+	    else { /* okay get the packet */
+		skb_reserve(skb, 2);
+		if( lp->silicon == 0  ) { /* work around a hardware bug */
+		    unsigned rhsa; /* receive start address */
+
+		    SelectPage(5);
+		    rhsa = GetWord(XIRCREG5_RHSA0);
+		    SelectPage(0);
+		    rhsa += 3; /* skip control infos */
+		    if( rhsa >= 0x8000 )
+			rhsa = 0;
+		    if( rhsa + pktlen > 0x8000 ) {
+			unsigned i;
+			u_char *buf = skb_put(skb, pktlen);
+			for(i=0; i < pktlen ; i++, rhsa++ ) {
+			    buf[i] = GetByte(XIRCREG_EDP);
+			    if( rhsa == 0x8000 ) {
+				rhsa = 0;
+				i--;
+			    }
+			}
+		    } else {
+			insw(ioaddr+XIRCREG_EDP,
+				skb_put(skb, pktlen), (pktlen+1)>>1 );
+		    }
+		}
+	      #if 0
+		else if( lp->mohawk ) {
+		    /* To use this 32 bit access we should use
+		     * a manual optimized loop
+		     * Also the words are swapped, we can get more
+		     * performance by using 32 bit access and swapping
+		     * the words in a register. Will need this for cardbus
+		     *
+		     * Note: don't forget to change the ALLOC_SKB to .. +3
+		     */
+		    unsigned i;
+		    u_long *p = skb_put(skb, pktlen);
+		    register u_long a;
+		    ioaddr_t edpreg = ioaddr+XIRCREG_EDP-2;
+		    for(i=0; i < len ; i += 4, p++ ) {
+			a = inl(edpreg);
+			__asm__("rorl $16,%0\n\t"
+				:"=q" (a)
+				: "0" (a));
+			*p = a;
+		    }
+		}
+	      #endif
+		else {
+		    insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen),
+			    (pktlen+1)>>1 );
+		}
+		skb->protocol = eth_type_trans(skb, dev);
+		skb->dev = dev;
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+		lp->stats.rx_bytes += pktlen;
+		if( !(rsr & PhyPkt) )
+		    lp->stats.multicast++;
+	    }
+	    PutWord(XIRCREG0_DO, 0x8000 ); /* issue cmd: skip_rx_packet */
+	}
+	else {
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 5 )
+		printk("rsr=%#02x\n", rsr );
+	  #endif
+	}
+	if( rsr & PktTooLong ) {
+	    lp->stats.rx_frame_errors++;
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 3 )
+		printk(KNOT_XIRC "%s: Packet too long\n", dev->name);
+	  #endif
+	}
+	if( rsr & CRCErr ) {
+	    lp->stats.rx_crc_errors++;
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 3 )
+		printk(KNOT_XIRC "%s: CRC error\n", dev->name);
+	  #endif
+	}
+	if( rsr & AlignErr ) {
+	    lp->stats.rx_fifo_errors++; /* okay ? */
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 3 )
+		printk(KNOT_XIRC "%s: Alignment error\n", dev->name);
+	  #endif
+	}
+
+	/* get the new ethernet status */
+	eth_status = GetByte(XIRCREG_ESR);
+    }
+    if( rx_status & 0x10 ) { /* Receive overrun */
+	lp->stats.rx_over_errors++;
+	PutByte(XIRCREG_CR, ClearRxOvrun);
+      #ifdef PCMCIA_DEBUG
+	if( pc_debug > 3 )
+	    printk(KDBG_XIRC "receive overrun cleared\n" );
+      #endif
+    }
+
+    /***** transmit section ******/
+    if( int_status & PktTxed ) {
+	unsigned n, nn;
+
+	n = lp->last_ptr_value;
+	nn = GetByte(XIRCREG0_PTR);
+	lp->last_ptr_value = nn;
+	if( nn < n ) /* rollover */
+	    lp->stats.tx_packets += 256 - n;
+	else if( n == nn ) { /* happens sometimes - don't know why */
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug )
+		printk(KDBG_XIRC "PTR not changed?\n" );
+	  #endif
+	}
+	else
+	    lp->stats.tx_packets += lp->last_ptr_value - n;
+	dev->tbusy = 0;
+	mark_bh(NET_BH);  /* Inform upper layers. */
+    }
+    if( tx_status & 0x0002 ) {	/* Execessive collissions */
+      #ifdef PCMCIA_DEBUG
+	if( pc_debug )
+	    printk(KDBG_XIRC "tx restarted due to execssive collissions\n" );
+      #endif
+	PutByte(XIRCREG_CR, RestartTx );  /* restart transmitter process */
+    }
+    if( tx_status & 0x0040 )
+	lp->stats.tx_aborted_errors++;
+
+    /* recalculate our work chunk so that we limit the duration of this
+     * ISR to about 1/10 of a second.
+     * Calculate only if we received a reasonable amount of bytes.
+     */
+    if( bytes_rcvd > 1000 ) {
+	u_long duration = jiffies - start_ticks;
+
+	if( duration >= HZ/10 ) { /* if more than about 1/10 second */
+	    maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration;
+	    if( maxrx_bytes < 2000 )
+		maxrx_bytes = 2000;
+	    else if( maxrx_bytes > 22000 )
+		maxrx_bytes = 22000;
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 1)
+		printk(KDBG_XIRC "set maxrx=%u (rcvd=%u ticks=%lu)\n",
+				  maxrx_bytes, bytes_rcvd, duration  );
+	  #endif
+	}
+	else if( !duration && maxrx_bytes < 22000 ) { /* now much faster*/
+	    maxrx_bytes += 2000;
+	    if( maxrx_bytes > 22000 )
+		maxrx_bytes = 22000;
+	  #ifdef PCMCIA_DEBUG
+	    if( pc_debug > 1 )
+		printk(KDBG_XIRC "set maxrx=%u\n", maxrx_bytes );
+	  #endif
+	}
+    }
+
+  leave:
+    if( lockup_hack ) {
+	if( int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0 )
+	    goto loop_entry;
+    }
+    SelectPage(saved_page);
+    dev->interrupt = 0;
+    PutByte(XIRCREG_CR, EnableIntr );  /* re-enable interrupts */
+    /* Instead of dropping packets during a receive, we could
+     * force an interrupt with this command:
+     *	  PutByte(XIRCREG_CR, EnableIntr|ForceIntr );
+     */
+} /* xirc2ps_interrupt */
+
+/*====================================================================*/
+
+static int
+do_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int okay;
+    unsigned freespace;
+    unsigned pktlen = skb? skb->len : 0;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug>1 )
+	printk(KDBG_XIRC "do_start_xmit(skb=%p, dev=%p) len=%u\n",
+						    skb, dev, pktlen );
+  #endif
+
+    /* Transmitter timeout, serious problems */
+    if( dev->tbusy ) {
+	int tickssofar = jiffies - dev->trans_start;
+
+	if( lp->suspended ) {
+	    dev_kfree_skb (skb);
+	    dev->trans_start = jiffies;
+	    lp->stats.tx_dropped++;
+	    return 0;
+	}
+	if( tickssofar < TX_TIMEOUT )
+	    return 1;
+
+	printk(KERN_NOTICE "%s: transmit timed out\n", dev->name );
+	lp->stats.tx_errors++;
+	/* reset the card */
+	do_reset(dev,1);
+	dev->trans_start = jiffies;
+	dev->tbusy = 0;
+    }
+
+    if( test_and_set_bit(0, (void*)&dev->tbusy ) ) {
+	printk(KWRN_XIRC "transmitter access conflict\n");
+	dev_kfree_skb (skb);
+	return 0;
+    }
+
+    /* adjust the packet length to min. required
+     * and hope that the buffer is large enough
+     * to provide some random data.
+     * fixme: For Mohawk we can change this by sending
+     * a larger packetlen than we actually have; the chip will
+     * pad this in his buffer with random bytes
+     */
+    if( pktlen < ETH_ZLEN )
+	pktlen = ETH_ZLEN;
+
+    SelectPage(0);
+    PutWord(XIRCREG0_TRS, (u_short)pktlen+2 );
+    freespace = GetWord(XIRCREG0_TSO);
+    okay = freespace & 0x8000;
+    freespace &= 0x7fff;
+    /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */
+    okay = pktlen +2 < freespace;
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug > 2  + ( okay ? 2 : 0) )
+	printk(KERN_DEBUG "%s: avail. tx space=%u%s\n", dev->name, freespace,
+				okay? " (okay)":" (not enough)" );
+  #endif
+    if( !okay ) { /* not enough space */
+	dev->tbusy = 1;
+	return 1;  /* upper layer may decide to requeue this packet */
+    }
+    /* send the packet */
+    PutWord(XIRCREG_EDP, (u_short)pktlen );
+    outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1 );
+    if( pktlen & 1 )
+	PutByte(XIRCREG_EDP, skb->data[pktlen-1] );
+
+    if( lp->mohawk )
+	PutByte(XIRCREG_CR, TransmitPacket|EnableIntr );
+
+    dev_kfree_skb (skb);
+    dev->trans_start = jiffies;
+    dev->tbusy = 0;
+    lp->stats.tx_bytes += pktlen;
+    return 0;
+}
+
+static struct enet_statistics *
+do_get_stats(struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+
+    /*	lp->stats.rx_missed_errors = GetByte(?) */
+    return &lp->stats;
+}
+
+/****************
+ * Set all addresses: This first one is the individual address,
+ * the next 9 addresses are taken from the multicast list and
+ * the rest is filled with the individual address.
+ */
+static void
+set_addresses(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    local_info_t *lp = dev->priv;
+    struct dev_mc_list *dmi = dev->mc_list;
+    char *addr;
+    int i,j,k,n;
+
+    SelectPage(k=0x50);
+    for(i=0,j=8,n=0; ; i++, j++) {
+	if( i > 5 ) {
+	    if( ++n > 9 )
+		break;
+	    i = 0;
+	}
+	if( j > 15 ) {
+	    j = 8;
+	    k++;
+	    SelectPage(k);
+	}
+
+	if( n && n <= dev->mc_count && dmi ) {
+	    addr = dmi->dmi_addr;
+	    dmi = dmi->next;
+	}
+	else
+	    addr = dev->dev_addr;
+
+	if( lp->mohawk )
+	    PutByte( j, addr[5-i] );
+	else
+	    PutByte( j, addr[i] );
+    }
+    SelectPage(0);
+}
+
+/****************
+ * Set or clear the multicast filter for this adaptor.
+ * We can filter up to 9 addresses, if more are requested we set
+ * multicast promiscuous mode.
+ */
+
+static void
+set_multicast_list(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+
+    SelectPage(0x42);
+    if( dev->flags & IFF_PROMISC ) { /* snoop */
+	PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */
+    }
+    else if( dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI) ) {
+	PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */
+    }
+    else if( dev->mc_count ) { /* the chip can filter 9 addresses perfectly */
+	PutByte(XIRCREG42_SWC1, 0x00);
+	SelectPage(0x40);
+	PutByte(XIRCREG40_CMD0, Offline );
+	set_addresses(dev);
+	SelectPage(0x40);
+	PutByte(XIRCREG40_CMD0, EnableRecv | Online );
+    }
+    else { /* standard usage */
+	PutByte(XIRCREG42_SWC1, 0x00);
+    }
+    SelectPage(0);
+}
+
+/****************
+ * We never need to do anything when a IIps device is "initialized"
+ * by the net software, because we only register already-found cards.
+ */
+static int
+do_init(struct net_device *dev)
+{
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "do_init(%p)\n", dev );
+  #endif
+    return 0;
+}
+
+static int
+do_config(struct net_device *dev, struct ifmap *map)
+{
+    local_info_t *local = dev->priv;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "do_config(%p)\n", dev );
+  #endif
+
+    if( map->port != 255 && map->port != dev->if_port ) {
+	if( map->port <= 4 ) {
+	    if( !map->port ) {
+		local->probe_port = 1;
+		dev->if_port = 1;
+	    }
+	    else {
+		local->probe_port = 0;
+		dev->if_port = map->port;
+	    }
+	    printk(KERN_INFO "%s: switching to %s port\n",
+			      dev->name, if_names[dev->if_port]);
+	    do_reset(dev,1);  /* not the fine way :-) */
+	}
+	else
+	    return -EINVAL;
+    }
+  #ifdef PCMCIA_DEBUG
+    else if( map->port == dev->if_port && local->mohawk ) {
+	/* kludge to print the mii regsiters */
+	mii_dump(dev);
+    }
+  #endif
+    return 0;
+}
+
+/****************
+ * Open the driver
+ */
+static int
+do_open(struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+    dev_link_t *link;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "do_open(%p)\n", dev );
+  #endif
+
+    /* Check that the PCMCIA card is still here. */
+    for( link = dev_list; link; link = link->next )
+	if( link->priv == dev )
+	    break;
+    /* Physical device present signature. */
+    if( !DEV_OK(link) )
+	return -ENODEV;
+
+    /* okay */
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    lp->suspended = 0;
+    do_reset(dev,1);
+
+    return 0;
+}
+
+static int
+do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u16 *data = (u16 *)&rq->ifr_data;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug > 1)
+	printk(KERN_DEBUG "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n",
+			   dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+			   data[0], data[1], data[2], data[3] );
+  #endif
+
+    if( !local->mohawk )
+	return -EOPNOTSUPP;
+
+    switch( cmd ) {
+      case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
+	data[0] = 0;		/* we have only this address */
+	/* fall trough */
+      case SIOCDEVPRIVATE+1:	/* Read the specified MII register. */
+	data[3] = mii_rd( ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+	break;
+      case SIOCDEVPRIVATE+2:	/* Write the specified MII register */
+	if( !suser() )
+	    return -EPERM;
+	mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16);
+	break;
+      default:
+	return -EOPNOTSUPP;
+    }
+    return 0;
+}
+
+static void
+hardreset(struct net_device *dev)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    SelectPage(4);
+    udelay(1);
+    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
+    busy_loop(HZ/25);		     /* wait 40 msec */
+    if( local->mohawk )
+	PutByte(XIRCREG4_GPR1, 1);	 /* set bit 0: power up */
+    else
+	PutByte(XIRCREG4_GPR1, 1 | 4);	 /* set bit 0: power up, bit 2: AIC */
+    busy_loop(HZ/50);		     /* wait 20 msec */
+}
+
+static void
+do_reset(struct net_device *dev, int full)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned value;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KERN_DEBUG "%s: do_reset(%p,%d)\n",
+					  dev? dev->name:"eth?", dev, full );
+  #endif
+
+    hardreset(dev);
+    PutByte(XIRCREG_CR, SoftReset ); /* set */
+    busy_loop(HZ/50);		     /* wait 20 msec */
+    PutByte(XIRCREG_CR, 0 );	     /* clear */
+    busy_loop(HZ/25);		     /* wait 40 msec */
+    if( local->mohawk ) {
+	SelectPage(4);
+	/* set pin GP1 and GP2 to output  (0x0c)
+	 * set GP1 to low to power up the ML6692 (0x00)
+	 * set GP2 to high to power up the 10Mhz chip  (0x02)
+	 */
+	PutByte(XIRCREG4_GPR0, 0x0e);
+    }
+
+    /* give the circuits some time to power up */
+    busy_loop(HZ/2);		/* about 500ms */
+
+    local->last_ptr_value = 0;
+    local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4
+				   : (GetByte(XIRCREG4_BOV) & 0x30) >> 4;
+
+    if( local->probe_port ) {
+	if( !local->mohawk ) {
+	    SelectPage(4);
+	    PutByte(XIRCREG4_GPR0, 4);
+	    local->probe_port = 0;
+	}
+    }
+    else if( dev->if_port == 2 ) { /* enable 10Base2 */
+	SelectPage(0x42);
+	PutByte(XIRCREG42_SWC1, 0xC0);
+    }
+    else { /* enable 10BaseT */
+	SelectPage(0x42);
+	PutByte(XIRCREG42_SWC1, 0x80);
+    }
+    busy_loop(HZ/25);		     /* wait 40 msec to let it complete */
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug) {
+	SelectPage(0);
+	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
+	printk(KERN_DEBUG "%s: ESR is: %#02x\n", dev->name, value);
+    }
+  #endif
+
+    /* setup the ECR */
+    SelectPage(1);
+    PutByte(XIRCREG1_IMR0, 0xff ); /* allow all ints */
+    PutByte(XIRCREG1_IMR1, 1	); /* and Set TxUnderrunDetect */
+    value = GetByte(XIRCREG1_ECR);
+  #if 0
+    if( local->mohawk )
+	value |= DisableLinkPulse;
+    PutByte(XIRCREG1_ECR, value);
+  #endif
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KERN_DEBUG "%s: ECR is: %#02x\n", dev->name, value);
+  #endif
+
+    SelectPage(0x42);
+    PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */
+
+    if( local->silicon != 1 ) {
+	/* set the local memory dividing line.
+	 * The comments in the sample code say that this is only
+	 * settable with the scipper version 2 which is revision 0.
+	 * Always for CE3 cards
+	 */
+	SelectPage(2);
+	PutWord(XIRCREG2_RBS, 0x2000 );
+    }
+
+    if( full )
+	set_addresses(dev);
+
+    /* Hardware workaround:
+     * The receive byte pointer after reset is off by 1 so we need
+     * to move the offset pointer back to 0.
+     */
+    SelectPage(0);
+    PutWord(XIRCREG0_DO, 0x2000 ); /* change offset command, off=0 */
+
+    /* setup MAC IMRs and clear status registers */
+    SelectPage(0x40);		     /* Bit 7 ... bit 0 */
+    PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */
+    PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
+    PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, rsv*/
+    PutByte(XIRCREG40_RXST0,  0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */
+    PutByte(XIRCREG40_TXST0,  0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
+    PutByte(XIRCREG40_TXST1,  0x00); /* TEN, rsv, PTD, EXT, retry_counter:4  */
+
+    if( full && local->mohawk && init_mii(dev) ) {
+	if( dev->if_port == 4 || local->dingo ) { /* and use it */
+	    SelectPage(2);
+	    value = GetByte(XIRCREG2_MSR);
+	    value |= 0x08;     /* Select MII */
+	    PutByte(XIRCREG2_MSR, value);
+	    busy_loop(HZ/50);	/* wait 20 msec */
+	  #ifdef PCMCIA_DEBUG
+	    if(pc_debug)
+		printk(KERN_DEBUG "%s: MII selected\n", dev->name);
+	  #endif
+	}
+	else {
+	    SelectPage(2);
+	    PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
+	    busy_loop(HZ/50);
+	  #ifdef PCMCIA_DEBUG
+	    if(pc_debug)
+		printk(KERN_DEBUG "%s: MII detected; using 10mbs\n",
+								dev->name);
+	  #endif
+	    SelectPage(0x42);
+	    if( dev->if_port == 2 ) /* enable 10Base2 */
+		PutByte(XIRCREG42_SWC1, 0xC0);
+	    else  /* enable 10BaseT */
+		PutByte(XIRCREG42_SWC1, 0x80);
+	    busy_loop(HZ/25);	/* wait 40 msec to let it complete */
+	}
+    }
+    else {  /* No MII */
+	SelectPage(0);
+	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
+	dev->if_port = (value & MediaSelect) ? 1 : 2;
+    }
+
+    /* configure the LEDs */
+    SelectPage(2);
+    if( dev->if_port == 1 || dev->if_port == 4 ) /* TP: Link and Activity */
+	PutByte(XIRCREG2_LED, 0x3b );
+    else			      /* Coax: Not-Collision and Activity */
+	PutByte(XIRCREG2_LED, 0x3a );
+
+    if (local->dingo)
+	PutByte( 0x0b, 0x04 ); /* 100 Mbit LED */
+
+    /* enable receiver and put the mac online */
+    if( full ) {
+	SelectPage(0x40);
+	PutByte(XIRCREG40_CMD0, EnableRecv | Online );
+    }
+
+    /* setup Ethernet IMR and enable interrupts */
+    SelectPage(1);
+    PutByte(XIRCREG1_IMR0, 0xff );
+    udelay(1);
+    SelectPage(0);
+    PutByte(XIRCREG_CR, EnableIntr );
+    if( local->modem && !local->dingo ) { /* do some magic */
+	if( !(GetByte( 0x10 ) & 0x01 ) )
+	    PutByte( 0x10, 0x11 ); /* unmask master-int bit */
+    }
+
+    if( full )
+	printk(KERN_INFO "%s: media %s, silicon revision %d\n", dev->name,
+				      if_names[dev->if_port], local->silicon);
+    /* We should switch back to page 0 to avoid a bug in revision 0
+     * where regs with offset below 8 can't be read after an access
+     * to the MAC registers */
+    SelectPage(0);
+}
+
+/****************
+ * Initialize the Media-Independent-Interface
+ * Returns: True if we have a good MII
+ */
+static int
+init_mii(struct net_device *dev)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned control, status, linkpartner;
+    int i;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug>1) {
+	mii_dump(dev);
+    }
+  #endif
+
+    status = mii_rd(ioaddr,  0, 1 );
+    if( (status & 0xff00) != 0x7800 )
+	return 0; /* No MII */
+
+    if( local->probe_port )
+	control = 0x1000; /* auto neg */
+    else if( dev->if_port == 4 )
+	control = 0x2000; /* no auto neg, 100mbs mode */
+    else
+	control = 0x0000; /* no auto neg, 10mbs mode */
+    mii_wr(ioaddr,  0, 0, control, 16 );
+    udelay(100);
+    control = mii_rd(ioaddr, 0, 0 );
+
+    if( control & 0x0400 ) {
+	printk(KERN_NOTICE "%s can't take PHY out of isolation mode\n",
+								dev->name);
+	local->probe_port = 0;
+	return 0;
+    }
+
+    if( local->probe_port ) {
+	/* according to the DP83840A specs the auto negotation process
+	 * may take up to 3.5 sec, so we use this also for our ML6692
+	 * Fixme: Better to use a timer here!
+	 */
+	for(i=0; i < 35; i++ ) {
+	    busy_loop(HZ/10);	 /* wait 100 msec */
+	    status = mii_rd(ioaddr,  0, 1 );
+	    if( (status & 0x0020) && (status & 0x0004) )
+		break;
+	}
+
+	if( !(status & 0x0020) ) {
+	    printk(KERN_NOTICE "%s: auto negotation failed;"
+			       " using 10mbs\n", dev->name );
+	    control = 0x0000;
+	    mii_wr(ioaddr,  0, 0, control, 16 );
+	    udelay(100);
+	    SelectPage(0);
+	    dev->if_port = (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2;
+	}
+	else {
+	    linkpartner = mii_rd(ioaddr, 0, 5 );
+	    printk(KERN_INFO "%s: MII link partner: %04x\n", dev->name,
+							linkpartner );
+	    if( linkpartner & 0x0080 ) { /* 100BaseTx capability */
+		dev->if_port = 4;
+	    }
+	    else
+		dev->if_port = 1;
+	}
+	local->probe_port = 0;
+    }
+
+  #ifdef PCMCIA_DEBUG
+    if( pc_debug )
+	mii_dump(dev);
+  #endif
+
+    return 1;
+}
+
+static void
+do_powerdown(struct net_device *dev)
+{
+
+    ioaddr_t ioaddr = dev->base_addr;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "do_powerdown(%p)\n", dev );
+  #endif
+
+    SelectPage(4);
+    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
+    SelectPage(0);
+}
+
+static int
+do_stop( struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    dev_link_t *link;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "do_stop(%p)\n", dev );
+  #endif
+
+    for(link = dev_list; link; link = link->next)
+	if(link->priv == dev)
+	    break;
+    if( !link )
+	return -ENODEV;
+
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "shutting down\n");
+  #endif
+    dev->tbusy = 1;
+    dev->start = 0;
+
+    SelectPage(0);
+    PutByte(XIRCREG_CR, 0 );  /* disable interrupts */
+    SelectPage(0x01);
+    PutByte(XIRCREG1_IMR0, 0x00 ); /* forbid all ints */
+    SelectPage(4);
+    PutByte(XIRCREG4_GPR1, 0);	/* clear bit 0: power down */
+    SelectPage(0);
+
+    link->open--; dev->start = 0;
+    if (link->state & DEV_STALE_CONFIG) {
+	link->release.expires = jiffies + HZ/20;
+	link->state |= DEV_RELEASE_PENDING;
+	add_timer(&link->release);
+    }
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+}
+
+static int __init
+init_xirc2ps_cs(void)
+{
+    servinfo_t serv;
+
+    printk(KERN_INFO "%s\n", version);
+    if( card_type )
+	printk(KINF_XIRC "option card_type is obsolete\n");
+    if( lockup_hack )
+	printk(KINF_XIRC "lockup hack is enabled\n");
+    CardServices(GetCardServicesInfo, &serv);
+    if( serv.Revision != CS_RELEASE_CODE ) {
+	printk(KNOT_XIRC "Card Services release does not match!\n");
+	return -1;
+    }
+  #ifdef PCMCIA_DEBUG
+    if( pc_debug )
+	printk(KDBG_XIRC "pc_debug=%d\n", pc_debug);
+  #endif
+    register_pccard_driver(&dev_info, &xirc2ps_attach, &xirc2ps_detach);
+    return 0;
+}
+
+static void __exit
+exit_xirc2ps_cs(void)
+{
+  #ifdef PCMCIA_DEBUG
+    if(pc_debug)
+	printk(KDBG_XIRC "unloading\n");
+  #endif
+    unregister_pccard_driver(&dev_info);
+    while( dev_list ) {
+	if( dev_list->state & DEV_CONFIG )
+	    xirc2ps_release( (u_long)dev_list );
+	if( dev_list )	/* xirc2ps_release() might already have detached... */
+	    xirc2ps_detach( dev_list );
+    }
+}
+
+module_init(init_xirc2ps_cs);
+module_exit(exit_xirc2ps_cs);
+
diff -u --recursive --new-file v2.3.22/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v2.3.22/linux/drivers/net/slhc.c	Thu Aug  5 14:35:52 1999
+++ linux/drivers/net/slhc.c	Mon Oct 18 11:26:31 1999
@@ -758,12 +758,6 @@
 
 #endif /* MODULE */
 #else /* CONFIG_INET */
-EXPORT_SYMBOL(slhc_init);
-EXPORT_SYMBOL(slhc_free);
-EXPORT_SYMBOL(slhc_remember);
-EXPORT_SYMBOL(slhc_compress);
-EXPORT_SYMBOL(slhc_uncompress);
-EXPORT_SYMBOL(slhc_toss);
 
 int
 slhc_toss(struct slcompress *comp)
@@ -804,5 +798,11 @@
   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
   return NULL;
 }
+EXPORT_SYMBOL(slhc_init);
+EXPORT_SYMBOL(slhc_free);
+EXPORT_SYMBOL(slhc_remember);
+EXPORT_SYMBOL(slhc_compress);
+EXPORT_SYMBOL(slhc_uncompress);
+EXPORT_SYMBOL(slhc_toss);
 
 #endif /* CONFIG_INET */
diff -u --recursive --new-file v2.3.22/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.3.22/linux/drivers/net/starfire.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/starfire.c	Tue Oct 19 10:32:24 1999
@@ -81,6 +81,7 @@
 #endif
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/timer.h>
diff -u --recursive --new-file v2.3.22/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.22/linux/drivers/net/via-rhine.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/via-rhine.c	Tue Oct 19 10:32:24 1999
@@ -111,11 +111,6 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
-#else
-#ifndef __alpha__
-#define ioremap vremap
-#define iounmap vfree
-#endif
 #endif
 #if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
diff -u --recursive --new-file v2.3.22/linux/drivers/pci/helper.c linux/drivers/pci/helper.c
--- v2.3.22/linux/drivers/pci/helper.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/pci/helper.c	Tue Oct 19 13:48:24 1999
@@ -57,7 +57,7 @@
 			if (match_limit && match_limit == matches)
 				return matches;
 
-			ent++;
+			break; /* stop list search on first match */
 		}
 
 		dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, dev);
diff -u --recursive --new-file v2.3.22/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.22/linux/drivers/pci/pci.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/pci/pci.c	Fri Oct 15 18:55:26 1999
@@ -140,6 +140,64 @@
 	return best;
 }
 
+/*
+ *  Set power management state of a device.  For transitions from state D3
+ *  it isn't as straightforward as one could assume since many devices forget
+ *  their configuration space during wakeup.  Returns old power state.
+ */
+int
+pci_set_power_state(struct pci_dev *dev, int new_state)
+{
+	u32 base[5], romaddr;
+	u16 pci_command, pwr_command;
+	u8  pci_latency, pci_cacheline;
+	int i, old_state;
+	int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+	if (!pm)
+		return 0;
+	pci_read_config_word(dev, pm + PCI_PM_CTRL, &pwr_command);
+	old_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+	if (old_state == new_state)
+		return old_state;
+	DBG("PCI: %s goes from D%d to D%d\n", dev->slot_name, old_state, new_state);
+	if (old_state == 3) {
+		pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+		pci_write_config_word(dev, PCI_COMMAND, pci_command & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+		for (i = 0; i < 5; i++)
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, &base[i]);
+		pci_read_config_dword(dev, PCI_ROM_ADDRESS, &romaddr);
+		pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+		pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+		pci_write_config_word(dev, pm + PCI_PM_CTRL, new_state);
+		for (i = 0; i < 5; i++)
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, base[i]);
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, romaddr);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cacheline);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, pci_latency);
+		pci_write_config_word(dev, PCI_COMMAND, pci_command);
+	} else
+		pci_write_config_word(dev, pm + PCI_PM_CTRL, (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | new_state);
+	return old_state;
+}
+
+/*
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O and memory. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int
+pci_enable_device(struct pci_dev *dev)
+{
+	int err;
+
+	if ((err = pcibios_enable_device(dev)) < 0)
+		return err;
+	pci_set_power_state(dev, 0);
+	return 0;
+}
+
 
 /*
  * This interrupt-safe spinlock protects all accesses to PCI
diff -u --recursive --new-file v2.3.22/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.3.22/linux/drivers/pci/quirks.c	Fri Oct 15 15:25:14 1999
+++ linux/drivers/pci/quirks.c	Mon Oct 18 11:34:30 1999
@@ -128,6 +128,7 @@
 	 */
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C596,	quirk_isa_dma_hangs },
+	{ PCI_FIXUP_FINAL,      PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437, 	quirk_triton }, 
diff -u --recursive --new-file v2.3.22/linux/drivers/pci/setup.c linux/drivers/pci/setup.c
--- v2.3.22/linux/drivers/pci/setup.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/pci/setup.c	Fri Oct 15 18:55:26 1999
@@ -323,3 +323,9 @@
 	for (dev = pci_devices; dev; dev = dev->next)
 		pdev_fixup_irq(dev, swizzle, map_irq);
 }
+
+int
+pcibios_enable_device(struct pci_dev *dev)
+{
+	return 0;
+}
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in
--- v2.3.22/linux/drivers/pcmcia/Config.in	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/Config.in	Wed Oct 20 21:33:12 1999
@@ -2,13 +2,15 @@
 # PCMCIA bus subsystem configuration
 #
 mainmenu_option next_comment
-comment 'PCMCIA/Cardbus support'
+comment 'PCMCIA/CardBus support'
 
-tristate 'PCMCIA/Cardbus support' CONFIG_PCMCIA
+tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
 if [ "$CONFIG_PCMCIA" != "n" ]; then
    if [ "$CONFIG_PCI" != "n" ]; then
       bool '  CardBus support' CONFIG_CARDBUS
    fi
+   bool '  i82365/Yenta compatible bridge support' CONFIG_I82365
+   bool '  Databook TCIC host bridge support' CONFIG_TCIC
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile
--- v2.3.22/linux/drivers/pcmcia/Makefile	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/Makefile	Wed Oct 20 21:33:12 1999
@@ -15,20 +15,34 @@
 MOD_LIST_NAME := PCMCIA_MODULES
 
 ifeq ($(CONFIG_PCMCIA),y)
-  O_OBJS   := i82365.o tcic.o cistpl.o rsrc_mgr.o bulkmem.o
+  O_OBJS   := cistpl.o rsrc_mgr.o bulkmem.o
   OX_OBJS  := ds.o cs.o
   O_TARGET := pcmcia.o
+  ifeq ($(CONFIG_I82365),y)
+    O_OBJS += i82365.o
+  endif
+  ifeq ($(CONFIG_TCIC),y)
+    O_OBJS += tcic.o
+  endif
   ifeq ($(CONFIG_CARDBUS),y)
     O_OBJS += cardbus.o
+    OX_OBJS += cb_enabler.o
   endif
 else
   ifeq ($(CONFIG_PCMCIA),m)
-     M_OBJS   := i82365.o tcic.o pcmcia_core.o 
+     M_OBJS   := pcmcia_core.o 
      MX_OBJS  := ds.o
      MIX_OBJS  := cs.o
      CORE_OBJS := cistpl.o rsrc_mgr.o bulkmem.o cs.o
+    ifeq ($(CONFIG_I82365),y)
+      M_OBJS += i82365.o
+    endif
+    ifeq ($(CONFIG_TCIC),y)
+      M_OBJS += tcic.o
+    endif
      ifeq ($(CONFIG_CARDBUS),y)
 	CORE_OBJS += cardbus.o
+	MX_OBJS += cb_enabler.o
      endif
   endif
 endif
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- v2.3.22/linux/drivers/pcmcia/cardbus.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/cardbus.c	Wed Oct 20 21:33:12 1999
@@ -2,7 +2,7 @@
   
     Cardbus device configuration
     
-    cardbus.c 1.59 1999/09/15 15:32:19
+    cardbus.c 1.61 1999/10/20 22:36:57
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -325,9 +325,9 @@
 	pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class);
 	c[i].dev.class >>= 8;
 	c[i].dev.hdr_type = hdr;
-#ifdef CONFIG_PROC_FS	
+#ifdef CONFIG_PROC_FS
 	pci_proc_attach_device(&c[i].dev);
-#endif	
+#endif
     }
     
     return CS_SUCCESS;
@@ -344,9 +344,9 @@
 	    if (*p == &c[0].dev) break;
 	for (q = *p; q; q = q->next) {
 	    if (q->bus != (*p)->bus) break;
-#ifdef CONFIG_PROC_FS	    
+#ifdef CONFIG_PROC_FS
 	    pci_proc_detach_device(q);
-#endif	    
+#endif
 	}
 	if (*p) *p = q;
 	s->cap.cb_bus->devices = NULL;
@@ -496,7 +496,8 @@
 	    s->irq.AssignedIRQ = irq;
 	}
     }
-    c[0].dev.irq = irq;
+    for (i = 0; i < fn; i++)
+	c[i].dev.irq = irq;
     
     return CS_SUCCESS;
 
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c
--- v2.3.22/linux/drivers/pcmcia/cb_enabler.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/cb_enabler.c	Wed Oct 20 21:33:12 1999
@@ -2,7 +2,7 @@
 
     Cardbus device enabler
 
-    cb_enabler.c 1.23 1999/09/15 15:32:19
+    cb_enabler.c 1.24 1999/10/20 00:19:09
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -58,7 +58,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"cb_enabler.c 1.23 1999/09/15 15:32:19 (David Hinds)";
+"cb_enabler.c 1.24 1999/10/20 00:19:09 (David Hinds)";
 #else
 #define DEBUG(n, args...) do { } while (0)
 #endif
@@ -371,6 +371,9 @@
 }
 
 /*====================================================================*/
+
+EXPORT_SYMBOL(register_driver);
+EXPORT_SYMBOL(unregister_driver);
 
 static int __init init_cb_enabler(void)
 {
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.3.22/linux/drivers/pcmcia/cs.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/cs.c	Wed Oct 20 21:33:12 1999
@@ -2,7 +2,7 @@
 
     PCMCIA Card Services -- core services
 
-    cs.c 1.228 1999/09/15 15:32:19
+    cs.c 1.232 1999/10/20 22:17:24
     
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -70,7 +70,7 @@
 int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 static const char *version =
-"cs.c 1.228 1999/09/15 15:32:19 (David Hinds)";
+"cs.c 1.232 1999/10/20 22:17:24 (David Hinds)";
 #endif
 
 static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
@@ -353,41 +353,40 @@
     socket_info_t *s = NULL;
     client_t *client;
 
+#ifdef CONFIG_PROC_FS
+    for (i = 0; i < sockets; i++) {
+	s = socket_table[i];
+	if (s->ss_entry != ss_entry) continue;
+	if (proc_pccard) {
+	    char name[3];
+	    sprintf(name, "%02d", i);
+#ifdef PCMCIA_DEBUG
+	    remove_proc_entry("clients", s->proc);
+#endif
+	}
+    }
+#endif
+
     for (;;) {
 	for (i = 0; i < sockets; i++) {
 	    s = socket_table[i];
 	    if (s->ss_entry == ss_entry) break;
 	}
-	if (i == sockets) {
+	if (i == sockets)
 	    break;
-	} else {
-#ifdef CONFIG_PROC_FS
-	    if (proc_pccard) {
-		char name[3];
-		sprintf(name, "%02d", i);
-#ifdef PCMCIA_DEBUG
-		remove_proc_entry("clients", s->proc);
-#endif
-		remove_proc_entry(name, proc_pccard);
-	    }
-#endif
-	    while (s->clients) {
-		client = s->clients;
-		s->clients = s->clients->next;
-		kfree(client);
-	    }
-	    init_socket(s);
-	    release_cis_mem(s);
-#ifdef CONFIG_CARDBUS
-	    cb_release_cis_mem(s);
-#endif
-	    s->ss_entry = NULL;
-	    kfree(s);
-	    socket_table[i] = NULL;
-	    for (j = i; j < sockets-1; j++)
-		socket_table[j] = socket_table[j+1];
-	    sockets--;
-	}
+	shutdown_socket(i);
+	release_cis_mem(s);
+	while (s->clients) {
+	    client = s->clients;
+	    s->clients = s->clients->next;
+	    kfree(client);
+	}
+	s->ss_entry = NULL;
+	kfree(s);
+	socket_table[i] = NULL;
+	for (j = i; j < sockets-1; j++)
+	    socket_table[j] = socket_table[j+1];
+	sockets--;
     }
     
 } /* unregister_ss_entry */
@@ -1808,7 +1807,7 @@
 {
     socket_info_t *s;
     window_t *win;
-    int w;
+    int w, align;
     
     if (CHECK_HANDLE(*handle))
 	return CS_BAD_HANDLE;
@@ -1835,9 +1834,10 @@
     win->sock = s;
     win->base = req->Base;
     win->size = req->Size;
+    align = ((s->cap.features & SS_CAP_MEM_ALIGN) ||
+	     (req->Attributes & WIN_STRICT_ALIGN));
     if (find_mem_region(&win->base, win->size, (*handle)->dev_info,
-			((s->cap.features & SS_CAP_MEM_ALIGN) ?
-			 req->Size : s->cap.map_size),
+			(align ? req->Size : s->cap.map_size),
 			(req->Attributes & WIN_MAP_BELOW_1MB) ||
 			!(s->cap.features & SS_CAP_PAGE_REGS)))
 	return CS_IN_USE;
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.3.22/linux/drivers/pcmcia/i82365.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/i82365.c	Wed Oct 20 21:33:12 1999
@@ -3,7 +3,7 @@
     Device driver for Intel 82365 and compatible PC Card controllers,
     and Yenta-compatible PCI-to-CardBus controllers.
 
-    i82365.c 1.254 1999/09/15 15:32:19
+    i82365.c 1.260 1999/10/21 00:56:07
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -76,7 +76,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static const char *version =
-"i82365.c 1.254 1999/09/15 15:32:19 (David Hinds)";
+"i82365.c 1.260 1999/10/21 00:56:07 (David Hinds)";
 #else
 #define DEBUG(n, args...) do { } while (0)
 #endif
@@ -189,7 +189,7 @@
 #ifdef CONFIG_ISA
 #ifdef CONFIG_PCI
 /* PCI card status change interrupts? */
-static int pci_csc = 0;
+static int pci_csc = 1;
 /* PCI IO card functional interrupts? */
 static int pci_int = 0;
 MODULE_PARM(pci_csc, "i");
@@ -240,7 +240,7 @@
 typedef struct socket_info_t {
     u_short		type, flags;
     socket_cap_t	cap;
-    u_short		ioaddr;
+    ioaddr_t		ioaddr;
     u_short		psock;
     u_char		cs_irq, intr;
     void		(*handler)(void *info, u_int events);
@@ -278,18 +278,18 @@
 /* Default ISA interrupt mask */
 #define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
 
-static void pcic_interrupt_wrapper(u_long);
-static void pcic_interrupt(int irq, void *dev,
-				    struct pt_regs *regs);
-static int pcic_service(u_int sock, u_int cmd, void *arg);
-#ifdef CONFIG_PROC_FS
-static void pcic_proc_remove(u_short sock);
-#endif
-
 #ifdef CONFIG_ISA
 static int grab_irq;
 static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+#define ISA_LOCK(n, f) \
+    if (!(socket[n].flags & IS_CARDBUS)) spin_lock_irqsave(&isa_lock, f)
+#define ISA_UNLOCK(n, f) \
+    if (!(socket[n].flags & IS_CARDBUS)) spin_unlock_irqrestore(&isa_lock, f)
+#else
+#define ISA_LOCK(n, f) do { } while (0)
+#define ISA_UNLOCK(n, f) do { } while (0)
 #endif
+
 static struct timer_list poll_timer;
 
 /*====================================================================*/
@@ -322,7 +322,7 @@
 #ifdef CONFIG_PCI
     IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730,
     IS_I82092AA, IS_OM82C092G,
-    IS_PD6832, IS_OZ6832, IS_OZ6836,
+    IS_PD6832, IS_OZ6832, IS_OZ6836, IS_OZ6812,
     IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478,
     IS_SMC34C90,
     IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210,
@@ -388,6 +388,8 @@
       PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 },
     { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
       PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 },
+    { "O2Micro OZ6812", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6812 },
     { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
       PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 },
     { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
@@ -441,8 +443,6 @@
 
 /* Some PCI shortcuts */
 
-#ifdef CONFIG_PCI
-
 #define pci_readb		pcibios_read_config_byte
 #define pci_writeb		pcibios_write_config_byte
 #define pci_readw		pcibios_read_config_word
@@ -457,7 +457,6 @@
 
 static void cb_get_power(u_short sock, socket_state_t *state);
 static void cb_set_power(u_short sock, socket_state_t *state);
-#endif
 
 /*====================================================================*/
 
@@ -469,7 +468,7 @@
     else
 #endif
     {
-	u_short port = socket[sock].ioaddr;
+	ioaddr_t port = socket[sock].ioaddr;
 	u_char val;
 	reg = I365_REG(socket[sock].psock, reg);
 	outb(reg, port); val = inb(port+1);
@@ -485,7 +484,7 @@
     else
 #endif
     {
-	u_short port = socket[sock].ioaddr;
+	ioaddr_t port = socket[sock].ioaddr;
 	u_char val = I365_REG(socket[sock].psock, reg);
 	outb(val, port); outb(data, port+1);
     }
@@ -954,6 +953,8 @@
 	p->mode_e &= ~O2_MODE_E_MHPG_DMA;
 	p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA;
 	p->mhpg &= ~O2_MHPG_CHANNEL;
+	if (t->revision == 0x34)
+	    p->mode_c = 0x20;
     } else {
 	if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000;
     }
@@ -1125,7 +1126,7 @@
     
 ======================================================================*/
 
-static void get_host_state(u_short s)
+static void get_bridge_state(u_short s)
 {
     socket_info_t *t = &socket[s];
     if (t->flags & IS_CIRRUS)
@@ -1148,7 +1149,7 @@
 #endif
 }
 
-static void set_host_state(u_short s)
+static void set_bridge_state(u_short s)
 {
     socket_info_t *t = &socket[s];
 #ifdef CONFIG_PCI
@@ -1178,7 +1179,7 @@
 #endif
 }
 
-static u_int __init set_host_opts(u_short s, u_short ns)
+static u_int __init set_bridge_opts(u_short s, u_short ns)
 {
     u_short i;
     u_int m = 0xffff;
@@ -1190,7 +1191,7 @@
 	    continue;
 	}
 	buf[0] = '\0';
-	get_host_state(i);
+	get_bridge_state(i);
 	if (socket[i].flags & IS_CIRRUS)
 	    m = cirrus_set_opts(i, buf);
 #ifdef CONFIG_ISA
@@ -1209,7 +1210,7 @@
 	if (socket[i].flags & IS_CARDBUS)
 	    cb_set_opts(i, buf+strlen(buf));
 #endif
-	set_host_state(i);
+	set_bridge_state(i);
 	printk(KERN_INFO "    host opts [%d]:%s\n", i,
 	       (*buf) ? buf : " none");
     }
@@ -1255,7 +1256,7 @@
     if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0)
 	return 1;
     irq_hits = 0; irq_sock = sock;
-    current->state = TASK_INTERRUPTIBLE;
+    __set_current_state(TASK_UNINTERRUPTIBLE);
     schedule_timeout(HZ/100);
     if (irq_hits) {
 	free_irq(irq, NULL);
@@ -1310,7 +1311,7 @@
 	(cb_set_irq_mode(sock, 0, 0) == 0))
 #endif
     if (do_scan) {
-	set_host_state(sock);
+	set_bridge_state(sock);
 	i365_set(sock, I365_CSCINT, 0);
 	for (i = 0; i < 16; i++)
 	    if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0))
@@ -1351,7 +1352,7 @@
     u_int i;
 
     cb_set_irq_mode(sock, 1, 0);
-    set_host_state(sock);
+    set_bridge_state(sock);
     i365_set(sock, I365_CSCINT, 0);
     /* Only probe irq's 9..11, to be conservative */
     for (i = 9; i < 12; i++) {
@@ -1371,7 +1372,7 @@
 static int to_cycles(int ns)
 {
     return ns/cycle_time;
-} /* speed_convert */
+}
 
 static int to_ns(int cycles)
 {
@@ -1517,7 +1518,7 @@
 	for (i = mask = 0; i < 16; i++)
 	    mask |= (1<<irq_list[i]);
 #endif
-    mask &= I365_MASK & set_host_opts(base, ns);
+    mask &= I365_MASK & set_bridge_opts(base, ns);
 #ifdef CONFIG_ISA
     /* Scan for ISA interrupts */
     mask = isa_scan(base, mask);
@@ -1672,8 +1673,7 @@
 		s->cb_virt = ioremap(s->cb_phys, 0x1000);
 		pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys);
 		/* Simple sanity checks */
-		if (((readb(s->cb_virt+0x800+I365_IDENT) & 0xf0)
-		     == 0x80) &&
+		if (!(readb(s->cb_virt+0x800+I365_IDENT) & 0x70) &&
 		    !(readb(s->cb_virt+0x800+I365_CSC) &&
 		      readb(s->cb_virt+0x800+I365_CSC) &&
 		      readb(s->cb_virt+0x800+I365_CSC)))
@@ -1712,7 +1712,7 @@
 
     /* Re-do card type & voltage detection */
     cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST);
-    current->state = TASK_INTERRUPTIBLE;
+    __set_current_state(TASK_UNINTERRUPTIBLE);
     schedule_timeout(HZ/5);
 
     /* Set up PCI bus bridge structures if needed */
@@ -1762,9 +1762,8 @@
 
 static void __init isa_probe(void)
 {
-    int i, j, sock, k;
-    int ns, id;
-    u_short port;
+    int i, j, sock, k, ns, id;
+    ioaddr_t port;
 
     if (check_region(i365_base, 2) != 0) {
 	if (sockets == 0)
@@ -1812,115 +1811,6 @@
 
 /*====================================================================*/
 
-static int __init init_i82365(void)
-{
-    servinfo_t serv;
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "i82365: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    DEBUG(0, "%s\n", version);
-    printk(KERN_INFO "Intel PCIC probe: ");
-    sockets = 0;
-
-#ifdef CONFIG_PCI
-    if (do_pci_probe && pcibios_present()) {
-	pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
-	pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
-    }
-#endif
-
-#ifdef CONFIG_ISA
-    isa_probe();
-#endif
-
-    if (sockets == 0) {
-	printk("not found.\n");
-	return -ENODEV;
-    }
-
-    /* Set up interrupt handler(s) */
-#ifdef CONFIG_ISA
-    if (grab_irq != 0)
-	request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
-#endif
-#ifdef CONFIG_PCI
-    if (pci_csc) {
-	u_int i, irq, mask = 0;
-	for (i = 0; i < sockets; i++) {
-	    irq = socket[i].cap.pci_irq;
-	    if (irq && !(mask & (1<<irq)))
-		request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
-	    mask |= (1<<irq);
-	}
-    }
-#endif
-    
-    if (register_ss_entry(sockets, &pcic_service) != 0)
-	printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
-
-    /* Finally, schedule a polling interrupt */
-    if (poll_interval != 0) {
-	poll_timer.function = pcic_interrupt_wrapper;
-	poll_timer.data = 0;
-	poll_timer.prev = poll_timer.next = NULL;
-    	poll_timer.expires = jiffies + poll_interval;
-	add_timer(&poll_timer);
-    }
-    
-    return 0;
-    
-} /* init_i82365 */
-  
-/*====================================================================*/
-
-static void __exit exit_i82365(void)
-{
-    int i;
-#ifdef CONFIG_PROC_FS
-    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
-#endif
-    unregister_ss_entry(&pcic_service);
-    if (poll_interval != 0)
-	del_timer(&poll_timer);
-#ifdef CONFIG_ISA
-    if (grab_irq != 0)
-	free_irq(cs_irq, NULL);
-#endif
-#ifdef CONFIG_PCI
-    if (pci_csc) {
-	u_int irq, mask = 0;
-	for (i = 0; i < sockets; i++) {
-	    irq = socket[i].cap.pci_irq;
-	    if (irq && !(mask & (1<<irq)))
-		free_irq(irq, NULL);
-	    mask |= (1<<irq);
-	}
-    }
-#endif
-    for (i = 0; i < sockets; i++) {
-	i365_set(i, I365_CSCINT, 0);
-#ifdef CONFIG_PCI
-	if (socket[i].cb_virt) {
-	    iounmap(socket[i].cb_virt);
-	    release_mem_region(socket[i].cb_phys, 0x1000);
-	} else
-#endif
-	    release_region(socket[i].ioaddr, 2);
-    }
-} /* exit_i82365 */
-
-/*====================================================================*/
-
-static void pcic_interrupt_wrapper(u_long data)
-{
-    pcic_interrupt(0, NULL, NULL);
-    poll_timer.expires = jiffies + poll_interval;
-    add_timer(&poll_timer);
-}
-
 static void pcic_interrupt(int irq, void *dev,
 				    struct pt_regs *regs)
 {
@@ -1938,17 +1828,18 @@
 	    if ((socket[i].cs_irq != irq) &&
 		(socket[i].cap.pci_irq != irq))
 		continue;
-#ifdef CONFIG_ISA
-	    if (!(socket[i].flags & IS_CARDBUS))
-		spin_lock_irqsave(&isa_lock, flags);
-#endif
+	    ISA_LOCK(i, flags);
 	    csc = i365_get(i, I365_CSC);
+#ifdef CONFIG_PCI
+	    if ((socket[i].flags & IS_CARDBUS) &&
+		(cb_readl(i,CB_SOCKET_EVENT) & (CB_SE_CCD1|CB_SE_CCD2))) {
+		cb_writel(i, CB_SOCKET_EVENT, CB_SE_CCD1|CB_SE_CCD2);
+		csc |= I365_CSC_DETECT;
+	    }
+#endif
 	    if ((csc == 0) || (!socket[i].handler) ||
 		(i365_get(i, I365_IDENT) & 0x70)) {
-#ifdef CONFIG_ISA
-		if (!(socket[i].flags & IS_CARDBUS))
-		    spin_unlock_irqrestore(&isa_lock, flags);
-#endif
+		ISA_UNLOCK(i, flags);
 		continue;
 	    }
 	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
@@ -1959,10 +1850,7 @@
 		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
 		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
 	    }
-#ifdef CONFIG_ISA
-	    if (!(socket[i].flags & IS_CARDBUS))
-		spin_unlock_irqrestore(&isa_lock, flags);
-#endif
+	    ISA_UNLOCK(i, flags);
 	    DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events);
 	    if (events)
 		socket[i].handler(socket[i].info, events);
@@ -1976,6 +1864,13 @@
     DEBUG(4, "i82365: interrupt done\n");
 } /* pcic_interrupt */
 
+static void pcic_interrupt_wrapper(u_long data)
+{
+    pcic_interrupt(0, NULL, NULL);
+    poll_timer.expires = jiffies + poll_interval;
+    add_timer(&poll_timer);
+}
+
 /*====================================================================*/
 
 static int pcic_register_callback(u_short sock, ss_callback_t *call)
@@ -2149,7 +2044,7 @@
 			(t->cap.pci_irq == state->io_irq));
     t->bcr &= ~CB_BCR_CB_RESET;
 #endif
-    set_host_state(sock);
+    set_bridge_state(sock);
     
     /* IO card, RESET flag, IO interrupt */
     reg = t->intr;
@@ -2250,6 +2145,13 @@
     }
     i365_set(sock, I365_CSCINT, reg);
     i365_get(sock, I365_CSC);
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS) {
+	if (t->cs_irq || (pci_csc && t->cap.pci_irq))
+	    cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD);
+	cb_writel(sock, CB_SOCKET_EVENT, -1);
+    }
+#endif
     
     return 0;
 } /* i365_set_socket */
@@ -2428,7 +2330,7 @@
     case CB_SC_VCC_3V:		state->Vcc = 33; break;
     case CB_SC_VCC_5V:		state->Vcc = 50; break;
     }
-    switch (reg & CB_SC_VCC_MASK) {
+    switch (reg & CB_SC_VPP_MASK) {
     case CB_SC_VPP_3V:		state->Vpp = 33; break;
     case CB_SC_VPP_5V:		state->Vpp = 50; break;
     case CB_SC_VPP_12V:		state->Vpp = 120; break;
@@ -2509,12 +2411,12 @@
 			(s->cap.pci_irq == state->io_irq));
     s->bcr &= ~CB_BCR_CB_RESET;
     s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0;
-    set_host_state(sock);
+    set_bridge_state(sock);
     
     cb_set_power(sock, state);
     
     /* Handle IO interrupt using ISA routing */
-    reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK;
+    reg = s->intr;
     if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq;
     i365_set(sock, I365_INTCTL, reg);
     
@@ -2523,6 +2425,9 @@
     if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
     i365_set(sock, I365_CSCINT, reg);
     i365_get(sock, I365_CSC);
+    if (s->cs_irq || (pci_csc && s->cap.pci_irq))
+	cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD);
+    cb_writel(sock, CB_SOCKET_EVENT, -1);
     
     return 0;
 } /* cb_set_socket */
@@ -2623,9 +2528,8 @@
     
 #ifdef CONFIG_ISA
     u_long flags = 0;
-    if (!(socket[sock].flags & IS_CARDBUS))
-	spin_lock_irqsave(&isa_lock, flags);
 #endif
+    ISA_LOCK(sock, flags);
     top = 0x40;
     if (socket[sock].flags & IS_CARDBUS)
 	top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50;
@@ -2639,10 +2543,7 @@
 		     i365_get(sock,i+2), i365_get(sock,i+3),
 		     ((i % 16) == 12) ? "\n" : " ");
     }
-#ifdef CONFIG_ISA
-    if (!(socket[sock].flags & IS_CARDBUS))
-	spin_unlock_irqrestore(&isa_lock, flags);
-#endif
+    ISA_UNLOCK(sock, flags);
     return (p - buf);
 }
 
@@ -2672,13 +2573,15 @@
 			     int count, int *eof, void *data)
 {
     u_short sock = (socket_info_t *)data - socket;
-    int len;
-    
-    len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n",
-		  cb_readl(sock,0), cb_readl(sock,4),
-		  cb_readl(sock,8), cb_readl(sock,12),
-		  cb_readl(sock,16), cb_readl(sock,32));
-    return len;
+    char *p = buf;
+    int i, top;
+
+    top = (socket[sock].flags & IS_O2MICRO) ? 0x30 : 0x20;
+    for (i = 0; i < top; i += 0x10)
+	p += sprintf(p, "%08x %08x %08x %08x\n",
+		     cb_readl(sock,i+0x00), cb_readl(sock,i+0x04),
+		     cb_readl(sock,i+0x08), cb_readl(sock,i+0x0c));
+    return (p - buf);
 }
 #endif
 
@@ -2757,7 +2660,11 @@
 static int pcic_service(u_int sock, u_int cmd, void *arg)
 {
     subfn_t fn;
-
+    int ret;
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+    
     DEBUG(2, "pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg);
 
     if (cmd >= NFUNC)
@@ -2782,20 +2689,114 @@
     }
 #endif
 
+    ISA_LOCK(sock, flags);
+    ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
+    ISA_UNLOCK(sock, flags);
+    return ret;
+} /* pcic_service */
+
+/*====================================================================*/
+
+static int __init init_i82365(void)
+{
+    servinfo_t serv;
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "i82365: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    DEBUG(0, "%s\n", version);
+    printk(KERN_INFO "Intel PCIC probe: ");
+    sockets = 0;
+
+#ifdef CONFIG_PCI
+    if (do_pci_probe && pcibios_present()) {
+	pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
+	pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
+    }
+#endif
+
 #ifdef CONFIG_ISA
-    if (!(socket[sock].flags & IS_CARDBUS)) {
-	int ret;
-	u_long flags;
-	spin_lock_irqsave(&isa_lock, flags);
-	ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
-	spin_unlock_irqrestore(&isa_lock, flags);
-	return ret;
+    isa_probe();
+#endif
+
+    if (sockets == 0) {
+	printk("not found.\n");
+	return -ENODEV;
     }
+
+    /* Set up interrupt handler(s) */
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
 #endif
-    return (fn == NULL) ? -EINVAL : fn(sock, arg);
-} /* pcic_service */
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+	u_int i, irq, mask = 0;
+	for (i = 0; i < sockets; i++) {
+	    irq = socket[i].cap.pci_irq;
+	    if (irq && !(mask & (1<<irq)))
+		request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    
+    if (register_ss_entry(sockets, &pcic_service) != 0)
+	printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
 
-/*====================================================================*/
+    /* Finally, schedule a polling interrupt */
+    if (poll_interval != 0) {
+	poll_timer.function = pcic_interrupt_wrapper;
+	poll_timer.data = 0;
+	poll_timer.prev = poll_timer.next = NULL;
+    	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+    }
+    
+    return 0;
+    
+} /* init_i82365 */
+
+static void __exit exit_i82365(void)
+{
+    int i;
+#ifdef CONFIG_PROC_FS
+    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
+#endif
+    unregister_ss_entry(&pcic_service);
+    if (poll_interval != 0)
+	del_timer(&poll_timer);
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	free_irq(cs_irq, NULL);
+#endif
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+	u_int irq, mask = 0;
+	for (i = 0; i < sockets; i++) {
+	    irq = socket[i].cap.pci_irq;
+	    if (irq && !(mask & (1<<irq)))
+		free_irq(irq, NULL);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    for (i = 0; i < sockets; i++) {
+	/* Turn off all interrupt sources! */
+	i365_set(i, I365_CSCINT, 0);
+#ifdef CONFIG_PCI
+	if (socket[i].flags & IS_CARDBUS)
+	    cb_writel(i, CB_SOCKET_MASK, 0);
+	if (socket[i].cb_virt) {
+	    iounmap(socket[i].cb_virt);
+	    release_mem_region(socket[i].cb_phys, 0x1000);
+	} else
+#endif
+	    release_region(socket[i].ioaddr, 2);
+    }
+} /* exit_i82365 */
 
 module_init(init_i82365);
 module_exit(exit_i82365);
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/o2micro.h linux/drivers/pcmcia/o2micro.h
--- v2.3.22/linux/drivers/pcmcia/o2micro.h	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pcmcia/o2micro.h	Wed Oct 20 21:33:12 1999
@@ -1,5 +1,5 @@
 /*
- * o2micro.h 1.10 1999/09/03 16:43:35
+ * o2micro.h 1.12 1999/10/16 01:43:24
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -45,17 +45,38 @@
 #ifndef PCI_DEVICE_ID_O2_6836
 #define PCI_DEVICE_ID_O2_6836		0x6836
 #endif
+#ifndef PCI_DEVICE_ID_O2_6812
+#define PCI_DEVICE_ID_O2_6812		0x6872
+#endif
+
+/* Additional PCI configuration registers */
+
+#define O2_MUX_CONTROL		0x90	/* 32 bit */
+#define  O2_MUX_RING_OUT	0x0000000f
+#define  O2_MUX_SKTB_ACTV	0x000000f0
+#define  O2_MUX_SCTA_ACTV_ENA	0x00000100
+#define  O2_MUX_SCTB_ACTV_ENA	0x00000200
+#define  O2_MUX_SER_IRQ_ROUTE	0x0000e000
+#define  O2_MUX_SER_PCI		0x00010000
+
+#define  O2_MUX_SKTA_TURBO	0x000c0000	/* for 6833, 6860 */
+#define  O2_MUX_SKTB_TURBO	0x00300000
+#define  O2_MUX_AUX_VCC_3V	0x00400000
+#define  O2_MUX_PCI_VCC_5V	0x00800000
+#define  O2_MUX_PME_MUX		0x0f000000
+
+/* Additional ExCA registers */
 
 #define O2_MODE_A		0x38
-#define O2_MODE_A_2		0x26	/* For 6833B, 6860C */
+#define O2_MODE_A_2		0x26	/* for 6833B, 6860C */
 #define  O2_MODE_A_CD_PULSE	0x04
 #define  O2_MODE_A_SUSP_EDGE	0x08
 #define  O2_MODE_A_HOST_SUSP	0x10
-#define  O2_MODE_A_PWRCHIP	0x60
+#define  O2_MODE_A_PWR_MASK	0x60
 #define  O2_MODE_A_QUIET	0x80
 
 #define O2_MODE_B		0x39
-#define O2_MODE_B_2		0x2e	/* For 6833B, 6860C */
+#define O2_MODE_B_2		0x2e	/* for 6833B, 6860C */
 #define  O2_MODE_B_IDENT	0x03
 #define  O2_MODE_B_ID_BSTEP	0x00
 #define  O2_MODE_B_ID_CSTEP	0x01
@@ -70,12 +91,16 @@
 #define  O2_MODE_C_DREQ_WP	0x02
 #define  O2_MODE_C_DREQ_BVD2	0x03
 #define  O2_MODE_C_ZVIDEO	0x08
+#define  O2_MODE_C_IREQ_SEL	0x30
+#define  O2_MODE_C_MGMT_SEL	0xc0
 
 #define O2_MODE_D		0x3b
 #define  O2_MODE_D_IRQ_MODE	0x03
+#define  O2_MODE_D_PCI_CLKRUN	0x04
+#define  O2_MODE_D_CB_CLKRUN	0x08
 #define  O2_MODE_D_SKT_ACTV	0x20
 #define  O2_MODE_D_PCI_FIFO	0x40	/* for OZ6729, OZ6730 */
-#define  O2_MODE_D_W97_IRQ	0x40	/* for OZ6832 */
+#define  O2_MODE_D_W97_IRQ	0x40
 #define  O2_MODE_D_ISA_IRQ	0x80
 
 #define O2_MHPG_DMA		0x3c
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- v2.3.22/linux/drivers/pcmcia/rsrc_mgr.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/pcmcia/rsrc_mgr.c	Wed Oct 20 21:33:12 1999
@@ -2,7 +2,7 @@
 
     Resource management routines
 
-    rsrc_mgr.c 1.71 1999/09/15 15:32:19
+    rsrc_mgr.c 1.73 1999/10/19 00:54:04
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -98,124 +98,15 @@
 
 #endif
 
-static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED;
-
 /*======================================================================
 
     Linux resource management extensions
     
 ======================================================================*/
 
-typedef struct resource_entry_t {
-    u_long			base, num;
-    char			*name;
-    struct resource_entry_t	*next;
-} resource_entry_t;
-
-/* Ordered linked lists of allocated IO and memory blocks */
-static resource_entry_t io_list = { 0, 0, NULL, NULL };
-
-static resource_entry_t *find_gap(resource_entry_t *root,
-				  resource_entry_t *entry)
-{
-    resource_entry_t *p;
-    
-    if (entry->base > entry->base+entry->num-1)
-	return NULL;
-    for (p = root; ; p = p->next) {
-	if ((p != root) && (p->base+p->num-1 >= entry->base)) {
-	    p = NULL;
-	    break;
-	}
-	if ((p->next == NULL) ||
-	    (p->next->base > entry->base+entry->num-1))
-	    break;
-    }
-    return p;
-}
-
-static int register_my_resource(resource_entry_t *list,
-				u_long base, u_long num, char *name)
-{
-    u_long flags;
-    resource_entry_t *p, *entry;
-
-    entry = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC);
-    entry->base = base;
-    entry->num = num;
-    entry->name = name;
-
-    spin_lock_irqsave(&rsrc_lock, flags);
-    p = find_gap(list, entry);
-    if (p == NULL) {
-	spin_unlock_irqrestore(&rsrc_lock, flags);
-	kfree(entry);
-	return -EBUSY;
-    }
-    entry->next = p->next;
-    p->next = entry;
-    spin_unlock_irqrestore(&rsrc_lock, flags);
-    return 0;
-}
-
-static void release_my_resource(resource_entry_t *list,
-				u_long base, u_long num)
-{
-    u_long flags;
-    resource_entry_t *p, *q;
-
-    spin_lock_irqsave(&rsrc_lock, flags);
-    for (p = list; ; p = q) {
-	q = p->next;
-	if (q == NULL) break;
-	if ((q->base == base) && (q->num == num)) {
-	    p->next = q->next;
-	    kfree(q);
-	    spin_unlock_irqrestore(&rsrc_lock, flags);
-	    return;
-	}
-    }
-    spin_unlock_irqrestore(&rsrc_lock, flags);
-    return;
-}
+static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED;
 
-static int check_my_resource(resource_entry_t *list,
-			     u_long base, u_long num)
-{
-    if (register_my_resource(list, base, num, NULL) != 0)
-	return -EBUSY;
-    release_my_resource(list, base, num);
-    return 0;
-}
-
-int check_io_region(u_long base, u_long num)
-{
-    return check_my_resource(&io_list, base, num);
-}
-void request_io_region(u_long base, u_long num, char *name)
-{
-    register_my_resource(&io_list, base, num, name);
-}
-void release_io_region(u_long base, u_long num)
-{
-    release_my_resource(&io_list, base, num);
-}
-#ifdef CONFIG_PROC_FS
-int proc_read_io(char *buf, char **start, off_t pos,
-		 int count, int *eof, void *data)
-{
-    resource_entry_t *r;
-    u_long flags;
-    char *p = buf;
-    
-    spin_lock_irqsave(&rsrc_lock, flags);
-    for (r = io_list.next; r; r = r->next)
-	p += sprintf(p, "%04lx-%04lx : %s\n", r->base,
-		     r->base+r->num-1, r->name);
-    spin_unlock_irqrestore(&rsrc_lock, flags);
-    return (p - buf);
-}
-#endif
+#define check_io_region(b,n) (0)
 
 /*======================================================================
 
@@ -773,7 +664,6 @@
 void release_resource_db(void)
 {
     resource_map_t *p, *q;
-    resource_entry_t *u, *v;
     
     for (p = mem_db.next; p != &mem_db; p = q) {
 	q = p->next;
@@ -782,9 +672,5 @@
     for (p = io_db.next; p != &io_db; p = q) {
 	q = p->next;
 	kfree(p);
-    }
-    for (u = io_list.next; u; u = v) {
-	v = u->next;
-	kfree(u);
     }
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h
--- v2.3.22/linux/drivers/pcmcia/rsrc_mgr.h	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pcmcia/rsrc_mgr.h	Wed Oct 20 21:33:12 1999
@@ -30,10 +30,4 @@
 #ifndef _RSRC_MGR_H
 #define _RSRC_MGR_H
 
-#ifdef __BEOS__
-int check_resource(int type, u_long base, u_long num);
-int register_resource(int type, u_long base, u_long num);
-int release_resource(int type, u_long base, u_long num);
-#endif
-
 #endif	/* _RSRC_MGR_H */
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- v2.3.22/linux/drivers/scsi/atp870u.c	Fri Sep 10 23:57:31 1999
+++ linux/drivers/scsi/atp870u.c	Mon Oct 18 11:35:54 1999
@@ -1,7 +1,7 @@
 /* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $
  *  linux/kernel/atp870u.c
  *
- *  Copyright (C) 1997	Wu Ching Chen
+ *  Copyright (C) 1997  Wu Ching Chen
  *  2.1.x update (C) 1998  Krzysztof G. Baranowski
  *   
  * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes 
@@ -30,745 +30,620 @@
 
 #include<linux/stat.h>
 
-struct proc_dir_entry proc_scsi_atp870u = {
-    PROC_SCSI_ATP870U, 7, "atp870u",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
+struct proc_dir_entry proc_scsi_atp870u =
+{
+	PROC_SCSI_ATP870U, 7, "atp870u",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
 void mydlyu(unsigned int);
+
 /*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
-*/
+ *   static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $";
+ */
+
+static unsigned char admaxu = 1, host_idu[2], chip_veru[2], scam_on[2], global_map[2];
+static unsigned short int active_idu[2], wide_idu[2], sync_idu, ultra_map[2];
+static int workingu[2] = {0, 0};
+
+static Scsi_Cmnd *querequ[2][qcnt], *curr_req[2][16];
+
+static unsigned char devspu[2][16] = {
+	{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20},
+	{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}
+};
 
-static unsigned char admaxu=1,host_idu[2],chip_veru[2],scam_on[2],global_map[2];
-static unsigned short int active_idu[2],wide_idu[2],sync_idu,ultra_map[2];
-static int  workingu[2]={0,0};
-static Scsi_Cmnd *querequ[2][qcnt],*curr_req[2][16];
-static unsigned char devspu[2][16] = {{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-				0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
-			       {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
-				0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}};
-static unsigned char dirctu[2][16],last_cmd[2],in_snd[2],in_int[2];
+static unsigned char dirctu[2][16], last_cmd[2], in_snd[2], in_int[2];
 static unsigned char ata_cdbu[2][16];
-static unsigned int ioportu[2]={0,0};
-static unsigned int irqnumu[2]={0,0};
+static unsigned int ioportu[2] = {0, 0};
+static unsigned int irqnumu[2] = {0, 0};
 static unsigned short int pciportu[2];
-static unsigned long prdaddru[2][16],tran_lenu[2][16],last_lenu[2][16];
+static unsigned long prdaddru[2][16], tran_lenu[2][16], last_lenu[2][16];
 static unsigned char prd_tableu[2][16][1024];
 static unsigned char *prd_posu[2][16];
-static unsigned char quhdu[2],quendu[2];
-static unsigned char devtypeu[2][16] = {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-				 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
-static struct Scsi_Host * atp_host[2]={NULL,NULL};
+static unsigned char quhdu[2], quendu[2];
+
+static unsigned char devtypeu[2][16] =
+{
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static struct Scsi_Host *atp_host[2] = {NULL, NULL};
 
 static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-	 unsigned long flags;
-    unsigned short int	tmpcip,id;
-    unsigned char	i,j,h,tarid,lun;
-    unsigned char  *prd;
-    Scsi_Cmnd *workrequ;
-    unsigned int workportu,tmport;
-    unsigned long adrcntu,k;
-    int      errstus;
-
-    for ( h=0; h < 2; h++ )
-    {
-	if ( ( irq & 0x0f ) == irqnumu[h] )
-	{
-	   goto irq_numok;
+	unsigned long flags;
+	unsigned short int tmpcip, id;
+	unsigned char i, j, h, tarid, lun;
+	unsigned char *prd;
+	Scsi_Cmnd *workrequ;
+	unsigned int workportu, tmport;
+	unsigned long adrcntu, k;
+	int errstus;
+
+	for (h = 0; h < 2; h++) {
+		if (irq == irqnumu[h]) {
+			goto irq_numok;
+		}
 	}
-    }
-    return;
+	return;
 irq_numok:
-    in_int[h]=1;
-    workportu=ioportu[h];
-    tmport=workportu;
-
-    if ( workingu[h] != 0 )
-    {
-       tmport += 0x1f;
-       j=inb(tmport);
-       tmpcip=pciportu[h];
-       if ((inb(tmpcip) & 0x08) != 0)
-       {
-	  tmpcip += 0x2;
-	  while((inb(tmpcip) & 0x08) != 0);
-       }
-       tmpcip=pciportu[h];
-       outb(0x00,tmpcip);
-       tmport -=0x08;
-       i=inb(tmport);
-       if ((j & 0x40) == 0)
-       {
-	  if ((last_cmd[h] & 0x40) == 0)
-	  {
-	     last_cmd[h]=0xff;
-	  }
-       }
-       else
-       {
-	  last_cmd[h] |= 0x40;
-       }
-       tmport -= 0x02;
-       tarid=inb(tmport);
-       tmport += 0x02;
-       if ((tarid & 0x40) != 0)
-       {
-	  tarid=(tarid & 0x07) | 0x08;
-       }
-       else
-       {
-	  tarid &= 0x07;
-       }
-       if ( i == 0x85 )
-       {
-	  if (wide_idu[h] != 0)
-	  {
-	     tmport=workportu+0x1b;
-	     j=inb(tmport) & 0x0e;
-	     j |= 0x01;
-	     outb(j,tmport);
-	  }
-	  if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
-	      (in_snd[h] == 0))
-	  {
-	     send_s870(h);
-	  }
-	  in_int[h]=0;
-	  return;
-       }
-       if ( i == 0x21 )
-       {
-	  tmport -= 0x05;
-	  adrcntu=0;
-	  ((unsigned char *)&adrcntu)[2]=inb(tmport++);
-	  ((unsigned char *)&adrcntu)[1]=inb(tmport++);
-	  ((unsigned char *)&adrcntu)[0]=inb(tmport);
-	  k=last_lenu[h][tarid];
-	  k -= adrcntu;
-	  tran_lenu[h][tarid]= k;
-	  last_lenu[h][tarid]=adrcntu;
-	  tmport -= 0x04;
-	  outb(0x41,tmport);
-	  tmport += 0x08;
-	  outb(0x08,tmport);
-	  in_int[h]=0;
-	  return ;
-       }
-
-       if ((i == 0x80) || (i == 0x8f))
-       {
-	  lun=0;
-	  tmport -= 0x07;
-	  j=inb(tmport);
-	  if ( j == 0x44 )
-	  {
-	     tmport += 0x0d;
-	     lun=inb(tmport) & 0x07;
-	  }
-	  else
-	  {
-	     if ( j == 0x41 )
-	     {
+	in_int[h] = 1;
+	workportu = ioportu[h];
+	tmport = workportu;
+
+	if (workingu[h] != 0) 
+	{
+		tmport += 0x1f;
+		j = inb(tmport);
+
+		tmpcip = pciportu[h];
+		if ((inb(tmpcip) & 0x08) != 0) 
+		{
+			tmpcip += 0x2;
+			while ((inb(tmpcip) & 0x08) != 0);
+		}
+		tmpcip = pciportu[h];
+		outb(0x00, tmpcip);
+		tmport -= 0x08;
+
+		i = inb(tmport);
+		if ((j & 0x40) == 0) 
+		{
+			if ((last_cmd[h] & 0x40) == 0) 
+			{
+				last_cmd[h] = 0xff;
+			}
+		}
+		else last_cmd[h] |= 0x40;
+
+		tmport -= 0x02;
+		tarid = inb(tmport);
 		tmport += 0x02;
-		adrcntu=0;
-		((unsigned char *)&adrcntu)[2]=inb(tmport++);
-		((unsigned char *)&adrcntu)[1]=inb(tmport++);
-		((unsigned char *)&adrcntu)[0]=inb(tmport);
-		k=last_lenu[h][tarid];
-		k -= adrcntu;
-		tran_lenu[h][tarid]= k;
-		last_lenu[h][tarid]=adrcntu;
-		tmport += 0x04;
-		outb(0x08,tmport);
-		in_int[h]=0;
-		return ;
-	     }
-	     else
-	     {
-		outb(0x46,tmport);
-		dirctu[h][tarid]=0x00;
+
+		if ((tarid & 0x40) != 0) {
+			tarid = (tarid & 0x07) | 0x08;
+		} else {
+			tarid &= 0x07;
+		}
+		if (i == 0x85) 
+		{
+			if (wide_idu[h] != 0) 
+			{
+				tmport = workportu + 0x1b;
+				j = inb(tmport) & 0x0e;
+				j |= 0x01;
+				outb(j, tmport);
+			}
+			if (((quhdu[h] != quendu[h]) || (last_cmd[h] != 0xff)) &&
+			    (in_snd[h] == 0)) 
+			{
+				send_s870(h);
+			}
+			in_int[h] = 0;
+			return;
+		}
+		if (i == 0x21) 
+		{
+			tmport -= 0x05;
+			adrcntu = 0;
+			((unsigned char *) &adrcntu)[2] = inb(tmport++);
+			((unsigned char *) &adrcntu)[1] = inb(tmport++);
+			((unsigned char *) &adrcntu)[0] = inb(tmport);
+			k = last_lenu[h][tarid];
+			k -= adrcntu;
+			tran_lenu[h][tarid] = k;
+			last_lenu[h][tarid] = adrcntu;
+			tmport -= 0x04;
+			outb(0x41, tmport);
+			tmport += 0x08;
+			outb(0x08, tmport);
+			in_int[h] = 0;
+			return;
+		}
+		if ((i == 0x80) || (i == 0x8f)) 
+		{
+			lun = 0;
+			tmport -= 0x07;
+			j = inb(tmport);
+			if (j == 0x44) {
+				tmport += 0x0d;
+				lun = inb(tmport) & 0x07;
+			} else {
+				if (j == 0x41) 
+				{
+					tmport += 0x02;
+					adrcntu = 0;
+					((unsigned char *) &adrcntu)[2] = inb(tmport++);
+					((unsigned char *) &adrcntu)[1] = inb(tmport++);
+					((unsigned char *) &adrcntu)[0] = inb(tmport);
+					k = last_lenu[h][tarid];
+					k -= adrcntu;
+					tran_lenu[h][tarid] = k;
+					last_lenu[h][tarid] = adrcntu;
+					tmport += 0x04;
+					outb(0x08, tmport);
+					in_int[h] = 0;
+					return;
+				}
+				else 
+				{
+					outb(0x46, tmport);
+					dirctu[h][tarid] = 0x00;
+					tmport += 0x02;
+					outb(0x00, tmport++);
+					outb(0x00, tmport++);
+					outb(0x00, tmport++);
+					tmport += 0x03;
+					outb(0x08, tmport);
+					in_int[h] = 0;
+					return;
+				}
+			}
+			tmport = workportu + 0x10;
+			outb(0x45, tmport);
+			tmport += 0x06;
+			tarid = inb(tmport);
+			if ((tarid & 0x10) != 0) 
+			{
+				tarid = (tarid & 0x07) | 0x08;
+			} else {
+				tarid &= 0x07;
+			}
+			workrequ = curr_req[h][tarid];
+			tmport = workportu + 0x0f;
+			outb(lun, tmport);
+			tmport += 0x02;
+			outb(devspu[h][tarid], tmport++);
+			adrcntu = tran_lenu[h][tarid];
+			k = last_lenu[h][tarid];
+			outb(((unsigned char *) &k)[2], tmport++);
+			outb(((unsigned char *) &k)[1], tmport++);
+			outb(((unsigned char *) &k)[0], tmport++);
+			j = tarid;
+			if (tarid > 7) {
+				j = (j & 0x07) | 0x40;
+			}
+			j |= dirctu[h][tarid];
+			outb(j, tmport++);
+			outb(0x80, tmport);
+			tmport = workportu + 0x1b;
+			j = inb(tmport) & 0x0e;
+			id = 1;
+			id = id << tarid;
+			if ((id & wide_idu[h]) != 0) {
+				j |= 0x01;
+			}
+			outb(j, tmport);
+			if (last_lenu[h][tarid] == 0) {
+				tmport = workportu + 0x18;
+				outb(0x08, tmport);
+				in_int[h] = 0;
+				return;
+			}
+			prd = prd_posu[h][tarid];
+			while (adrcntu != 0) 
+			{
+				id = ((unsigned short int *) (prd))[2];
+				if (id == 0) {
+					k = 0x10000;
+				} else {
+					k = id;
+				}
+				if (k > adrcntu) {
+					((unsigned short int *) (prd))[2] = (unsigned short int)
+					    (k - adrcntu);
+					((unsigned long *) (prd))[0] += adrcntu;
+					adrcntu = 0;
+					prd_posu[h][tarid] = prd;
+				} else {
+					adrcntu -= k;
+					prdaddru[h][tarid] += 0x08;
+					prd += 0x08;
+					if (adrcntu == 0) {
+						prd_posu[h][tarid] = prd;
+					}
+				}
+			}
+			tmpcip = pciportu[h] + 0x04;
+			outl(prdaddru[h][tarid], tmpcip);
+			tmpcip -= 0x02;
+			outb(0x06, tmpcip);
+			outb(0x00, tmpcip);
+			tmpcip -= 0x02;
+			tmport = workportu + 0x18;
+			if (dirctu[h][tarid] != 0) {
+				outb(0x08, tmport);
+				outb(0x01, tmpcip);
+				in_int[h] = 0;
+				return;
+			}
+			outb(0x08, tmport);
+			outb(0x09, tmpcip);
+			in_int[h] = 0;
+			return;
+		}
+		workrequ = curr_req[h][tarid];
+		if (i == 0x42) {
+			errstus = 0x02;
+			workrequ->result = errstus;
+			goto go_42;
+		}
+		if (i == 0x16) 
+		{
+			errstus = 0;
+			tmport -= 0x08;
+			errstus = inb(tmport);
+			workrequ->result = errstus;
+go_42:
+			spin_lock_irqsave(&io_request_lock, flags);
+			(*workrequ->scsi_done) (workrequ);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+
+			curr_req[h][tarid] = 0;
+			workingu[h]--;
+			if (wide_idu[h] != 0) {
+				tmport = workportu + 0x1b;
+				j = inb(tmport) & 0x0e;
+				j |= 0x01;
+				outb(j, tmport);
+			}
+			if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
+			    (in_snd[h] == 0)) 
+			{
+				send_s870(h);
+			}
+			in_int[h] = 0;
+			return;
+		}
+		if (i == 0x4f) {
+			i = 0x89;
+		}
+		i &= 0x0f;
+		if (i == 0x09) {
+			tmpcip = tmpcip + 4;
+			outl(prdaddru[h][tarid], tmpcip);
+			tmpcip = tmpcip - 2;
+			outb(0x06, tmpcip);
+			outb(0x00, tmpcip);
+			tmpcip = tmpcip - 2;
+			tmport = workportu + 0x10;
+			outb(0x41, tmport);
+			dirctu[h][tarid] = 0x00;
+			tmport += 0x08;
+			outb(0x08, tmport);
+			outb(0x09, tmpcip);
+			in_int[h] = 0;
+			return;
+		}
+		if (i == 0x08) {
+			tmpcip = tmpcip + 4;
+			outl(prdaddru[h][tarid], tmpcip);
+			tmpcip = tmpcip - 2;
+			outb(0x06, tmpcip);
+			outb(0x00, tmpcip);
+			tmpcip = tmpcip - 2;
+			tmport = workportu + 0x10;
+			outb(0x41, tmport);
+			tmport += 0x05;
+			outb((unsigned char) (inb(tmport) | 0x20), tmport);
+			dirctu[h][tarid] = 0x20;
+			tmport += 0x03;
+			outb(0x08, tmport);
+			outb(0x01, tmpcip);
+			in_int[h] = 0;
+			return;
+		}
+		tmport -= 0x07;
+		if (i == 0x0a) {
+			outb(0x30, tmport);
+		} else {
+			outb(0x46, tmport);
+		}
+		dirctu[h][tarid] = 0x00;
 		tmport += 0x02;
-		outb(0x00,tmport++);
-		outb(0x00,tmport++);
-		outb(0x00,tmport++);
-		tmport+=0x03;
-		outb(0x08,tmport);
-		in_int[h]=0;
+		outb(0x00, tmport++);
+		outb(0x00, tmport++);
+		outb(0x00, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		in_int[h] = 0;
 		return;
-	     }
-	  }
-	  tmport=workportu + 0x10;
-	  outb(0x45,tmport);
-	  tmport += 0x06;
-	  tarid=inb(tmport);
-	  if ((tarid & 0x10) != 0)
-	  {
-	     tarid=(tarid & 0x07) | 0x08;
-	  }
-	  else
-	  {
-	     tarid &= 0x07;
-	  }
-	  workrequ=curr_req[h][tarid];
-	  tmport=workportu + 0x0f;
-	  outb(lun,tmport);
-	  tmport += 0x02;
-	  outb(devspu[h][tarid],tmport++);
-	  adrcntu=tran_lenu[h][tarid];
-	  k=last_lenu[h][tarid];
-	  outb(((unsigned char *)&k)[2],tmport++);
-	  outb(((unsigned char *)&k)[1],tmport++);
-	  outb(((unsigned char *)&k)[0],tmport++);
-	  j=tarid;
-	  if ( tarid > 7 )
-	  {
-	     j = (j & 0x07) | 0x40;
-	  }
-	  j |= dirctu[h][tarid];
-	  outb(j,tmport++);
-	  outb(0x80,tmport);
-	  tmport=workportu + 0x1b;
-	  j=inb(tmport) & 0x0e;
-	  id=1;
-	  id=id << tarid;
-	  if ((id & wide_idu[h]) != 0)
-	  {
-	     j |= 0x01;
-	  }
-	  outb(j,tmport);
-	  if ( last_lenu[h][tarid] == 0 )
-	  {
-	     tmport=workportu + 0x18;
-	     outb(0x08,tmport);
-	     in_int[h]=0;
-	     return ;
-	  }
-	  prd=prd_posu[h][tarid];
-	  while ( adrcntu != 0 )
-	  {
-	       id=((unsigned short int *)(prd))[2];
-	       if ( id == 0 )
-	       {
-		  k=0x10000;
-	       }
-	       else
-	       {
-		  k=id;
-	       }
-	       if ( k > adrcntu )
-	       {
-		  ((unsigned short int *)(prd))[2] =(unsigned short int)
-						     (k - adrcntu);
-		  ((unsigned long *)(prd))[0] += adrcntu;
-		  adrcntu=0;
-		  prd_posu[h][tarid]=prd;
-	       }
-	       else
-	       {
-		  adrcntu -= k;
-		  prdaddru[h][tarid] += 0x08;
-		  prd += 0x08;
-		  if ( adrcntu == 0 )
-		  {
-		     prd_posu[h][tarid]=prd;
-		  }
-	       }
-	  }
-	  tmpcip=pciportu[h] + 0x04;
-	  outl(prdaddru[h][tarid],tmpcip);
-	  tmpcip -= 0x02;
-	  outb(0x06,tmpcip);
-	  outb(0x00,tmpcip);
-	  tmpcip -= 0x02;
-	  tmport=workportu + 0x18;
-	  if ( dirctu[h][tarid] != 0 )
-	  {
-	     outb(0x08,tmport);
-	     outb(0x01,tmpcip);
-	     in_int[h]=0;
-	     return;
-	  }
-	  outb(0x08,tmport);
-	  outb(0x09,tmpcip);
-	  in_int[h]=0;
-	  return;
-       }
-
-       workrequ=curr_req[h][tarid];
-       if ( i == 0x42 )
-       {
-	  errstus=0x02;
-	  workrequ->result=errstus;
-	  goto go_42;
-       }
-       if ( i == 0x16 )
-       {
-	  errstus=0;
-	  tmport -= 0x08;
-	  errstus=inb(tmport);
-	  workrequ->result=errstus;
-/*	  if ( errstus == 0x02 )
-	  {
-	     tmport +=0x10;
-	     if ((inb(tmport) & 0x80) != 0)
-	     {
-		printk(" autosense ");
-	     }
-	     tmport -=0x09;
-	     outb(0,tmport);
-	     tmport=workportu+0x3a;
-	     outb((unsigned char)(inb(tmport) | 0x10),tmport);
-	     tmport -= 0x39;
-
-	     outb(0x08,tmport++);
-	     outb(0x7f,tmport++);
-	     outb(0x03,tmport++);
-	     outb(0x00,tmport++);
-	     outb(0x00,tmport++);
-	     outb(0x00,tmport++);
-	     outb(0x0e,tmport++);
-	     outb(0x00,tmport);
-	     tmport+=0x07;
-	     outb(0x00,tmport++);
-	     tmport++;
-	     outb(devspu[h][workrequ->target],tmport++);
-	     outb(0x00,tmport++);
-	     outb(0x00,tmport++);
-	     outb(0x0e,tmport++);
-	     tmport+=0x03;
-	     outb(0x09,tmport);
-	     tmport+=0x07;
-	     i=0;
-	     adrcntu=(unsigned long)(&workrequ->sense_buffer[0]);
-get_sens:
-	     j=inb(tmport);
-	     if ((j & 0x01) != 0)
-	     {
-		tmport-=0x06;
-		(unsigned char)(((caddr_t) adrcntu)[i++])=inb(tmport);
-		tmport+=0x06;
-		goto get_sens;
-	     }
-	     if ((j & 0x80) == 0)
-	     {
-		goto get_sens;
-	     }
-	     if ((j & 0x40) == 0)
-	     {
-		tmport-=0x08;
-		i=inb(tmport);
-	     }
-	     tmport=workportu+0x3a;
-	     outb((unsigned char)(inb(tmport) & 0xef),tmport);
-	     tmport=workportu+0x01;
-	     outb(0x2c,tmport);
-	     tmport += 0x15;
-	     outb(0x80,tmport);
-	  }   */
-go_42:
-	  spin_lock_irqsave(&io_request_lock, flags);
-	  (*workrequ->scsi_done)(workrequ);
-	  spin_unlock_irqrestore(&io_request_lock, flags);
-
-	  curr_req[h][tarid]=0;
-	  workingu[h]--;
-	  if (wide_idu[h] != 0)
-	  {
-	     tmport=workportu+0x1b;
-	     j=inb(tmport) & 0x0e;
-	     j |= 0x01;
-	     outb(j,tmport);
-	  }
-	  if (((last_cmd[h] != 0xff) || (quhdu[h] != quendu[h])) &&
-	      (in_snd[h] == 0))
-	  {
-	     send_s870(h);
-	  }
-	  in_int[h]=0;
-	  return;
-       }
-   if ( i == 0x4f )
-   {
-      i=0x89;
-   }
-   i &= 0x0f;
-   if ( i == 0x09 )
-   {
-      tmpcip=tmpcip+4;
-      outl(prdaddru[h][tarid],tmpcip);
-      tmpcip=tmpcip-2;
-      outb(0x06,tmpcip);
-      outb(0x00,tmpcip);
-      tmpcip=tmpcip-2;
-      tmport=workportu+0x10;
-      outb(0x41,tmport);
-      dirctu[h][tarid]=0x00;
-      tmport += 0x08;
-      outb(0x08,tmport);
-      outb(0x09,tmpcip);
-      in_int[h]=0;
-      return;
-   }
-   if ( i == 0x08 )
-   {
-      tmpcip=tmpcip+4;
-      outl(prdaddru[h][tarid],tmpcip);
-      tmpcip=tmpcip-2;
-      outb(0x06,tmpcip);
-      outb(0x00,tmpcip);
-      tmpcip=tmpcip-2;
-      tmport=workportu+0x10;
-      outb(0x41,tmport);
-      tmport += 0x05;
-      outb((unsigned char)(inb(tmport) | 0x20),tmport);
-      dirctu[h][tarid]=0x20;
-      tmport += 0x03;
-      outb(0x08,tmport);
-      outb(0x01,tmpcip);
-      in_int[h]=0;
-      return;
-   }
-   tmport -= 0x07;
-   if ( i == 0x0a )
-   {
-      outb(0x30,tmport);
-   }
-   else
-   {
-      outb(0x46,tmport);
-   }
-   dirctu[h][tarid]=0x00;
-   tmport += 0x02;
-   outb(0x00,tmport++);
-   outb(0x00,tmport++);
-   outb(0x00,tmport++);
-   tmport+=0x03;
-   outb(0x08,tmport);
-   in_int[h]=0;
-   return;
-  }
-  else
-  {
-     tmport=workportu+0x17;
-     inb(tmport);
-     workingu[h]=0;
-     in_int[h]=0;
-     return;
-  }
+	} else {
+		tmport = workportu + 0x17;
+		inb(tmport);
+		workingu[h] = 0;
+		in_int[h] = 0;
+		return;
+	}
 }
 
-int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done)(Scsi_Cmnd *))
+int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *))
 {
-    unsigned char i,h;
-    unsigned long flags;
-    unsigned short int m;
-    unsigned int tmport;
-
-    for( h=0; h <= admaxu; h++ )
-    {
-       if ( req_p->host == atp_host[h] )
-       {
-	  goto host_ok;
-       }
-    }
-    return 0;
+	unsigned char i, h;
+	unsigned long flags;
+	unsigned short int m;
+	unsigned int tmport;
+
+	for (h = 0; h <= admaxu; h++) {
+		if (req_p->host == atp_host[h]) {
+			goto host_ok;
+		}
+	}
+	return 0;
 host_ok:
-   if ( req_p->channel != 0 )
-   {
-      req_p->result = 0x00040000;
-      done(req_p);
-      return 0;
-   }
-   m=1;
-   m=  m << req_p->target;
-   if ( ( m & active_idu[h] ) == 0 )
-   {
-      req_p->result = 0x00040000;
-      done(req_p);
-      return 0;
-   }
-   if (done)
-   {
-      req_p->scsi_done = done;
-   }
-   else
-   {
-      printk("atp870u_queuecommand: done can't be NULL\n");
-      req_p->result = 0;
-      done(req_p);
-      return 0;
-   }
-   quendu[h]++;
-   if ( quendu[h] >= qcnt )
-   {
-      quendu[h]=0;
-   }
-   wait_que_empty:
-     if ( quhdu[h] == quendu[h] )
-     {
-	goto wait_que_empty;
-     }
-     save_flags(flags);
-     cli();
-     querequ[h][quendu[h]]=req_p;
-     if ( quendu[h] == 0 )
-     {
-	i=qcnt-1;
-     }
-     else
-     {
-	i=quendu[h]-1;
-     }
-     tmport = ioportu[h]+0x1c;
-     restore_flags(flags);
-     if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0))
-     {
-	 send_s870(h);
-     }
-     return 0;
+	if (req_p->channel != 0) {
+		req_p->result = 0x00040000;
+		done(req_p);
+		return 0;
+	}
+	m = 1;
+	m = m << req_p->target;
+	if ((m & active_idu[h]) == 0) {
+		req_p->result = 0x00040000;
+		done(req_p);
+		return 0;
+	}
+	if (done) {
+		req_p->scsi_done = done;
+	} else {
+		printk("atp870u_queuecommand: done can't be NULL\n");
+		req_p->result = 0;
+		done(req_p);
+		return 0;
+	}
+	quendu[h]++;
+	if (quendu[h] >= qcnt) {
+		quendu[h] = 0;
+	}
+wait_que_empty:
+	if (quhdu[h] == quendu[h]) {
+		goto wait_que_empty;
+	}
+	save_flags(flags);
+	cli();
+	querequ[h][quendu[h]] = req_p;
+	if (quendu[h] == 0) {
+		i = qcnt - 1;
+	} else {
+		i = quendu[h] - 1;
+	}
+	tmport = ioportu[h] + 0x1c;
+	restore_flags(flags);
+	if ((inb(tmport) == 0) && (in_int[h] == 0) && (in_snd[h] == 0)) {
+		send_s870(h);
+	}
+	return 0;
 }
 
-void mydlyu(unsigned int dlycnt )
+void mydlyu(unsigned int dlycnt)
 {
-    unsigned int i ;
-    for ( i = 0 ; i < dlycnt ; i++ )
-    {
-       inb(0x80);
-    }
+	unsigned int i;
+	for (i = 0; i < dlycnt; i++) {
+		inb(0x80);
+	}
 }
 
 void send_s870(unsigned char h)
 {
-     unsigned int  tmport;
-     Scsi_Cmnd *workrequ;
-     unsigned long flags;
-     unsigned int   i;
-     unsigned char  j,tarid;
-     unsigned char  *prd;
-     unsigned short int   tmpcip,w;
-     unsigned long  l,bttl;
-     unsigned int workportu;
-     struct scatterlist * sgpnt;
+	unsigned int tmport;
+	Scsi_Cmnd *workrequ;
+	unsigned long flags;
+	unsigned int i;
+	unsigned char j, tarid;
+	unsigned char *prd;
+	unsigned short int tmpcip, w;
+	unsigned long l, bttl;
+	unsigned int workportu;
+	struct scatterlist *sgpnt;
 
 	save_flags(flags);
 	cli();
-	if ( in_snd[h] != 0 )
-	{
-	   restore_flags(flags);
-	   return;
+	if (in_snd[h] != 0) {
+		restore_flags(flags);
+		return;
 	}
-	in_snd[h]=1;
-	if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0))
-	{
-	   last_cmd[h] &= 0x0f;
-	   workrequ=curr_req[h][last_cmd[h]];
-	   goto cmd_subp;
+	in_snd[h] = 1;
+	if ((last_cmd[h] != 0xff) && ((last_cmd[h] & 0x40) != 0)) {
+		last_cmd[h] &= 0x0f;
+		workrequ = curr_req[h][last_cmd[h]];
+		goto cmd_subp;
 	}
 	workingu[h]++;
-	j=quhdu[h];
+	j = quhdu[h];
 	quhdu[h]++;
-	if ( quhdu[h] >= qcnt )
-	{
-	   quhdu[h]=0;
+	if (quhdu[h] >= qcnt) {
+		quhdu[h] = 0;
 	}
-	workrequ=querequ[h][quhdu[h]];
-	if ( curr_req[h][workrequ->target] == 0 )
-	{
-	   curr_req[h][workrequ->target]=workrequ;
-	   last_cmd[h]=workrequ->target;
-	   goto cmd_subp;
+	workrequ = querequ[h][quhdu[h]];
+	if (curr_req[h][workrequ->target] == 0) {
+		curr_req[h][workrequ->target] = workrequ;
+		last_cmd[h] = workrequ->target;
+		goto cmd_subp;
 	}
-	quhdu[h]=j;
+	quhdu[h] = j;
 	workingu[h]--;
-	in_snd[h]=0;
+	in_snd[h] = 0;
 	restore_flags(flags);
-	return ;
+	return;
 cmd_subp:
-   workportu=ioportu[h];
-   tmport=workportu+0x1f;
-   if ((inb(tmport) & 0xb0) != 0)
-   {
-      goto abortsnd;
-   }
-   tmport=workportu+0x1c;
-   if ( inb(tmport) == 0 )
-   {
-      goto oktosend;
-   }
+	workportu = ioportu[h];
+	tmport = workportu + 0x1f;
+	if ((inb(tmport) & 0xb0) != 0) {
+		goto abortsnd;
+	}
+	tmport = workportu + 0x1c;
+	if (inb(tmport) == 0) {
+		goto oktosend;
+	}
 abortsnd:
-   last_cmd[h] |= 0x40;
-   in_snd[h]=0;
-   restore_flags(flags);
-   return;
-oktosend:
-   memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
-   if ( ata_cdbu[h][0] == 0x25 )
-   {
-      if ( workrequ->request_bufflen > 8 )
-      {
-	 workrequ->request_bufflen=0x08;
-      }
-   }
-   if ( ata_cdbu[h][0] == 0x12 )
-   {
-      if ( workrequ->request_bufflen > 0x24 )
-      {
-	 workrequ->request_bufflen = 0x24;
-	 ata_cdbu[h][4]=0x24;
-      }
-   }
-
-   tmport=workportu+0x1b;
-   j=inb(tmport) & 0x0e;
-   tarid=workrequ->target;
-   w=1;
-   w = w << tarid;
-   if ((w & wide_idu[h]) != 0)
-   {
-      j |= 0x01;
-   }
-   outb(j,tmport);
-   tmport=workportu;
-   outb(workrequ->cmd_len,tmport++);
-   outb(0x2c,tmport++);
-   outb(0xcf,tmport++);
-   for ( i=0 ; i < workrequ->cmd_len ; i++ )
-   {
-       outb(ata_cdbu[h][i],tmport++);
-   }
-   tmport=workportu+0x0f;
-   outb(0x00,tmport);
-   tmport+=0x02;
-   outb(devspu[h][tarid],tmport++);
-   if (workrequ->use_sg)
-   {
-
-     l=0;
-     sgpnt = (struct scatterlist *) workrequ->request_buffer;
-     for(i=0; i<workrequ->use_sg; i++)
-     {
-       if(sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
-       {
-	 panic("Foooooooood fight!");
-       }
-       l += sgpnt[i].length;
-     }
-   }
-   else
-   {
-     l=workrequ->request_bufflen;
-   }
-   outb((unsigned char)(((unsigned char *)(&l))[2]),tmport++);
-   outb((unsigned char)(((unsigned char *)(&l))[1]),tmport++);
-   outb((unsigned char)(((unsigned char *)(&l))[0]),tmport++);
-   j=tarid;
-   last_lenu[h][j]=l;
-   tran_lenu[h][j]=0;
-   if ((j & 0x08) != 0)
-   {
-      j=(j & 0x07) | 0x40;
-   }
-   if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
-       (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
-   {
-      outb((unsigned char)(j | 0x20),tmport++);
-   }
-   else
-   {
-      outb(j,tmport++);
-   }
-   outb(0x80,tmport);
-   tmport=workportu + 0x1c;
-   dirctu[h][tarid]=0;
-   if ( l == 0 )
-   {
-      if ( inb(tmport) == 0 )
-      {
-	 tmport=workportu+0x18;
-	 outb(0x08,tmport);
-      }
-      else
-      {
 	last_cmd[h] |= 0x40;
-      }
-      in_snd[h]=0;
-      restore_flags(flags);
-      return;
-   }
-   tmpcip=pciportu[h];
-   prd=&prd_tableu[h][tarid][0];
-   prd_posu[h][tarid]=prd;
-   if (workrequ->use_sg)
-   {
-     sgpnt = (struct scatterlist *) workrequ->request_buffer;
-     i=0;
-     for(j=0; j<workrequ->use_sg; j++)
-     {
-	(unsigned long)(((unsigned long *)(prd))[i >> 1])=(unsigned long)sgpnt[j].address;
-	(unsigned short int)(((unsigned short int *)(prd))[i+2])=sgpnt[j].length;
-	(unsigned short int)(((unsigned short int *)(prd))[i+3])=0;
-	i +=0x04;
-     }
-     (unsigned short int)(((unsigned short int *)(prd))[i-1])=0x8000;
-   }
-   else
-   {
-     bttl=(unsigned long)workrequ->request_buffer;
-     l=workrequ->request_bufflen;
-     i=0;
-     while ( l > 0x10000 )
-     {
-	(unsigned short int)(((unsigned short int *)(prd))[i+3])=0x0000;
-	(unsigned short int)(((unsigned short int *)(prd))[i+2])=0x0000;
-	(unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
-	l -= 0x10000;
-	bttl += 0x10000;
-	i += 0x04;
-     }
-     (unsigned short int)(((unsigned short int *)(prd))[i+3])=0x8000;
-     (unsigned short int)(((unsigned short int *)(prd))[i+2])=l;
-     (unsigned long)(((unsigned long *)(prd))[i >> 1])=bttl;
-   }
-   tmpcip=tmpcip+4;
-   prdaddru[h][tarid]=(unsigned long)&prd_tableu[h][tarid][0];
-   outl(prdaddru[h][tarid],tmpcip);
-   tmpcip=tmpcip-2;
-   outb(0x06,tmpcip);
-   outb(0x00,tmpcip);
-   tmpcip=tmpcip-2;
-   if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
-       (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15))
-   {
-      dirctu[h][tarid]=0x20;
-      if ( inb(tmport) == 0 )
-      {
-	 tmport=workportu+0x18;
-	 outb(0x08,tmport);
-	 outb(0x01,tmpcip);
-      }
-      else
-      {
-	 last_cmd[h] |= 0x40;
-      }
-      in_snd[h]=0;
-      restore_flags(flags);
-      return;
-   }
-   if ( inb(tmport) == 0 )
-   {
-      tmport=workportu+0x18;
-      outb(0x08,tmport);
-      outb(0x09,tmpcip);
-   }
-   else
-   {
-      last_cmd[h] |= 0x40;
-   }
-   in_snd[h]=0;
-   restore_flags(flags);
-   return;
+	in_snd[h] = 0;
+	restore_flags(flags);
+	return;
+oktosend:
+	memcpy(&ata_cdbu[h][0], &workrequ->cmnd[0], workrequ->cmd_len);
+	if (ata_cdbu[h][0] == 0x25) {
+		if (workrequ->request_bufflen > 8) {
+			workrequ->request_bufflen = 0x08;
+		}
+	}
+	if (ata_cdbu[h][0] == 0x12) {
+		if (workrequ->request_bufflen > 0x24) {
+			workrequ->request_bufflen = 0x24;
+			ata_cdbu[h][4] = 0x24;
+		}
+	}
+	tmport = workportu + 0x1b;
+	j = inb(tmport) & 0x0e;
+	tarid = workrequ->target;
+	w = 1;
+	w = w << tarid;
+	if ((w & wide_idu[h]) != 0) {
+		j |= 0x01;
+	}
+	outb(j, tmport);
+	tmport = workportu;
+	outb(workrequ->cmd_len, tmport++);
+	outb(0x2c, tmport++);
+	outb(0xcf, tmport++);
+	for (i = 0; i < workrequ->cmd_len; i++) {
+		outb(ata_cdbu[h][i], tmport++);
+	}
+	tmport = workportu + 0x0f;
+	outb(0x00, tmport);
+	tmport += 0x02;
+	outb(devspu[h][tarid], tmport++);
+	if (workrequ->use_sg) 
+	{
+		l = 0;
+		sgpnt = (struct scatterlist *) workrequ->request_buffer;
+		for (i = 0; i < workrequ->use_sg; i++) 
+		{
+			if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) 
+			{
+				panic("Foooooooood fight!");
+			}
+			l += sgpnt[i].length;
+		}
+	} else {
+		l = workrequ->request_bufflen;
+	}
+	outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
+	outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
+	outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+	j = tarid;
+	last_lenu[h][j] = l;
+	tran_lenu[h][j] = 0;
+	if ((j & 0x08) != 0) {
+		j = (j & 0x07) | 0x40;
+	}
+	if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+	    (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) {
+		outb((unsigned char) (j | 0x20), tmport++);
+	} else {
+		outb(j, tmport++);
+	}
+	outb(0x80, tmport);
+	tmport = workportu + 0x1c;
+	dirctu[h][tarid] = 0;
+	if (l == 0) {
+		if (inb(tmport) == 0) {
+			tmport = workportu + 0x18;
+			outb(0x08, tmport);
+		} else {
+			last_cmd[h] |= 0x40;
+		}
+		in_snd[h] = 0;
+		restore_flags(flags);
+		return;
+	}
+	tmpcip = pciportu[h];
+	prd = &prd_tableu[h][tarid][0];
+	prd_posu[h][tarid] = prd;
+	if (workrequ->use_sg) 
+	{
+		sgpnt = (struct scatterlist *) workrequ->request_buffer;
+		i = 0;
+		for (j = 0; j < workrequ->use_sg; j++) {
+			(unsigned long) (((unsigned long *) (prd))[i >> 1]) = virt_to_bus(sgpnt[j].address);
+			(unsigned short int) (((unsigned short int *) (prd))[i + 2]) = sgpnt[j].length;
+			(unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0;
+			i += 0x04;
+		}
+		(unsigned short int) (((unsigned short int *) (prd))[i - 1]) = 0x8000;
+	} else {
+		bttl = virt_to_bus(workrequ->request_buffer);
+		l = workrequ->request_bufflen;
+		i = 0;
+		while (l > 0x10000) {
+			(unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x0000;
+			(unsigned short int) (((unsigned short int *) (prd))[i + 2]) = 0x0000;
+			(unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
+			l -= 0x10000;
+			bttl += 0x10000;
+			i += 0x04;
+		}
+		(unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x8000;
+		(unsigned short int) (((unsigned short int *) (prd))[i + 2]) = l;
+		(unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
+	}
+	tmpcip = tmpcip + 4;
+	prdaddru[h][tarid] = virt_to_bus(&prd_tableu[h][tarid][0]);
+	outl(prdaddru[h][tarid], tmpcip);
+	tmpcip = tmpcip - 2;
+	outb(0x06, tmpcip);
+	outb(0x00, tmpcip);
+	tmpcip = tmpcip - 2;
+	if ((ata_cdbu[h][0] == 0x0a) || (ata_cdbu[h][0] == 0x2a) ||
+	    (ata_cdbu[h][0] == 0xaa) || (ata_cdbu[h][0] == 0x15)) 
+	{
+		dirctu[h][tarid] = 0x20;
+		if (inb(tmport) == 0) {
+			tmport = workportu + 0x18;
+			outb(0x08, tmport);
+			outb(0x01, tmpcip);
+		} else {
+			last_cmd[h] |= 0x40;
+		}
+		in_snd[h] = 0;
+		restore_flags(flags);
+		return;
+	}
+	if (inb(tmport) == 0) 
+	{
+		tmport = workportu + 0x18;
+		outb(0x08, tmport);
+		outb(0x09, tmpcip);
+	} else {
+		last_cmd[h] |= 0x40;
+	}
+	in_snd[h] = 0;
+	restore_flags(flags);
+	return;
 
 }
 
@@ -780,1101 +655,964 @@
 int atp870u_command(Scsi_Cmnd * SCpnt)
 {
 
-    atp870u_queuecommand(SCpnt, internal_done);
+	atp870u_queuecommand(SCpnt, internal_done);
 
-    SCpnt->SCp.Status = 0;
-    while (!SCpnt->SCp.Status)
-	barrier();
-    return SCpnt->result;
+	SCpnt->SCp.Status = 0;
+	while (!SCpnt->SCp.Status)
+		barrier();
+	return SCpnt->result;
 }
 
-unsigned char fun_scam ( unsigned char host,unsigned short int * val )
+unsigned char fun_scam(unsigned char host, unsigned short int *val)
 {
-    unsigned int  tmport ;
-    unsigned short int	 i,k;
-    unsigned char     j;
+	unsigned int tmport;
+	unsigned short int i, k;
+	unsigned char j;
 
-    tmport = ioportu[host]+0x1c;
-    outw(*val,tmport);
+	tmport = ioportu[host] + 0x1c;
+	outw(*val, tmport);
 FUN_D7:
-    for ( i=0; i < 10; i++ )	     /* stable >= bus settle delay(400 ns)  */
-    {
-	k=inw(tmport);
-	j= (unsigned char)(k >> 8);
-	if ((k & 0x8000) != 0)	     /* DB7 all release?    */
-	{
-	   goto  FUN_D7;
+	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
+		k = inw(tmport);
+		j = (unsigned char) (k >> 8);
+		if ((k & 0x8000) != 0) {	/* DB7 all release?    */
+			goto FUN_D7;
+		}
 	}
-    }
-    *val |= 0x4000;		    /* assert DB6	    */
-    outw(*val,tmport);
-    *val &= 0xdfff;		    /* assert DB5	    */
-    outw(*val,tmport);
+	*val |= 0x4000;		/* assert DB6           */
+	outw(*val, tmport);
+	*val &= 0xdfff;		/* assert DB5           */
+	outw(*val, tmport);
 FUN_D5:
-    for ( i=0; i < 10; i++ )	    /* stable >= bus settle delay(400 ns) */
-    {
-       if ((inw(tmport) & 0x2000) != 0)   /* DB5 all release?	*/
-       {
-	  goto	FUN_D5;
-       }
-    }
-    *val |= 0x8000;		     /* no DB4-0, assert DB7	*/
-    *val &= 0xe0ff;
-    outw(*val,tmport);
-    *val &= 0xbfff;		     /* release DB6		*/
-    outw(*val,tmport);
-FUN_D6:
-    for ( i=0; i < 10; i++ )	     /* stable >= bus settle delay(400 ns)  */
-    {
-       if ((inw(tmport) & 0x4000) != 0)   /* DB6 all release?  */
-       {
-	  goto	FUN_D6;
-       }
-    }
+	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns) */
+		if ((inw(tmport) & 0x2000) != 0) {	/* DB5 all release?       */
+			goto FUN_D5;
+		}
+	}
+	*val |= 0x8000;		/* no DB4-0, assert DB7    */
+	*val &= 0xe0ff;
+	outw(*val, tmport);
+	*val &= 0xbfff;		/* release DB6             */
+	outw(*val, tmport);
+      FUN_D6:
+	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
+		if ((inw(tmport) & 0x4000) != 0) {	/* DB6 all release?  */
+			goto FUN_D6;
+		}
+	}
 
-    return j;
+	return j;
 }
 
-void tscam( unsigned char host )
+void tscam(unsigned char host)
 {
 
-    unsigned int  tmport ;
-    unsigned char  i,j,k;
-    unsigned long  n;
-    unsigned short int	m,assignid_map,val;
-    unsigned char  mbuf[33],quintet[2];
-    static unsigned char g2q_tab[8]={ 0x38,0x31,0x32,0x2b,0x34,0x2d,0x2e,0x27 };
+	unsigned int tmport;
+	unsigned char i, j, k;
+	unsigned long n;
+	unsigned short int m, assignid_map, val;
+	unsigned char mbuf[33], quintet[2];
+	static unsigned char g2q_tab[8] =
+	{0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27};
 
 
-    for ( i=0; i < 0x10; i++ )
-    {
-	mydlyu(0xffff);
-    }
+	for (i = 0; i < 0x10; i++) {
+		mydlyu(0xffff);
+	}
 
-    tmport = ioportu[host]+1;
-    outb(0x08,tmport++);
-    outb(0x7f,tmport);
-    tmport = ioportu[host]+0x11;
-    outb(0x20,tmport);
-
-    if ((scam_on[host] & 0x40) == 0)
-    {
-       return;
-    }
-
-    m=1;
-    m <<= host_idu[host];
-    j=16;
-    if ( chip_veru[host] < 4 )
-    {
-       m |= 0xff00;
-       j=8;
-    }
-    assignid_map=m;
-    tmport = ioportu[host]+0x02;
-    outb(0x02,tmport++);	/* 2*2=4ms,3EH 2/32*3E=3.9ms */
-    outb(0,tmport++);
-    outb(0,tmport++);
-    outb(0,tmport++);
-    outb(0,tmport++);
-    outb(0,tmport++);
-    outb(0,tmport++);
-
-    for ( i = 0 ; i < j ; i ++ )
-    {
-	m=1;
-	m=m<<i;
-	if ( ( m & assignid_map ) != 0 )
-	{
-	   continue;
+	tmport = ioportu[host] + 1;
+	outb(0x08, tmport++);
+	outb(0x7f, tmport);
+	tmport = ioportu[host] + 0x11;
+	outb(0x20, tmport);
+
+	if ((scam_on[host] & 0x40) == 0) {
+		return;
+	}
+	m = 1;
+	m <<= host_idu[host];
+	j = 16;
+	if (chip_veru[host] < 4) {
+		m |= 0xff00;
+		j = 8;
 	}
-    tmport = ioportu[host]+0x0f;
-    outb(0,tmport++);
-    tmport += 0x02;
-    outb(0,tmport++);
-    outb(0,tmport++);
-    outb(0,tmport++);
-    if ( i > 7 )
-    {
-       k=(i & 0x07) | 0x40;
-    }
-    else
-    {
-       k=i;
-    }
-    outb(k,tmport++);
-    tmport = ioportu[host]+0x1b;
-    if ( chip_veru[host] == 4 )
-    {
-       outb((unsigned char)((inb(tmport) & 0x0e) | 0x01),tmport);
-    }
-    else
-    {
-       outb((unsigned char)(inb(tmport) & 0x0e),tmport);
-    }
+	assignid_map = m;
+	tmport = ioportu[host] + 0x02;
+	outb(0x02, tmport++);	/* 2*2=4ms,3EH 2/32*3E=3.9ms */
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+
+	for (i = 0; i < j; i++) {
+		m = 1;
+		m = m << i;
+		if ((m & assignid_map) != 0) {
+			continue;
+		}
+		tmport = ioportu[host] + 0x0f;
+		outb(0, tmport++);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		if (i > 7) {
+			k = (i & 0x07) | 0x40;
+		} else {
+			k = i;
+		}
+		outb(k, tmport++);
+		tmport = ioportu[host] + 0x1b;
+		if (chip_veru[host] == 4) {
+			outb((unsigned char) ((inb(tmport) & 0x0e) | 0x01), tmport);
+		} else {
+			outb((unsigned char) (inb(tmport) & 0x0e), tmport);
+		}
 wait_rdyok:
-    tmport = ioportu[host]+0x18;
-    outb(0x09,tmport);
-    tmport += 0x07;
-
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport -= 0x08;
-    k=inb(tmport);
-    if ( k != 0x16 )
-    {
-       if ((k == 0x85) || (k == 0x42))
-       {
-	  continue;
-       }
-       tmport = ioportu[host]+0x10;
-       outb(0x41,tmport);
-       goto wait_rdyok;
-    }
-    assignid_map |= m;
-
-    }
-    tmport = ioportu[host]+0x02;
-    outb(0x7f,tmport);
-    tmport = ioportu[host]+0x1b;
-    outb(0x02,tmport);
-
-    outb(0,0x80);
-
-    val=0x0080;      /* bsy  */
-    tmport = ioportu[host]+0x1c;
-    outw(val,tmport);
-    val |=0x0040;    /* sel  */
-    outw(val,tmport);
-    val |=0x0004;    /* msg  */
-    outw(val,tmport);
-    inb(0x80);		      /* 2 deskew delay(45ns*2=90ns) */
-    val &=0x007f;    /* no bsy	*/
-    outw(val,tmport);
-    mydlyu(0xffff);  /* recommanded SCAM selection response time */
-    mydlyu(0xffff);
-    val &=0x00fb;    /* after 1ms no msg */
-    outw(val,tmport);
+		tmport = ioportu[host] + 0x18;
+		outb(0x09, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		k = inb(tmport);
+		if (k != 0x16) {
+			if ((k == 0x85) || (k == 0x42)) {
+				continue;
+			}
+			tmport = ioportu[host] + 0x10;
+			outb(0x41, tmport);
+			goto wait_rdyok;
+		}
+		assignid_map |= m;
+
+	}
+	tmport = ioportu[host] + 0x02;
+	outb(0x7f, tmport);
+	tmport = ioportu[host] + 0x1b;
+	outb(0x02, tmport);
+
+	outb(0, 0x80);
+
+	val = 0x0080;		/* bsy  */
+	tmport = ioportu[host] + 0x1c;
+	outw(val, tmport);
+	val |= 0x0040;		/* sel  */
+	outw(val, tmport);
+	val |= 0x0004;		/* msg  */
+	outw(val, tmport);
+	inb(0x80);		/* 2 deskew delay(45ns*2=90ns) */
+	val &= 0x007f;		/* no bsy  */
+	outw(val, tmport);
+	mydlyu(0xffff);		/* recommanded SCAM selection response time */
+	mydlyu(0xffff);
+	val &= 0x00fb;		/* after 1ms no msg */
+	outw(val, tmport);
 wait_nomsg:
-    if ((inb(tmport) & 0x04) != 0)
-    {
-       goto wait_nomsg;
-    }
-    outb(1,0x80);
-    mydlyu(100);
-    for ( n=0; n < 0x30000; n++ )
-    {
-	if ((inb(tmport) & 0x80) != 0)	   /* bsy ? */
-	{
-	   goto wait_io;
+	if ((inb(tmport) & 0x04) != 0) {
+		goto wait_nomsg;
+	}
+	outb(1, 0x80);
+	mydlyu(100);
+	for (n = 0; n < 0x30000; n++) {
+		if ((inb(tmport) & 0x80) != 0) {	/* bsy ? */
+			goto wait_io;
+		}
 	}
-    }
-    goto  TCM_SYNC;
+	goto TCM_SYNC;
 wait_io:
-    for ( n=0; n < 0x30000; n++ )
-    {
-	if ((inb(tmport) & 0x81) == 0x0081)
-	{
-	   goto wait_io1;
+	for (n = 0; n < 0x30000; n++) {
+		if ((inb(tmport) & 0x81) == 0x0081) {
+			goto wait_io1;
+		}
 	}
-    }
-    goto  TCM_SYNC;
+	goto TCM_SYNC;
 wait_io1:
-    inb(0x80);
-    val |=0x8003;    /* io,cd,db7  */
-    outw(val,tmport);
-    inb(0x80);
-    val &=0x00bf;    /* no sel	   */
-    outw(val,tmport);
-    outb(2,0x80);
+	inb(0x80);
+	val |= 0x8003;		/* io,cd,db7  */
+	outw(val, tmport);
+	inb(0x80);
+	val &= 0x00bf;		/* no sel     */
+	outw(val, tmport);
+	outb(2, 0x80);
 TCM_SYNC:
-    mydlyu(0x800);
-    if ((inb(tmport) & 0x80) == 0x00)	 /* bsy ? */
-    {
-       outw(0,tmport--);
-       outb(0,tmport);
-       tmport=ioportu[host] + 0x15;
-       outb(0,tmport);
-       tmport += 0x03;
-       outb(0x09,tmport);
-       tmport += 0x07;
-       while ((inb(tmport) & 0x80) == 0);
-       tmport -= 0x08;
-       inb(tmport);
-       return;
-    }
-
-    val &= 0x00ff;		 /* synchronization  */
-    val |= 0x3f00;
-    fun_scam(host,&val);
-    outb(3,0x80);
-    val &= 0x00ff;		 /* isolation	     */
-    val |= 0x2000;
-    fun_scam(host,&val);
-    outb(4,0x80);
-    i=8;
-    j=0;
+	mydlyu(0x800);
+	if ((inb(tmport) & 0x80) == 0x00) {	/* bsy ? */
+		outw(0, tmport--);
+		outb(0, tmport);
+		tmport = ioportu[host] + 0x15;
+		outb(0, tmport);
+		tmport += 0x03;
+		outb(0x09, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0);
+		tmport -= 0x08;
+		inb(tmport);
+		return;
+	}
+	val &= 0x00ff;		/* synchronization  */
+	val |= 0x3f00;
+	fun_scam(host, &val);
+	outb(3, 0x80);
+	val &= 0x00ff;		/* isolation        */
+	val |= 0x2000;
+	fun_scam(host, &val);
+	outb(4, 0x80);
+	i = 8;
+	j = 0;
 TCM_ID:
-    if ((inw(tmport) & 0x2000) == 0)
-    {
-       goto TCM_ID;
-    }
-    outb(5,0x80);
-    val &= 0x00ff;		 /* get ID_STRING */
-    val |= 0x2000;
-    k=fun_scam(host,&val);
-    if ((k & 0x03) == 0)
-    {
-       goto TCM_5;
-    }
-    mbuf[j] <<= 0x01;
-    mbuf[j] &= 0xfe;
-    if ((k & 0x02) != 0)
-    {
-       mbuf[j] |= 0x01;
-    }
-    i--;
-    if ( i > 0 )
-    {
-       goto TCM_ID;
-    }
-    j++;
-    i=8;
-    goto TCM_ID;
+	if ((inw(tmport) & 0x2000) == 0) {
+		goto TCM_ID;
+	}
+	outb(5, 0x80);
+	val &= 0x00ff;		/* get ID_STRING */
+	val |= 0x2000;
+	k = fun_scam(host, &val);
+	if ((k & 0x03) == 0) {
+		goto TCM_5;
+	}
+	mbuf[j] <<= 0x01;
+	mbuf[j] &= 0xfe;
+	if ((k & 0x02) != 0) {
+		mbuf[j] |= 0x01;
+	}
+	i--;
+	if (i > 0) {
+		goto TCM_ID;
+	}
+	j++;
+	i = 8;
+	goto TCM_ID;
 
-TCM_5:			     /* isolation complete..  */
+TCM_5:			/* isolation complete..  */
 /*    mbuf[32]=0;
-    printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
-    i=15;
-    j=mbuf[0];
-    if ((j & 0x20) != 0)     /* bit5=1:ID upto 7      */
-    {
-       i=7;
-    }
-    if ((j & 0x06) == 0)     /* IDvalid?	      */
-    {
-       goto  G2Q5;
-    }
-    k=mbuf[1];
+	printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
+	i = 15;
+	j = mbuf[0];
+	if ((j & 0x20) != 0) {	/* bit5=1:ID upto 7      */
+		i = 7;
+	}
+	if ((j & 0x06) == 0) {	/* IDvalid?             */
+		goto G2Q5;
+	}
+	k = mbuf[1];
 small_id:
-    m=1;
-    m <<= k;
-    if ((m & assignid_map) == 0)
-    {
-       goto G2Q_QUIN;
-    }
-    if ( k > 0 )
-    {
-       k--;
-       goto small_id;
-    }
-G2Q5:			      /* srch from max acceptable ID#  */
-    k=i;		      /* max acceptable ID#	       */
+	m = 1;
+	m <<= k;
+	if ((m & assignid_map) == 0) {
+		goto G2Q_QUIN;
+	}
+	if (k > 0) {
+		k--;
+		goto small_id;
+	}
+G2Q5:				/* srch from max acceptable ID#  */
+	k = i;			/* max acceptable ID#            */
 G2Q_LP:
-    m=1;
-    m <<= k;
-    if ((m & assignid_map) == 0)
-    {
-       goto G2Q_QUIN;
-    }
-    if ( k > 0 )
-    {
-       k--;
-       goto G2Q_LP;
-    }
-G2Q_QUIN:		      /* k=binID#,	 */
-    assignid_map |= m;
-    if ( k < 8 )
-    {
-       quintet[0]=0x38;       /* 1st dft ID<8	 */
-    }
-    else
-    {
-       quintet[0]=0x31;       /* 1st  ID>=8	 */
-    }
-    k &= 0x07;
-    quintet[1]=g2q_tab[k];
-
-    val &= 0x00ff;	       /* AssignID 1stQuintet,AH=001xxxxx  */
-    m=quintet[0] << 8;
-    val |= m;
-    fun_scam(host,&val);
-    val &= 0x00ff;	       /* AssignID 2ndQuintet,AH=001xxxxx */
-    m=quintet[1] << 8;
-    val |= m;
-    fun_scam(host,&val);
+	m = 1;
+	m <<= k;
+	if ((m & assignid_map) == 0) {
+		goto G2Q_QUIN;
+	}
+	if (k > 0) {
+		k--;
+		goto G2Q_LP;
+	}
+G2Q_QUIN:		/* k=binID#,       */
+	assignid_map |= m;
+	if (k < 8) {
+		quintet[0] = 0x38;	/* 1st dft ID<8    */
+	} else {
+		quintet[0] = 0x31;	/* 1st  ID>=8      */
+	}
+	k &= 0x07;
+	quintet[1] = g2q_tab[k];
 
-    goto TCM_SYNC;
+	val &= 0x00ff;		/* AssignID 1stQuintet,AH=001xxxxx  */
+	m = quintet[0] << 8;
+	val |= m;
+	fun_scam(host, &val);
+	val &= 0x00ff;		/* AssignID 2ndQuintet,AH=001xxxxx */
+	m = quintet[1] << 8;
+	val |= m;
+	fun_scam(host, &val);
+
+	goto TCM_SYNC;
 
 }
 
-void is870(unsigned long host,unsigned int wkport )
+void is870(unsigned long host, unsigned int wkport)
 {
-    unsigned int  tmport ;
-    unsigned char i,j,k,rmb;
-    unsigned short int m;
-    static unsigned char mbuf[512];
-    static unsigned char satn[9] = { 0,0,0,0,0,0,0,6,6 };
-    static unsigned char inqd[9] = { 0x12,0,0,0,0x24,0,0,0x24,6 };
-    static unsigned char synn[6] = { 0x80,1,3,1,0x19,0x0e };
-    static unsigned char synu[6] = { 0x80,1,3,1,0x0c,0x0e };
-    static unsigned char synw[6] = { 0x80,1,3,1,0x0c,0x07 };
-    static unsigned char wide[6] = { 0x80,1,2,3,1,0 };
-
-    sync_idu=0;
-    tmport=wkport+0x3a;
-    outb((unsigned char)(inb(tmport) | 0x10),tmport);
-
-    for ( i = 0 ; i < 16 ; i ++ )
-    {
-	if ((chip_veru[host] != 4) && (i > 7))
-	{
-	   break;
-	}
-	m=1;
-	m=m<<i;
-	if ( ( m & active_idu[host] ) != 0 )
-	{
-	   continue;
-	}
-	if ( i == host_idu[host] )
-	{
-	   printk("         ID: %2d  Host Adapter\n",host_idu[host]);
-	   continue;
-	}
-	if ( chip_veru[host] == 4 )
-	{
-	   tmport=wkport+0x1b;
-	   j=(inb(tmport) & 0x0e) | 0x01;
-	   outb(j,tmport);
-	}
-    tmport=wkport+1;
-    outb(0x08,tmport++);
-    outb(0x7f,tmport++);
-    outb(satn[0],tmport++);
-    outb(satn[1],tmport++);
-    outb(satn[2],tmport++);
-    outb(satn[3],tmport++);
-    outb(satn[4],tmport++);
-    outb(satn[5],tmport++);
-    tmport+=0x06;
-    outb(0,tmport);
-    tmport+=0x02;
-    outb(devspu[host][i],tmport++);
-    outb(0,tmport++);
-    outb(satn[6],tmport++);
-    outb(satn[7],tmport++);
-    j=i;
-    if ((j & 0x08) != 0)
-    {
-       j=(j & 0x07) | 0x40;
-    }
-    outb(j,tmport);
-    tmport+=0x03;
-    outb(satn[8],tmport);
-    tmport+=0x07;
-
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
-    {
-       continue;
-    }
-    while ( inb(tmport) != 0x8e );
-    active_idu[host] |= m;
-
-    tmport=wkport+0x10;
-    outb(0x30,tmport);
-    tmport=wkport+0x04;
-    outb(0x00,tmport);
+	unsigned int tmport;
+	unsigned char i, j, k, rmb;
+	unsigned short int m;
+	static unsigned char mbuf[512];
+	static unsigned char satn[9] = 	{0, 0, 0, 0, 0, 0, 0, 6, 6};
+	static unsigned char inqd[9] =	{0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
+	static unsigned char synn[6] =  {0x80, 1, 3, 1, 0x19, 0x0e};
+	static unsigned char synu[6] =	{0x80, 1, 3, 1, 0x0c, 0x0e};
+	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x0c, 0x07};
+	static unsigned char wide[6] =  {0x80, 1, 2, 3, 1, 0};
+
+	sync_idu = 0;
+	tmport = wkport + 0x3a;
+	outb((unsigned char) (inb(tmport) | 0x10), tmport);
+
+	for (i = 0; i < 16; i++) {
+		if ((chip_veru[host] != 4) && (i > 7)) {
+			break;
+		}
+		m = 1;
+		m = m << i;
+		if ((m & active_idu[host]) != 0) {
+			continue;
+		}
+		if (i == host_idu[host]) {
+			printk("         ID: %2d  Host Adapter\n", host_idu[host]);
+			continue;
+		}
+		if (chip_veru[host] == 4) {
+			tmport = wkport + 0x1b;
+			j = (inb(tmport) & 0x0e) | 0x01;
+			outb(j, tmport);
+		}
+		tmport = wkport + 1;
+		outb(0x08, tmport++);
+		outb(0x7f, tmport++);
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(devspu[host][i], tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		j = i;
+		if ((j & 0x08) != 0) {
+			j = (j & 0x07) | 0x40;
+		}
+		outb(j, tmport);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e);
+		active_idu[host] |= m;
+
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x04;
+		outb(0x00, tmport);
 
 phase_cmd:
-    tmport=wkport+0x18;
-    outb(0x08,tmport);
-    tmport+=0x07;
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    j=inb(tmport);
-    if ( j != 0x16 )
-    {
-       tmport=wkport+0x10;
-       outb(0x41,tmport);
-       goto phase_cmd;
-    }
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			tmport = wkport + 0x10;
+			outb(0x41, tmport);
+			goto phase_cmd;
+		}
 sel_ok:
-       tmport=wkport+3;
-       outb(inqd[0],tmport++);
-       outb(inqd[1],tmport++);
-       outb(inqd[2],tmport++);
-       outb(inqd[3],tmport++);
-       outb(inqd[4],tmport++);
-       outb(inqd[5],tmport);
-       tmport+=0x07;
-       outb(0,tmport);
-       tmport+=0x02;
-       outb(devspu[host][i],tmport++);
-       outb(0,tmport++);
-       outb(inqd[6],tmport++);
-       outb(inqd[7],tmport++);
-       tmport+=0x03;
-       outb(inqd[8],tmport);
-       tmport+=0x07;
-       while ((inb(tmport) & 0x80) == 0x00);
-       tmport-=0x08;
-       if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
-       {
-	  continue;
-       }
-       while ( inb(tmport) != 0x8e );
-       if ( chip_veru[host] == 4 )
-       {
-	  tmport=wkport+0x1b;
-	  j=inb(tmport) & 0x0e;
-	  outb(j,tmport);
-       }
-       tmport=wkport+0x18;
-       outb(0x08,tmport);
-       tmport += 0x07;
-       j=0;
+		tmport = wkport + 3;
+		outb(inqd[0], tmport++);
+		outb(inqd[1], tmport++);
+		outb(inqd[2], tmport++);
+		outb(inqd[3], tmport++);
+		outb(inqd[4], tmport++);
+		outb(inqd[5], tmport);
+		tmport += 0x07;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(devspu[host][i], tmport++);
+		outb(0, tmport++);
+		outb(inqd[6], tmport++);
+		outb(inqd[7], tmport++);
+		tmport += 0x03;
+		outb(inqd[8], tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e);
+		if (chip_veru[host] == 4) {
+			tmport = wkport + 0x1b;
+			j = inb(tmport) & 0x0e;
+			outb(j, tmport);
+		}
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		j = 0;
 rd_inq_data:
-       k=inb(tmport);
-       if ((k & 0x01) != 0 )
-       {
-	  tmport-=0x06;
-	  mbuf[j++]=inb(tmport);
-	  tmport+=0x06;
-	  goto rd_inq_data;
-       }
-       if ((k & 0x80) == 0 )
-       {
-	  goto rd_inq_data;
-       }
-       tmport-=0x08;
-       j=inb(tmport);
-       if ( j == 0x16 )
-       {
-	  goto inq_ok;
-       }
-    tmport=wkport+0x10;
-    outb(0x46,tmport);
-    tmport+=0x02;
-    outb(0,tmport++);
-    outb(0,tmport++);
-    outb(0,tmport++);
-    tmport+=0x03;
-    outb(0x08,tmport);
-    tmport+=0x07;
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    if (inb(tmport) != 0x16)
-    {
-       goto sel_ok;
-    }
+		k = inb(tmport);
+		if ((k & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[j++] = inb(tmport);
+			tmport += 0x06;
+			goto rd_inq_data;
+		}
+		if ((k & 0x80) == 0) {
+			goto rd_inq_data;
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x16) {
+			goto inq_ok;
+		}
+		tmport = wkport + 0x10;
+		outb(0x46, tmport);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		if (inb(tmport) != 0x16) {
+			goto sel_ok;
+		}
 inq_ok:
-     mbuf[36]=0;
-     printk("         ID: %2d  %s\n",i,&mbuf[8]);
-     devtypeu[host][i]=mbuf[0];
-     rmb=mbuf[1];
-     if ( chip_veru[host] != 4 )
-     {
-	goto not_wide;
-     }
-     if ((mbuf[7] & 0x60) == 0)
-     {
-	goto not_wide;
-     }
-     if ((global_map[host] & 0x20) == 0)
-     {
-	goto not_wide;
-     }
-     tmport=wkport+0x1b;
-     j=(inb(tmport) & 0x0e) | 0x01;
-     outb(j,tmport);
-    tmport=wkport+3;
-    outb(satn[0],tmport++);
-    outb(satn[1],tmport++);
-    outb(satn[2],tmport++);
-    outb(satn[3],tmport++);
-    outb(satn[4],tmport++);
-    outb(satn[5],tmport++);
-    tmport+=0x06;
-    outb(0,tmport);
-    tmport+=0x02;
-    outb(devspu[host][i],tmport++);
-    outb(0,tmport++);
-    outb(satn[6],tmport++);
-    outb(satn[7],tmport++);
-    tmport+=0x03;
-    outb(satn[8],tmport);
-    tmport+=0x07;
-
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
-    {
-       continue;
-    }
-    while ( inb(tmport) != 0x8e );
+		mbuf[36] = 0;
+		printk("         ID: %2d  %s\n", i, &mbuf[8]);
+		devtypeu[host][i] = mbuf[0];
+		rmb = mbuf[1];
+		if (chip_veru[host] != 4) {
+			goto not_wide;
+		}
+		if ((mbuf[7] & 0x60) == 0) {
+			goto not_wide;
+		}
+		if ((global_map[host] & 0x20) == 0) {
+			goto not_wide;
+		}
+		tmport = wkport + 0x1b;
+		j = (inb(tmport) & 0x0e) | 0x01;
+		outb(j, tmport);
+		tmport = wkport + 3;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(devspu[host][i], tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e);
 try_wide:
-    j=0;
-    tmport=wkport+0x14;
-    outb(0x05,tmport);
-    tmport += 0x04;
-    outb(0x20,tmport);
-    tmport+=0x07;
-
-    while ((inb(tmport) & 0x80) == 0 )
-    {
-       if ((inb(tmport) & 0x01) != 0 )
-       {
-	  tmport-=0x06;
-	  outb(wide[j++],tmport);
-	  tmport+=0x06;
-       }
-    }
-    tmport-=0x08;
-    while ((inb(tmport) & 0x80) == 0x00);
-    j=inb(tmport) & 0x0f;
-    if ( j == 0x0f )
-    {
-       goto widep_in;
-    }
-    if ( j == 0x0a )
-    {
-       goto widep_cmd;
-    }
-    if ( j == 0x0e )
-    {
-       goto try_wide;
-    }
-    continue;
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x05, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(wide[j++], tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00);
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_wide;
+		}
+		continue;
 widep_out:
-    tmport=wkport+0x18;
-    outb(0x20,tmport);
-    tmport+=0x07;
-    while ((inb(tmport) & 0x80) == 0 )
-    {
-	if ((inb(tmport) & 0x01) != 0 )
-	{
-	   tmport-=0x06;
-	   outb(0,tmport);
-	   tmport+=0x06;
-	}
-    }
-    tmport-=0x08;
-    j=inb(tmport) & 0x0f;
-    if ( j == 0x0f )
-    {
-       goto widep_in;
-    }
-    if ( j == 0x0a )
-    {
-       goto widep_cmd;
-    }
-    if ( j == 0x0e )
-    {
-       goto widep_out;
-    }
-    continue;
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
 widep_in:
-    tmport=wkport+0x14;
-    outb(0xff,tmport);
-    tmport += 0x04;
-    outb(0x20,tmport);
-    tmport+=0x07;
-    k=0;
+		tmport = wkport + 0x14;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
 widep_in1:
-    j=inb(tmport);
-    if ((j & 0x01) != 0)
-    {
-       tmport-=0x06;
-       mbuf[k++]=inb(tmport);
-       tmport+=0x06;
-       goto widep_in1;
-    }
-    if ((j & 0x80) == 0x00)
-    {
-       goto widep_in1;
-    }
-    tmport-=0x08;
-    j=inb(tmport) & 0x0f;
-    if ( j == 0x0f )
-    {
-       goto widep_in;
-    }
-    if ( j == 0x0a )
-    {
-       goto widep_cmd;
-    }
-    if ( j == 0x0e )
-    {
-       goto widep_out;
-    }
-    continue;
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto widep_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto widep_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
 widep_cmd:
-    tmport=wkport+0x10;
-    outb(0x30,tmport);
-    tmport=wkport+0x14;
-    outb(0x00,tmport);
-    tmport+=0x04;
-    outb(0x08,tmport);
-    tmport+=0x07;
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    j=inb(tmport);
-    if ( j != 0x16 )
-    {
-       if ( j == 0x4e )
-       {
-	  goto widep_out;
-       }
-       continue;
-    }
-    if ( mbuf[0] != 0x01 )
-    {
-       goto not_wide;
-    }
-    if ( mbuf[1] != 0x02 )
-    {
-       goto not_wide;
-    }
-    if ( mbuf[2] != 0x03 )
-    {
-       goto not_wide;
-    }
-    if ( mbuf[3] != 0x01 )
-    {
-       goto not_wide;
-    }
-    m=1;
-    m = m << i;
-    wide_idu[host] |= m;
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto widep_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto not_wide;
+		}
+		if (mbuf[1] != 0x02) {
+			goto not_wide;
+		}
+		if (mbuf[2] != 0x03) {
+			goto not_wide;
+		}
+		if (mbuf[3] != 0x01) {
+			goto not_wide;
+		}
+		m = 1;
+		m = m << i;
+		wide_idu[host] |= m;
 not_wide:
-    if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07))
-    {
-       goto set_sync;
-    }
-    continue;
+		if ((devtypeu[host][i] == 0x00) || (devtypeu[host][i] == 0x07)) {
+			goto set_sync;
+		}
+		continue;
 set_sync:
-    tmport=wkport+0x1b;
-    j=inb(tmport) & 0x0e;
-    if ((m & wide_idu[host]) != 0 )
-    {
-       j |= 0x01;
-    }
-    outb(j,tmport);
-    tmport=wkport+3;
-    outb(satn[0],tmport++);
-    outb(satn[1],tmport++);
-    outb(satn[2],tmport++);
-    outb(satn[3],tmport++);
-    outb(satn[4],tmport++);
-    outb(satn[5],tmport++);
-    tmport+=0x06;
-    outb(0,tmport);
-    tmport+=0x02;
-    outb(devspu[host][i],tmport++);
-    outb(0,tmport++);
-    outb(satn[6],tmport++);
-    outb(satn[7],tmport++);
-    tmport+=0x03;
-    outb(satn[8],tmport);
-    tmport+=0x07;
-
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e))
-    {
-       continue;
-    }
-    while ( inb(tmport) != 0x8e);
+		tmport = wkport + 0x1b;
+		j = inb(tmport) & 0x0e;
+		if ((m & wide_idu[host]) != 0) {
+			j |= 0x01;
+		}
+		outb(j, tmport);
+		tmport = wkport + 3;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(devspu[host][i], tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e);
 try_sync:
-    j=0;
-    tmport=wkport+0x14;
-    outb(0x06,tmport);
-    tmport += 0x04;
-    outb(0x20,tmport);
-    tmport+=0x07;
-
-    while ((inb(tmport) & 0x80) == 0 )
-    {
-       if ((inb(tmport) & 0x01) != 0 )
-       {
-	  tmport-=0x06;
-	  if ( rmb != 0 )
-	  {
-	     outb(synn[j++],tmport);
-	  }
-	  else
-	  {
-	     if ((m & wide_idu[host]) != 0)
-	     {
-		outb(synw[j++],tmport);
-	     }
-	     else
-	     {
-		if ((m & ultra_map[host]) != 0)
-		{
-		   outb(synu[j++],tmport);
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				if (rmb != 0) {
+					outb(synn[j++], tmport);
+				} else {
+					if ((m & wide_idu[host]) != 0) {
+						outb(synw[j++], tmport);
+					} else {
+						if ((m & ultra_map[host]) != 0) {
+							outb(synu[j++], tmport);
+						} else {
+							outb(synn[j++], tmport);
+						}
+					}
+				}
+				tmport += 0x06;
+			}
 		}
-		else
-		{
-		   outb(synn[j++],tmport);
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00);
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
 		}
-	     }
-	  }
-	  tmport+=0x06;
-       }
-    }
-    tmport-=0x08;
-    while ((inb(tmport) & 0x80) == 0x00);
-    j=inb(tmport) & 0x0f;
-    if ( j == 0x0f )
-    {
-       goto phase_ins;
-    }
-    if ( j == 0x0a )
-    {
-       goto phase_cmds;
-    }
-    if ( j == 0x0e )
-    {
-       goto try_sync;
-    }
-    continue;
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto try_sync;
+		}
+		continue;
 phase_outs:
-    tmport=wkport+0x18;
-    outb(0x20,tmport);
-    tmport+=0x07;
-    while ((inb(tmport) & 0x80) == 0x00)
-    {
-      if ((inb(tmport) & 0x01) != 0x00)
-      {
-	 tmport-=0x06;
-	 outb(0x00,tmport);
-	 tmport+=0x06;
-      }
-    }
-    tmport-=0x08;
-    j=inb(tmport);
-    if ( j == 0x85 )
-    {
-       goto tar_dcons;
-    }
-    j &= 0x0f;
-    if ( j == 0x0f )
-    {
-       goto phase_ins;
-    }
-    if ( j == 0x0a )
-    {
-       goto phase_cmds;
-    }
-    if ( j == 0x0e )
-    {
-       goto phase_outs;
-    }
-    continue;
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00) {
+			if ((inb(tmport) & 0x01) != 0x00) {
+				tmport -= 0x06;
+				outb(0x00, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
 phase_ins:
-    tmport=wkport+0x14;
-    outb(0xff,tmport);
-    tmport += 0x04;
-    outb(0x20,tmport);
-    tmport+=0x07;
-    k=0;
+		tmport = wkport + 0x14;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
 phase_ins1:
-    j=inb(tmport);
-    if ((j & 0x01) != 0x00)
-    {
-       tmport-=0x06;
-       mbuf[k++]=inb(tmport);
-       tmport+=0x06;
-       goto phase_ins1;
-    }
-    if ((j & 0x80) == 0x00)
-    {
-       goto phase_ins1;
-    }
-    tmport-=0x08;
-    while ((inb(tmport) & 0x80) == 0x00);
-    j=inb(tmport);
-    if ( j == 0x85 )
-    {
-       goto tar_dcons;
-    }
-    j &= 0x0f;
-    if ( j == 0x0f )
-    {
-       goto phase_ins;
-    }
-    if ( j == 0x0a )
-    {
-       goto phase_cmds;
-    }
-    if ( j == 0x0e )
-    {
-       goto phase_outs;
-    }
-    continue;
+		j = inb(tmport);
+		if ((j & 0x01) != 0x00) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto phase_ins1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto phase_ins1;
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00);
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
 phase_cmds:
-    tmport=wkport+0x10;
-    outb(0x30,tmport);
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
 tar_dcons:
-    tmport=wkport+0x14;
-    outb(0x00,tmport);
-    tmport+=0x04;
-    outb(0x08,tmport);
-    tmport+=0x07;
-    while ((inb(tmport) & 0x80) == 0x00);
-    tmport-=0x08;
-    j=inb(tmport);
-    if ( j != 0x16 )
-    {
-       continue;
-    }
-    if ( mbuf[0] != 0x01 )
-    {
-       continue;
-    }
-    if ( mbuf[1] != 0x03 )
-    {
-       continue;
-    }
-    if ( mbuf[4] == 0x00 )
-    {
-       continue;
-    }
-    if ( mbuf[3] > 0x64 )
-    {
-       continue;
-    }
-    if ( mbuf[4] > 0x0c )
-    {
-       mbuf[4]=0x0c;
-    }
-    devspu[host][i] = mbuf[4];
-    if ((mbuf[3] < 0x0d) && (rmb == 0))
-    {
-       j=0xa0;
-       goto set_syn_ok;
-    }
-    if ( mbuf[3] < 0x1a )
-    {
-       j=0x20;
-       goto set_syn_ok;
-    }
-    if ( mbuf[3] < 0x33 )
-    {
-       j=0x40;
-       goto set_syn_ok;
-    }
-    if ( mbuf[3] < 0x4c )
-    {
-       j=0x50;
-       goto set_syn_ok;
-    }
-    j=0x60;
-set_syn_ok:
-    devspu[host][i] = (devspu[host][i] & 0x0f) | j;
-   }
-   tmport=wkport+0x3a;
-   outb((unsigned char)(inb(tmport) & 0xef),tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			continue;
+		}
+		if (mbuf[1] != 0x03) {
+			continue;
+		}
+		if (mbuf[4] == 0x00) {
+			continue;
+		}
+		if (mbuf[3] > 0x64) {
+			continue;
+		}
+		if (mbuf[4] > 0x0c) {
+			mbuf[4] = 0x0c;
+		}
+		devspu[host][i] = mbuf[4];
+		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
+			j = 0xa0;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x1a) {
+			j = 0x20;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x33) {
+			j = 0x40;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x4c) {
+			j = 0x50;
+			goto set_syn_ok;
+		}
+		j = 0x60;
+	      set_syn_ok:
+		devspu[host][i] = (devspu[host][i] & 0x0f) | j;
+	}
+	tmport = wkport + 0x3a;
+	outb((unsigned char) (inb(tmport) & 0xef), tmport);
 }
 
 /* return non-zero on detection */
 int atp870u_detect(Scsi_Host_Template * tpnt)
 {
-    unsigned char irq,h,k;
-    unsigned long flags;
-    unsigned int base_io,error,tmport;
-    unsigned short index = 0;
-    unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3],host_id;
-    struct Scsi_Host * shpnt = NULL;
-    int count = 0;
-    static unsigned short devid[7]={0x8002,0x8010,0x8020,0x8030,0x8040,0x8050,0};
-    static struct pci_dev *pdev = NULL, *acard_pdev[3];
-
-    printk("aec671x_detect: \n");
-    if (!pci_present())
-    {
-       printk("   NO BIOS32 SUPPORT.\n");
-       return count;
-    }
-
-    tpnt->proc_dir = &proc_scsi_atp870u;
-
-    for ( h = 0 ; h < 2 ; h++ )
-    {
-      active_idu[h]=0;
-      wide_idu[h]=0;
-      host_idu[h]=0x07;
-      quhdu[h]=0;
-      quendu[h]=0;
-      pci_bus[h]=0;
-      pci_device_fn[h]=0xff;
-      chip_ver[h]=0;
-      last_cmd[h]=0xff;
-      in_snd[h]=0;
-      in_int[h]=0;
-      for ( k = 0 ; k < qcnt ; k++ )
-      {
-	  querequ[h][k]=0;
-      }
-      for ( k = 0 ; k < 16 ; k++ )
-      {
-	  curr_req[h][k]=0;
-      }
-    }
-    h=0;
-    while ( devid[h] != 0 )
-    {
-      pdev = pci_find_device(0x1191,devid[h],pdev);
-      if (pdev == NULL) {
-	  h++;
-	  index=0;
-	  continue;
-       }
-       chip_ver[2]=0;
-	   
-       /* To avoid messing with the things below...  */
-       acard_pdev[2] = pdev;
-       pci_device_fn[2] =  pdev->devfn;
-       pci_bus[2] = pdev->bus->number;
-
-       if ( devid[h] == 0x8002 )
-       {
-	  error = pci_read_config_byte(pdev,0x08,&chip_ver[2]);
-	  if ( chip_ver[2] < 2 )
-	  {
-	     goto nxt_devfn;
-	  }
-       }
-       if ( devid[h] == 0x8010 )
-       {
-	  chip_ver[2]=0x04;
-       }
-       if ( pci_device_fn[2] < pci_device_fn[0] )
-       {
-	  acard_pdev[1]=acard_pdev[0];
-	  pci_bus[1]=pci_bus[0];
-	  pci_device_fn[1]=pci_device_fn[0];
-	  chip_ver[1]=chip_ver[0];
-	  acard_pdev[0]=acard_pdev[2];
-	  pci_bus[0]=pci_bus[2];
-	  pci_device_fn[0]=pci_device_fn[2];
-	  chip_ver[0]=chip_ver[2];
-       }
-       else if ( pci_device_fn[2] < pci_device_fn[1] )
-       {
-	  acard_pdev[1]=acard_pdev[2];
-	  pci_bus[1]=pci_bus[2];
-	  pci_device_fn[1]=pci_device_fn[2];
-	  chip_ver[1]=chip_ver[2];
-       }
-nxt_devfn:
-       index++;
-       if ( index > 3 )
-       {
-	  index=0;
-	  h++;
-       }
-    }
-    for ( h=0; h < 2; h++ )
-    {
-    if ( pci_device_fn[h] == 0xff )
-    {
-       return count;
-    }
-
-    pdev = acard_pdev[h];
-    pdev->devfn = pci_device_fn[h];
-    pdev->bus->number = pci_bus[h];
-
-    /* Found an atp870u/w. */
-    error = pci_read_config_dword(pdev,0x10,&base_io);
-    error += pci_read_config_byte(pdev,0x3c,&irq);
-    error += pci_read_config_byte(pdev,0x49,&host_id);
-
-    base_io &= 0xfffffff8;
-    printk("   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d    IO:%x, IRQ:%d.\n"
-			     ,h,base_io,irq);
-    ioportu[h]=base_io;
-    pciportu[h]=base_io + 0x20;
-    irqnumu[h]=irq;
-    host_id &= 0x07;
-    host_idu[h]=host_id;
-    chip_veru[h]=chip_ver[h];
-
-    tmport=base_io+0x22;
-    scam_on[h]=inb(tmport);
-    tmport += 0x0b;
-    global_map[h]=inb(tmport++);
-    ultra_map[h]=inw(tmport);
-    if ( ultra_map[h] == 0 )
-    {
-       scam_on[h]=0x00;
-       global_map[h]=0x20;
-       ultra_map[h]=0xffff;
-    }
-
-    shpnt = scsi_register(tpnt,4);
-
-    save_flags(flags);
-    cli();
-    if (request_irq(irq,atp870u_intr_handle, 0, "atp870u", NULL))
-    {
-       printk("Unable to allocate IRQ for Acard controller.\n");
-       goto unregister;
-    }
-
-    tmport=base_io+0x3a;
-    k=(inb(tmport) & 0xf3) | 0x10;
-    outb(k,tmport);
-    outb((k & 0xdf),tmport);
-    mydlyu(0x8000);
-    outb(k,tmport);
-    mydlyu(0x8000);
-    tmport=base_io;
-    outb((host_id | 0x08),tmport);
-    tmport += 0x18;
-    outb(0,tmport);
-    tmport += 0x07;
-    while ((inb(tmport) & 0x80) == 0);
-    tmport -= 0x08;
-    inb(tmport);
-    tmport = base_io +1;
-    outb(8,tmport++);
-    outb(0x7f,tmport);
-    tmport = base_io + 0x11;
-    outb(0x20,tmport);
-
-    tscam(h);
-    is870(h,base_io);
-    tmport=base_io+0x3a;
-    outb((inb(tmport) & 0xef),tmport);
-
-    atp_host[h] = shpnt;
-    if ( chip_ver[h] == 4 )
-    {
-       shpnt->max_id = 16;
-    }
-    shpnt->this_id = host_id;
-    shpnt->unique_id = base_io;
-    shpnt->io_port = base_io;
-    shpnt->n_io_port = 0x40;  /* Number of bytes of I/O space used */
-    shpnt->irq = irq;
-    restore_flags(flags);
-    request_region(base_io, 0x40,"atp870u");  /* Register the IO ports that we use */
-    count++;
-    index++;
-    continue;
+	unsigned char irq, h, k;
+	unsigned long flags;
+	unsigned int base_io, error, tmport;
+	unsigned short index = 0;
+	unsigned char pci_bus[3], pci_device_fn[3], chip_ver[3], host_id;
+	struct Scsi_Host *shpnt = NULL;
+	int count = 0;
+	static unsigned short devid[7] =
+	{0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0};
+	static struct pci_dev *pdev = NULL, *acard_pdev[3];
+
+	printk("aec671x_detect: \n");
+	if (!pci_present()) {
+		printk("   NO BIOS32 SUPPORT.\n");
+		return count;
+	}
+	tpnt->proc_dir = &proc_scsi_atp870u;
+
+	for (h = 0; h < 2; h++) {
+		active_idu[h] = 0;
+		wide_idu[h] = 0;
+		host_idu[h] = 0x07;
+		quhdu[h] = 0;
+		quendu[h] = 0;
+		pci_bus[h] = 0;
+		pci_device_fn[h] = 0xff;
+		chip_ver[h] = 0;
+		last_cmd[h] = 0xff;
+		in_snd[h] = 0;
+		in_int[h] = 0;
+		for (k = 0; k < qcnt; k++) {
+			querequ[h][k] = 0;
+		}
+		for (k = 0; k < 16; k++) {
+			curr_req[h][k] = 0;
+		}
+	}
+	h = 0;
+	while (devid[h] != 0) {
+		pdev = pci_find_device(0x1191, devid[h], pdev);
+		if (pdev == NULL) {
+			h++;
+			index = 0;
+			continue;
+		}
+		chip_ver[2] = 0;
+
+		/* To avoid messing with the things below...  */
+		acard_pdev[2] = pdev;
+		pci_device_fn[2] = pdev->devfn;
+		pci_bus[2] = pdev->bus->number;
+
+		if (devid[h] == 0x8002) {
+			error = pci_read_config_byte(pdev, 0x08, &chip_ver[2]);
+			if (chip_ver[2] < 2) {
+				goto nxt_devfn;
+			}
+		}
+		if (devid[h] == 0x8010) {
+			chip_ver[2] = 0x04;
+		}
+		if (pci_device_fn[2] < pci_device_fn[0]) {
+			acard_pdev[1] = acard_pdev[0];
+			pci_bus[1] = pci_bus[0];
+			pci_device_fn[1] = pci_device_fn[0];
+			chip_ver[1] = chip_ver[0];
+			acard_pdev[0] = acard_pdev[2];
+			pci_bus[0] = pci_bus[2];
+			pci_device_fn[0] = pci_device_fn[2];
+			chip_ver[0] = chip_ver[2];
+		} else if (pci_device_fn[2] < pci_device_fn[1]) {
+			acard_pdev[1] = acard_pdev[2];
+			pci_bus[1] = pci_bus[2];
+			pci_device_fn[1] = pci_device_fn[2];
+			chip_ver[1] = chip_ver[2];
+		}
+	      nxt_devfn:
+		index++;
+		if (index > 3) {
+			index = 0;
+			h++;
+		}
+	}
+	for (h = 0; h < 2; h++) {
+		if (pci_device_fn[h] == 0xff) {
+			return count;
+		}
+		pdev = acard_pdev[h];
+		pdev->devfn = pci_device_fn[h];
+		pdev->bus->number = pci_bus[h];
+
+		/* Found an atp870u/w. */
+		error = pci_read_config_dword(pdev, 0x10, &base_io);
+		error += pci_read_config_byte(pdev, 0x3c, &irq);
+		error += pci_read_config_byte(pdev, 0x49, &host_id);
+
+		base_io &= 0xfffffff8;
+		printk("   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d    IO:%x, IRQ:%d.\n"
+		       ,h, base_io, irq);
+		ioportu[h] = base_io;
+		pciportu[h] = base_io + 0x20;
+		irqnumu[h] = irq;
+		host_id &= 0x07;
+		host_idu[h] = host_id;
+		chip_veru[h] = chip_ver[h];
+
+		tmport = base_io + 0x22;
+		scam_on[h] = inb(tmport);
+		tmport += 0x0b;
+		global_map[h] = inb(tmport++);
+		ultra_map[h] = inw(tmport);
+		if (ultra_map[h] == 0) {
+			scam_on[h] = 0x00;
+			global_map[h] = 0x20;
+			ultra_map[h] = 0xffff;
+		}
+		shpnt = scsi_register(tpnt, 4);
+
+		save_flags(flags);
+		cli();
+		if (request_irq(irq, atp870u_intr_handle, 0, "atp870u", NULL)) {
+			printk("Unable to allocate IRQ for Acard controller.\n");
+			goto unregister;
+		}
+		tmport = base_io + 0x3a;
+		k = (inb(tmport) & 0xf3) | 0x10;
+		outb(k, tmport);
+		outb((k & 0xdf), tmport);
+		mydlyu(0x8000);
+		outb(k, tmport);
+		mydlyu(0x8000);
+		tmport = base_io;
+		outb((host_id | 0x08), tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0);
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 1;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0x11;
+		outb(0x20, tmport);
+
+		tscam(h);
+		is870(h, base_io);
+		tmport = base_io + 0x3a;
+		outb((inb(tmport) & 0xef), tmport);
+
+		atp_host[h] = shpnt;
+		if (chip_ver[h] == 4) {
+			shpnt->max_id = 16;
+		}
+		shpnt->this_id = host_id;
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
+		shpnt->n_io_port = 0x40;	/* Number of bytes of I/O space used */
+		shpnt->irq = irq;
+		restore_flags(flags);
+		request_region(base_io, 0x40, "atp870u");	/* Register the IO ports that we use */
+		count++;
+		index++;
+		continue;
 unregister:
-    scsi_unregister(shpnt);
-    restore_flags(flags);
-    index++;
-    continue;
-    }
+		scsi_unregister(shpnt);
+		restore_flags(flags);
+		index++;
+		continue;
+	}
 
-    return count;
+	return count;
 }
 
 /* The abort command does not leave the device in a clean state where
@@ -1883,162 +1621,147 @@
 
 int atp870u_abort(Scsi_Cmnd * SCpnt)
 {
-    unsigned char h,j;
-    unsigned int  tmport;
+	unsigned char h, j;
+	unsigned int tmport;
 /*    printk(" atp870u_abort: \n");   */
-    for ( h=0; h <= admaxu; h++ )
-    {
-	if ( SCpnt->host == atp_host[h] )
-	{
-	   goto find_adp;
+	for (h = 0; h <= admaxu; h++) {
+		if (SCpnt->host == atp_host[h]) {
+			goto find_adp;
+		}
 	}
-    }
-    panic("Abort host not found !");
+	panic("Abort host not found !");
 find_adp:
-    printk(" workingu=%x last_cmd=%x ",workingu[h],last_cmd[h]);
-    printk(" quhdu=%x quendu=%x ",quhdu[h],quendu[h]);
-    tmport=ioportu[h];
-    for ( j=0; j < 0x17; j++)
-    {
-	printk(" r%2x=%2x",j,inb(tmport++));
-    }
-    tmport += 0x05;
-    printk(" r1c=%2x",inb(tmport));
-    tmport += 0x03;
-    printk(" r1f=%2x in_snd=%2x ",inb(tmport),in_snd[h]);
-    tmport++;
-    printk(" r20=%2x",inb(tmport));
-    tmport += 0x02;
-    printk(" r22=%2x \n",inb(tmport));
-    return (SCSI_ABORT_SNOOZE);
+	printk(" workingu=%x last_cmd=%x ", workingu[h], last_cmd[h]);
+	printk(" quhdu=%x quendu=%x ", quhdu[h], quendu[h]);
+	tmport = ioportu[h];
+	for (j = 0; j < 0x17; j++) {
+		printk(" r%2x=%2x", j, inb(tmport++));
+	}
+	tmport += 0x05;
+	printk(" r1c=%2x", inb(tmport));
+	tmport += 0x03;
+	printk(" r1f=%2x in_snd=%2x ", inb(tmport), in_snd[h]);
+	tmport++;
+	printk(" r20=%2x", inb(tmport));
+	tmport += 0x02;
+	printk(" r22=%2x \n", inb(tmport));
+	return (SCSI_ABORT_SNOOZE);
 }
 
 int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
-    unsigned char h;
-    /*
-     * See if a bus reset was suggested.
-     */
-/*    printk("atp870u_reset: \n");    */
-    for( h=0; h <= admaxu; h++ )
-    {
-       if ( SCpnt->host == atp_host[h] )
-       {
-	  goto find_host;
-       }
-    }
-    panic("Reset bus host not found !");
+	unsigned char h;
+	/*
+	 * See if a bus reset was suggested.
+	 */
+/*	printk("atp870u_reset: \n");    */
+	for (h = 0; h <= admaxu; h++) {
+		if (SCpnt->host == atp_host[h]) {
+			goto find_host;
+		}
+	}
+	panic("Reset bus host not found !");
 find_host:
-/*    SCpnt->result = 0x00080000;
-    SCpnt->scsi_done(SCpnt);
-    workingu[h]=0;
-    quhdu[h]=0;
-    quendu[h]=0;
-    return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);  */
-    return (SCSI_RESET_SNOOZE);
+/*      SCpnt->result = 0x00080000;
+	SCpnt->scsi_done(SCpnt);
+	workingu[h]=0;
+	quhdu[h]=0;
+	quendu[h]=0;
+	return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);  */
+	return (SCSI_RESET_SNOOZE);
 }
 
-const char *
-atp870u_info(struct Scsi_Host *notused)
+const char *atp870u_info(struct Scsi_Host *notused)
 {
-  static char buffer[128];
+	static char buffer[128];
 
-  strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
+	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V1.0 ");
 
-  return buffer;
+	return buffer;
 }
 
-int
-atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
 {
-  return (-ENOSYS);  /* Currently this is a no-op */
+	return (-ENOSYS);	/* Currently this is a no-op */
 }
 
 #define BLS buffer + len + size
-int
-atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
-    int hostno, int inout)
+int atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
+		      int hostno, int inout)
 {
-  struct Scsi_Host *HBAptr;
-  static u8 buff[512];
-  int	i;
-  int	size = 0;
-  int	len = 0;
-  off_t begin = 0;
-  off_t pos = 0;
-
-  HBAptr = NULL;
-  for (i = 0; i < 2; i++)
-  {
-    if ((HBAptr = atp_host[i]) != NULL)
-    {
-      if (HBAptr->host_no == hostno)
-      {
-	break;
-      }
-      HBAptr = NULL;
-    }
-  }
-
-  if (HBAptr == NULL)
-  {
-    size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
-    len += size; pos = begin + len; size = 0;
-    goto stop_output;
-  }
-
-  if (inout == TRUE) /* Has data been written to the file? */
-  {
-    return (atp870u_set_info(buffer, length, HBAptr));
-  }
-
-  if (offset == 0)
-  {
-    memset(buff, 0, sizeof(buff));
-  }
-
-  size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
-  len += size; pos = begin + len; size = 0;
-
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Adapter Configuration:\n");
-  size += sprintf(BLS, "               Base IO: %#.4lx\n", HBAptr->io_port);
-  size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
-  len += size; pos = begin + len; size = 0;
-
-stop_output:
-  *start = buffer + (offset - begin);	/* Start of wanted data */
-  len -= (offset - begin);	/* Start slop */
-  if (len > length)
-  {
-    len = length;		/* Ending slop */
-  }
+	struct Scsi_Host *HBAptr;
+	static u8 buff[512];
+	int i;
+	int size = 0;
+	int len = 0;
+	off_t begin = 0;
+	off_t pos = 0;
+
+	HBAptr = NULL;
+	for (i = 0; i < 2; i++) {
+		if ((HBAptr = atp_host[i]) != NULL) {
+			if (HBAptr->host_no == hostno) {
+				break;
+			}
+			HBAptr = NULL;
+		}
+	}
 
-  return (len);
+	if (HBAptr == NULL) {
+		size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
+		len += size;
+		pos = begin + len;
+		size = 0;
+		goto stop_output;
+	}
+	if (inout == TRUE) {	/* Has data been written to the file? */
+		return (atp870u_set_info(buffer, length, HBAptr));
+	}
+	if (offset == 0) {
+		memset(buff, 0, sizeof(buff));
+	}
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 1.0\n");
+	len += size;
+	pos = begin + len;
+	size = 0;
+
+	size += sprintf(BLS, "\n");
+	size += sprintf(BLS, "Adapter Configuration:\n");
+	size += sprintf(BLS, "               Base IO: %#.4lx\n", HBAptr->io_port);
+	size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
+	len += size;
+	pos = begin + len;
+	size = 0;
+
+      stop_output:
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);	/* Start slop */
+	if (len > length) {
+		len = length;	/* Ending slop */
+	}
+	return (len);
 }
 
 #include "sd.h"
 
-int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip)
+int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
 {
-  int heads, sectors, cylinders;
+	int heads, sectors, cylinders;
 
-  heads = 64;
-  sectors = 32;
-  cylinders = disk->capacity / (heads * sectors);
-
-  if ( cylinders > 1024 )
-  {
-    heads = 255;
-    sectors = 63;
-    cylinders = disk->capacity / (heads * sectors);
-  }
-
-  ip[0] = heads;
-  ip[1] = sectors;
-  ip[2] = cylinders;
+	heads = 64;
+	sectors = 32;
+	cylinders = disk->capacity / (heads * sectors);
+
+	if (cylinders > 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = disk->capacity / (heads * sectors);
+	}
+	ip[0] = heads;
+	ip[1] = sectors;
+	ip[2] = cylinders;
 
-  return 0;
+	return 0;
 }
 
 #ifdef MODULE
@@ -2046,4 +1769,3 @@
 
 #include "scsi_module.c"
 #endif
-
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/atp870u.h linux/drivers/scsi/atp870u.h
--- v2.3.22/linux/drivers/scsi/atp870u.h	Sun Dec 27 22:19:20 1998
+++ linux/drivers/scsi/atp870u.h	Mon Oct 18 11:35:54 1999
@@ -1,7 +1,7 @@
 #ifndef _ATP870U_H
 
 /* $Id: atp870u.h,v 1.0 1997/05/07 15:09:00 root Exp root $
- *
+
  * Header file for the ACARD 870U/W driver for Linux
  *
  * $Log: atp870u.h,v $
@@ -20,10 +20,10 @@
 
 int atp870u_detect(Scsi_Host_Template *);
 int atp870u_command(Scsi_Cmnd *);
-int atp870u_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int atp870u_abort(Scsi_Cmnd *);
 int atp870u_reset(Scsi_Cmnd *, unsigned int);
-int atp870u_biosparam(Disk *, kdev_t, int*);
+int atp870u_biosparam(Disk *, kdev_t, int *);
 void send_s870(unsigned char);
 
 #define qcnt            32
@@ -31,7 +31,7 @@
 #define ATP870U_CMDLUN 1
 
 #ifndef NULL
-        #define NULL 0
+#define NULL 0
 #endif
 
 extern struct proc_dir_entry proc_scsi_atp870u;
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.3.22/linux/drivers/scsi/ide-scsi.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/ide-scsi.c	Mon Oct 18 11:14:22 1999
@@ -299,11 +299,6 @@
 	scsi->pc = NULL;
 }
 
-static inline unsigned long get_timeout(idescsi_pc_t *pc)
-{
-	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
-}
-
 /*
  *	Our interrupt handler.
  */
@@ -364,7 +359,8 @@
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
 				idescsi_discard_data (drive,bcount - temp);
-				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));
+				drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+				ide_set_handler(drive, &idescsi_pc_intr);
 				return;
 			}
 #if IDESCSI_DEBUG_LOG
@@ -388,7 +384,8 @@
 	pc->actually_transferred+=bcount;				/* Update the current position */
 	pc->current_position+=bcount;
 
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));	/* And set the interrupt handler again */
+	drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+	ide_set_handler(drive, &idescsi_pc_intr);	/* And set the interrupt handler again */
 }
 
 static void idescsi_transfer_pc (ide_drive_t *drive)
@@ -407,7 +404,8 @@
 		ide_do_reset (drive);
 		return;
 	}
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));	/* Set the interrupt routine */
+	drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+	ide_set_handler(drive, &idescsi_pc_intr);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
 }
 
@@ -441,7 +439,8 @@
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 	}
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc));
+		drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+		ide_set_handler (drive, &idescsi_transfer_pc);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -488,7 +487,7 @@
 /*
  *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
  */
-	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_SHORT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
+	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
 	ide_add_setting(drive,	"bios_head",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
 	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
 	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h
--- v2.3.22/linux/drivers/scsi/inia100.h	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/inia100.h	Fri Oct 22 12:48:21 1999
@@ -349,8 +349,8 @@
 #define ORC_BUSDEVRST	0x01	/* SCSI Bus Device Reset  */
 
 /* Status of ORCSCB_Status */
-#define SCB_COMPLETE	0x00	/* SCB request completed  */
-#define SCB_POST	0x01	/* SCB is posted by the HOST      */
+#define ORCSCB_COMPLETE	0x00	/* SCB request completed  */
+#define ORCSCB_POST	0x01	/* SCB is posted by the HOST      */
 
 /* Bit Definition for ORCSCB_Flags */
 #define SCF_DISINT	0x01	/* Disable HOST interrupt */
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- v2.3.22/linux/drivers/scsi/ips.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/scsi/ips.c	Mon Oct 18 11:26:31 1999
@@ -1840,10 +1840,10 @@
       }
 
       if ((scb->scsi_cmd->request.cmd == READ) && (SC->request_bufflen))
-         scb->dcdb.cmd_attribute |= DATA_IN;
+         scb->dcdb.cmd_attribute |= IPS_DATA_IN;
 
       if ((scb->scsi_cmd->request.cmd == WRITE) && (SC->request_bufflen))
-         scb->dcdb.cmd_attribute |= DATA_OUT;
+         scb->dcdb.cmd_attribute |= IPS_DATA_OUT;
 
       if (scb->data_len >= IPS_MAX_XFER) {
          scb->dcdb.cmd_attribute |= TRANSFER_64K;
@@ -2274,10 +2274,10 @@
          }
 
          if ((scb->scsi_cmd->request.cmd == READ) && (scb->data_len))
-            scb->dcdb.cmd_attribute |= DATA_IN;
+            scb->dcdb.cmd_attribute |= IPS_DATA_IN;
 
          if ((scb->scsi_cmd->request.cmd == WRITE) && (scb->data_len))
-            scb->dcdb.cmd_attribute |= DATA_OUT;
+            scb->dcdb.cmd_attribute |= IPS_DATA_OUT;
 
          if (scb->data_len >= IPS_MAX_XFER) {
             scb->dcdb.cmd_attribute |= TRANSFER_64K;
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/ips.h linux/drivers/scsi/ips.h
--- v2.3.22/linux/drivers/scsi/ips.h	Mon Oct  4 15:49:29 1999
+++ linux/drivers/scsi/ips.h	Fri Oct 22 12:47:50 1999
@@ -237,8 +237,8 @@
    #define NO_DISCONNECT                0x00
    #define DISCONNECT_ALLOWED           0x80
    #define NO_AUTO_REQUEST_SENSE        0x40
-   #define DATA_IN                      0x01
-   #define DATA_OUT                     0x02
+   #define IPS_DATA_IN                  0x01
+   #define IPS_DATA_OUT                 0x02
    #define TRANSFER_64K                 0x08
    #define NOTIMEOUT                    0x00
    #define TIMEOUT10                    0x10
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.22/linux/drivers/scsi/st.c	Fri Sep 10 23:57:32 1999
+++ linux/drivers/scsi/st.c	Tue Oct 19 11:57:45 1999
@@ -11,7 +11,7 @@
    Copyright 1992 - 1999 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sat Aug  7 13:54:31 1999 by makisara@kai.makisara.local
+   Last modified: Tue Oct 19 21:39:15 1999 by makisara@kai.makisara.local
    Some small formal changes - aeb, 950809
  */
 
@@ -36,10 +36,17 @@
    is defined and non-zero. */
 #define DEBUG 0
 
+#if DEBUG
 /* The message level for the debug messages is currently set to KERN_NOTICE
    so that people can easily see the messages. Later when the debugging messages
    in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
 #define ST_DEB_MSG  KERN_NOTICE
+#define DEB(a) a
+#define DEBC(a) if (debugging) { a ; }
+#else
+#define DEB(a)
+#define DEBC(a)
+#endif
 
 #define MAJOR_NR SCSI_TAPE_MAJOR
 #include <linux/blk.h>
@@ -100,9 +107,7 @@
 #error "Buffer size should not exceed (2 << 24 - 1) bytes!"
 #endif
 
-#if DEBUG
-static int debugging = 1;
-#endif
+DEB( static int debugging = DEBUG; )
 
 #define MAX_RETRIES 0
 #define MAX_WRITE_RETRIES 0
@@ -164,9 +169,7 @@
 	int dev = TAPE_NR(SCpnt->request.rq_dev);
 	int result = SCpnt->result;
 	unsigned char *sense = SCpnt->sense_buffer, scode;
-#if DEBUG
-	const char *stp;
-#endif
+	DEB(const char *stp;)
 
 	if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
 		return 0;
@@ -178,35 +181,35 @@
 		scode = 0;
 	}
 
-#if DEBUG
-	if (debugging) {
-		printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+        DEB(
+        if (debugging) {
+                printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
 		       dev, result,
 		       SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
 		       SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
 		       SCpnt->request_bufflen);
 		if (driver_byte(result) & DRIVER_SENSE)
 			print_sense("st", SCpnt);
-	} else
-#endif
+	} else ) /* end DEB */
 		if (!(driver_byte(result) & DRIVER_SENSE) ||
 		    ((sense[0] & 0x70) == 0x70 &&
 		     scode != NO_SENSE &&
 		     scode != RECOVERED_ERROR &&
-/*       scode != UNIT_ATTENTION && */
+                     /* scode != UNIT_ATTENTION && */
 		     scode != BLANK_CHECK &&
 		     scode != VOLUME_OVERFLOW &&
 		     SCpnt->data_cmnd[0] != MODE_SENSE &&
-		     SCpnt->data_cmnd[0] != TEST_UNIT_READY)) {		/* Abnormal conditions for tape */
+		     SCpnt->data_cmnd[0] != TEST_UNIT_READY)) {	/* Abnormal conditions for tape */
 		if (driver_byte(result) & DRIVER_SENSE) {
 			printk(KERN_WARNING "st%d: Error with sense data: ", dev);
 			print_sense("st", SCpnt);
 		} else
 			printk(KERN_WARNING
 			       "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
-			       dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
-			       host_byte(result));
+			       dev, result, suggestion(result),
+                               driver_byte(result) & DRIVER_MASK, host_byte(result));
 	}
+
 	if ((sense[0] & 0x70) == 0x70 &&
 	    scode == RECOVERED_ERROR
 #if ST_RECOVERED_WRITE_FATAL
@@ -216,7 +219,8 @@
 	    ) {
 		scsi_tapes[dev].recover_count++;
 		scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
-#if DEBUG
+
+                DEB(
 		if (debugging) {
 			if (SCpnt->data_cmnd[0] == READ_6)
 				stp = "read";
@@ -226,8 +230,8 @@
 				stp = "ioctl";
 			printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,
 			       scsi_tapes[dev].recover_count);
-		}
-#endif
+		} ) /* end DEB */
+
 		if ((sense[2] & 0xe0) == 0)
 			return 0;
 	}
@@ -250,8 +254,9 @@
 			/* EOM at write-behind, has all been written? */
 			if ((SCpnt->sense_buffer[0] & 0x80) != 0)
 				remainder = (SCpnt->sense_buffer[3] << 24) |
-				    (SCpnt->sense_buffer[4] << 16) |
-				    (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+                                    (SCpnt->sense_buffer[4] << 16) |
+				    (SCpnt->sense_buffer[5] << 8) |
+                                    SCpnt->sense_buffer[6];
 			else
 				remainder = 0;
 			if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
@@ -263,16 +268,14 @@
 			(STp->buffer)->last_result = SCpnt->result;
 		SCpnt->request.rq_status = RQ_SCSI_DONE;
 		(STp->buffer)->last_SCpnt = SCpnt;
+		DEB( STp->write_pending = 0; )
 
-#if DEBUG
-		STp->write_pending = 0;
-#endif
 		up(SCpnt->request.sem);
 	}
-#if DEBUG
+        DEB(
 	else if (debugging)
 		printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr);
-#endif
+	) /* end DEB */
 }
 
 
@@ -289,10 +292,12 @@
 	spin_lock_irqsave(&io_request_lock, flags);
 	if (SCpnt == NULL)
 		if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
-			printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+			printk(KERN_ERR "st%d: Can't get SCSI request.\n",
+                               TAPE_NR(STp->devt));
 			spin_unlock_irqrestore(&io_request_lock, flags);
 			return NULL;
 		}
+
 	cmd[1] |= (SCpnt->lun << 5) & 0xe0;
 	init_MUTEX_LOCKED(&STp->sem);
 	SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
@@ -314,7 +319,6 @@
 
 	if (do_wait) {
 		down(SCpnt->request.sem);
-
 		(STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
 	}
 	return SCpnt;
@@ -329,12 +333,12 @@
 
 	STbuffer = STp->buffer;
 
-#if DEBUG
+        DEB(
 	if (STp->write_pending)
 		STp->nbr_waits++;
 	else
 		STp->nbr_finished++;
-#endif
+        ) /* end DEB */
 
 	down(&(STp->sem));
 
@@ -347,7 +351,8 @@
 		       STbuffer->b_data + STbuffer->writing,
 		       STbuffer->buffer_bytes - STbuffer->writing);
 #else
-		printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n");
+		printk(KERN_WARNING
+                       "st: write_behind_check: something left in buffer!\n");
 #endif
 	STbuffer->buffer_bytes -= STbuffer->writing;
 	STps = &(STp->ps[STp->partition]);
@@ -378,11 +383,9 @@
 	} else
 		cmd[2] = cmd[3] = cmd[4] = 0xff;	/* -1 filemarks */
 	cmd[5] = 0;
-#if DEBUG
-	if (debugging)
-		printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
-		   TAPE_NR(STp->devt), forward ? "forward" : "backward");
-#endif
+
+        DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
+		   TAPE_NR(STp->devt), forward ? "forward" : "backward"));
 
 	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
 	if (!SCpnt)
@@ -411,11 +414,9 @@
 	if ((STp->buffer)->writing) {
 		write_behind_check(STp);
 		if ((STp->buffer)->last_result_fatal) {
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n",
-				       TAPE_NR(STp->devt), (STp->buffer)->last_result);
-#endif
+                        DEBC(printk(ST_DEB_MSG
+                                       "st%d: Async write error (flush) %x.\n",
+				       TAPE_NR(STp->devt), (STp->buffer)->last_result))
 			if ((STp->buffer)->last_result == INT_MAX)
 				return (-ENOSPC);
 			return (-EIO);
@@ -430,10 +431,9 @@
 		offset = (STp->buffer)->buffer_bytes;
 		transfer = ((offset + STp->block_size - 1) /
 			    STp->block_size) * STp->block_size;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n",
+                               TAPE_NR(STp->devt), transfer));
+
 		memset((STp->buffer)->b_data + offset, 0, transfer - offset);
 
 		memset(cmd, 0, 10);
@@ -444,8 +444,8 @@
 		cmd[3] = blks >> 8;
 		cmd[4] = blks;
 
-		SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES,
-				   TRUE);
+		SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout,
+                                   MAX_WRITE_RETRIES, TRUE);
 		if (!SCpnt)
 			return (-EBUSY);
 
@@ -458,7 +458,8 @@
 				(STp->buffer)->buffer_bytes = 0;
 				result = (-ENOSPC);
 			} else {
-				printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt));
+				printk(KERN_ERR "st%d: Error on flush.\n",
+                                       TAPE_NR(STp->devt));
 				result = (-EIO);
 			}
 			STps->drv_block = (-1);
@@ -514,7 +515,7 @@
 	result = 0;
 	if (!seek_next) {
 		if (STps->eof == ST_FM_HIT) {
-			result = cross_eof(STp, FALSE);		/* Back over the EOF hit */
+			result = cross_eof(STp, FALSE);	/* Back over the EOF hit */
 			if (!result)
 				STps->eof = ST_NOEOF;
 			else {
@@ -590,19 +591,14 @@
 	}
 	STp = &(scsi_tapes[dev]);
 	if (STp->in_use) {
-#if DEBUG
-		printk(ST_DEB_MSG "st%d: Device already in use.\n", dev);
-#endif
+		DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
 		return (-EBUSY);
 	}
 	STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
 
 	if (mode != STp->current_mode) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
-			       dev, STp->current_mode, mode);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
+			       dev, STp->current_mode, mode));
 		new_session = TRUE;
 		STp->current_mode = mode;
 	}
@@ -646,9 +642,7 @@
 	}
 	STp->ready = ST_READY;
 	STp->recover_count = 0;
-#if DEBUG
-	STp->nbr_waits = STp->nbr_finished = 0;
-#endif
+	DEB( STp->nbr_waits = STp->nbr_finished = 0; )
 
 	if (scsi_tapes[dev].device->host->hostt->module)
 		__MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
@@ -667,18 +661,26 @@
 			__MOD_DEC_USE_COUNT(st_template.module);
 		return (-EBUSY);
 	}
+
 	if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 	    (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {	/* New media? */
-		memset((void *) &cmd[0], 0, 10);
-		cmd[0] = TEST_UNIT_READY;
 
-		SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
-				   TRUE);
+		/* Flush the queued UNIT ATTENTION sense data */
+		for (i=0; i < 10; i++) {
+                        memset((void *) &cmd[0], 0, 10);
+                        cmd[0] = TEST_UNIT_READY;
+                        SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout,
+                                           MAX_READY_RETRIES, TRUE);
+                        if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+                            (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+                                break;
+		}
 
 		(STp->device)->was_reset = 0;
 		STp->partition = STp->new_partition = 0;
 		if (STp->can_partitions)
-			STp->nbr_partitions = 1;	/* This guess will be updated later if necessary */
+			STp->nbr_partitions = 1; /* This guess will be updated later
+                                                    if necessary */
 		for (i = 0; i < ST_NBR_PARTITIONS; i++) {
 			STps = &(STp->ps[i]);
 			STps->rw = ST_IDLE;
@@ -690,6 +692,7 @@
 		}
 		new_session = TRUE;
 	}
+
 	if ((STp->buffer)->last_result_fatal != 0) {
 		if ((STp->device)->scsi_level >= SCSI_2 &&
 		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
@@ -709,30 +712,29 @@
 		STp->in_use = 1;
 		return 0;
 	}
+
 	if (STp->omit_blklims)
 		STp->min_block = STp->max_block = (-1);
 	else {
 		memset((void *) &cmd[0], 0, 10);
 		cmd[0] = READ_BLOCK_LIMITS;
 
-		SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE);
+		SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES,
+                                   TRUE);
 
 		if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
 			    ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
 			STp->min_block = ((STp->buffer)->b_data[4] << 8) |
 			    (STp->buffer)->b_data[5];
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
-				       STp->max_block);
-#endif
+			if ( DEB( debugging || ) !STp->inited)
+				printk(KERN_WARNING
+                                       "st%d: Block limits %d - %d bytes.\n", dev,
+                                       STp->min_block, STp->max_block);
 		} else {
 			STp->min_block = STp->max_block = (-1);
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev);
-#endif
+                        DEBC(printk(ST_DEB_MSG "st%d: Can't read block limits.\n",
+                                       dev));
 		}
 	}
 
@@ -743,40 +745,33 @@
 	SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
 
 	if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
 		STp->block_size = ST_DEFAULT_BLOCK;	/* Educated guess (?) */
 		(STp->buffer)->last_result_fatal = 0;	/* Prevent error propagation */
 		STp->drv_write_prot = 0;
 	} else {
-
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
-			       dev,
-			       (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
-			       (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]);
-#endif
+                DEBC(printk(ST_DEB_MSG
+                            "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
+                            dev,
+                            (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
+                            (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]));
 
 		if ((STp->buffer)->b_data[3] >= 8) {
 			STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
 			STp->density = (STp->buffer)->b_data[4];
 			STp->block_size = (STp->buffer)->b_data[9] * 65536 +
 			    (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n",
-				       dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
-				       (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
-				       STp->drv_buffer);
-#endif
+                        DEBC(printk(ST_DEB_MSG
+                                    "st%d: Density %x, tape length: %x, drv buffer: %d\n",
+                                    dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
+                                    (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
+                                    STp->drv_buffer));
 		}
+
 		if (STp->block_size > (STp->buffer)->buffer_size &&
 		    !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
-			printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
-			       STp->block_size);
+			printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n",
+                               dev, STp->block_size);
 			scsi_release_command(SCpnt);
 			(STp->buffer)->in_use = 0;
 			STp->buffer = NULL;
@@ -790,26 +785,25 @@
 	}
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
+        STp->inited = TRUE;
 
 	if (STp->block_size > 0)
-		(STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size;
+		(STp->buffer)->buffer_blocks =
+                        (STp->buffer)->buffer_size / STp->block_size;
 	else
 		(STp->buffer)->buffer_blocks = 1;
 	(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
 
-#if DEBUG
-	if (debugging)
-		printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
+        DEBC(printk(ST_DEB_MSG
+                       "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
 		       STp->block_size, (STp->buffer)->buffer_size,
-		       (STp->buffer)->buffer_blocks);
-#endif
+		       (STp->buffer)->buffer_blocks));
 
 	if (STp->drv_write_prot) {
 		STp->write_prot = 1;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Write protected\n", dev);
-#endif
+
+                DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev));
+
 		if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
 			(STp->buffer)->in_use = 0;
 			STp->buffer = NULL;
@@ -820,14 +814,13 @@
 			return (-EROFS);
 		}
 	}
+
 	if (STp->can_partitions && STp->nbr_partitions < 1) {
 		/* This code is reached when the device is opened for the first time
 		   after the driver has been initialized with tape in the drive and the
 		   partition support has been enabled. */
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG
+                            "st%d: Updating partition number in status.\n", dev));
 		if ((STp->partition = find_partition(inode)) < 0) {
 			(STp->buffer)->in_use = 0;
 			STp->buffer = NULL;
@@ -838,8 +831,9 @@
 			return STp->partition;
 		}
 		STp->new_partition = STp->partition;
-		STp->nbr_partitions = 1;	/* This guess will be updated when necessary */
+		STp->nbr_partitions = 1; /* This guess will be updated when necessary */
 	}
+
 	if (new_session) {	/* Change the drive parameters for the new mode */
 		STp->density_changed = STp->blksize_changed = FALSE;
 		STp->compression_changed = FALSE;
@@ -853,9 +847,11 @@
 				__MOD_DEC_USE_COUNT(st_template.module);
 			return i;
 		}
+
 		if (STp->default_drvbuffer != 0xff) {
 			if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
-				printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n",
+				printk(KERN_WARNING
+                                       "st%d: Can't set default drive buffering to %d.\n",
 				       dev, STp->default_drvbuffer);
 		}
 	}
@@ -889,24 +885,20 @@
 
 	if (STp->can_partitions &&
 	    (result = update_partition(inode)) < 0) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG
+                               "st%d: update_partition at close failed.\n", dev));
 		goto out;
 	}
+
 	if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
 
 		result = flush_write_buffer(STp);
 
-#if DEBUG
-		if (debugging) {
-			printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
-			       dev, (long) (filp->f_pos));
-			printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
-			       dev, STp->nbr_waits, STp->nbr_finished);
-		}
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
+                            dev, (long) (filp->f_pos));
+                     printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
+                            dev, STp->nbr_waits, STp->nbr_finished);
+		)
 
 		if (result == 0 || result == (-ENOSPC)) {
 
@@ -914,8 +906,8 @@
 			cmd[0] = WRITE_FILEMARKS;
 			cmd[4] = 1 + STp->two_fm;
 
-			SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES,
-					   TRUE);
+			SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout,
+                                           MAX_WRITE_RETRIES, TRUE);
 			if (!SCpnt)
 				goto out;
 
@@ -943,11 +935,9 @@
 				STps->eof = ST_FM;
 			}
 		}
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
-			       dev, cmd[4]);
-#endif
+
+                DEBC(printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
+                            dev, cmd[4]));
 	} else if (!STp->rew_at_close) {
 		STps = &(STp->ps[STp->partition]);
 		if (!STm->sysv || STps->rw != ST_READING) {
@@ -972,6 +962,7 @@
 			STps->eof = ST_FM;
 		}
 	}
+
       out:
 	if (STp->rew_at_close) {
 		result2 = st_int_ioctl(inode, MTREW, 1);
@@ -1001,6 +992,7 @@
 		normalize_buffer(STp->buffer);
 		(STp->buffer)->in_use = 0;
 	}
+
 	STp->in_use = 0;
 	if (scsi_tapes[dev].device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
@@ -1039,16 +1031,19 @@
 	if (!scsi_block_when_processing_errors(STp->device)) {
 		return -ENXIO;
 	}
+
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
 		return -ENXIO;
 	}
+
 	if (STp->ready != ST_READY) {
 		if (STp->ready == ST_NO_TAPE)
 			return (-ENOMEDIUM);
 		else
 			return (-EIO);
 	}
+
 	STm = &(STp->modes[STp->current_mode]);
 	if (!STm->defined)
 		return (-ENXIO);
@@ -1062,12 +1057,11 @@
 	if (STp->device->was_reset)
 		return (-EIO);
 
-#if DEBUG
+        DEB(
 	if (!STp->in_use) {
 		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
 		return (-EIO);
-	}
-#endif
+	} ) /* end DEB */
 
 	/* Write must be integral number of blocks */
 	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
@@ -1075,6 +1069,7 @@
 		       dev);
 		return (-EIO);
 	}
+
 	if (STp->can_partitions &&
 	    (retval = update_partition(inode)) < 0)
 		return retval;
@@ -1111,20 +1106,19 @@
 			}
 		}
 	}
+
 	if ((STp->buffer)->writing) {
 		write_behind_check(STp);
 		if ((STp->buffer)->last_result_fatal) {
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev,
-				       (STp->buffer)->last_result);
-#endif
+                        DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n",
+                                    dev, (STp->buffer)->last_result));
 			if ((STp->buffer)->last_result == INT_MAX)
 				STps->eof = ST_EOM_OK;
 			else
 				STps->eof = ST_EOM_ERROR;
 		}
 	}
+
 	if (STps->eof == ST_EOM_OK)
 		return (-ENOSPC);
 	else if (STps->eof == ST_EOM_ERROR)
@@ -1178,6 +1172,7 @@
 			}
 			return i;
 		}
+
 		if (STp->block_size == 0)
 			blks = transfer = do_count;
 		else {
@@ -1195,18 +1190,18 @@
 			return (-EBUSY);
 
 		if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Error on write:\n", dev);
-#endif
+                        DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev));
 			if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 			    (SCpnt->sense_buffer[2] & 0x40)) {
-				if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0)
+				if (STp->block_size != 0 &&
+                                    (SCpnt->sense_buffer[0] & 0x80) != 0)
 					transfer = (SCpnt->sense_buffer[3] << 24) |
 					    (SCpnt->sense_buffer[4] << 16) |
-					    (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+					    (SCpnt->sense_buffer[5] << 8) |
+                                                SCpnt->sense_buffer[6];
 				else if (STp->block_size == 0 &&
-					 (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
+					 (SCpnt->sense_buffer[2] & 0x0f) ==
+                                         VOLUME_OVERFLOW)
 					transfer = do_count;
 				else
 					transfer = 0;
@@ -1216,26 +1211,26 @@
 					filp->f_pos += do_count - transfer;
 					count -= do_count - transfer;
 					if (STps->drv_block >= 0) {
-						if (STp->block_size == 0 && transfer < do_count)
+						if (STp->block_size == 0 &&
+                                                    transfer < do_count)
 							STps->drv_block++;
 						else if (STp->block_size != 0)
-							STps->drv_block += (do_count - transfer) / STp->block_size;
+							STps->drv_block +=
+                                                                (do_count - transfer) /
+                                                                STp->block_size;
 					}
 					STps->eof = ST_EOM_OK;
-					retval = (-ENOSPC);	/* EOM within current request */
-#if DEBUG
-					if (debugging)
-						printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n",
-						       dev, transfer);
-#endif
+					retval = (-ENOSPC); /* EOM within current request */
+                                        DEBC(printk(ST_DEB_MSG
+                                                       "st%d: EOM with %d bytes unwritten.\n",
+						       dev, transfer));
 				} else {
 					STps->eof = ST_EOM_ERROR;
-					STps->drv_block = (-1);		/* Too cautious? */
+					STps->drv_block = (-1); /* Too cautious? */
 					retval = (-EIO);	/* EOM for old data */
-#if DEBUG
-					if (debugging)
-						printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev);
-#endif
+					DEBC(printk(ST_DEB_MSG
+                                                       "st%d: EOM with lost data.\n",
+                                                       dev));
 				}
 			} else {
 				STps->drv_block = (-1);		/* Too cautious? */
@@ -1276,11 +1271,13 @@
 		filp->f_pos += count;
 		count = 0;
 	}
+
 	if (doing_write && (STp->buffer)->last_result_fatal != 0) {
 		scsi_release_command(SCpnt);
 		SCpnt = NULL;
 		return (STp->buffer)->last_result_fatal;
 	}
+
 	if (STm->do_async_writes &&
 	    (((STp->buffer)->buffer_bytes >= STp->write_threshold &&
 	      (STp->buffer)->buffer_bytes >= STp->block_size) ||
@@ -1301,9 +1298,7 @@
 		cmd[2] = blks >> 16;
 		cmd[3] = blks >> 8;
 		cmd[4] = blks;
-#if DEBUG
-		STp->write_pending = 1;
-#endif
+		DEB( STp->write_pending = 1; )
 
 		SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
 				   MAX_WRITE_RETRIES, FALSE);
@@ -1376,21 +1371,18 @@
 	/* Something to check */
 	if ((STp->buffer)->last_result_fatal) {
 		retval = 1;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
-			       dev,
-			  SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
-			  SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
-			  SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
-			 SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]);
-#endif
+		DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+                            dev,
+                            SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
+                            SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
+                            SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
+                            SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]));
 		if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) {	/* extended sense */
 
 			if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
-				SCpnt->sense_buffer[2] &= 0xcf;		/* No need for EOM in this case */
+				SCpnt->sense_buffer[2] &= 0xcf;	/* No need for EOM in this case */
 
-			if ((SCpnt->sense_buffer[2] & 0xe0) != 0) {	/* EOF, EOM, or ILI */
+			if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
 				/* Compute the residual count */
 				if ((SCpnt->sense_buffer[0] & 0x80) != 0)
 					transfer = (SCpnt->sense_buffer[3] << 24) |
@@ -1410,7 +1402,7 @@
 					} else {
 						scsi_release_command(SCpnt);
 						SCpnt = *aSCpnt = NULL;
-						if (transfer == blks) {		/* We did not get anything, error */
+						if (transfer == blks) {	/* We did not get anything, error */
 							printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
 							if (STps->drv_block >= 0)
 								STps->drv_block += blks - transfer + 1;
@@ -1420,12 +1412,9 @@
 						/* We have some data, deliver it */
 						(STp->buffer)->buffer_bytes = (blks - transfer) *
 						    STp->block_size;
-#if DEBUG
-						if (debugging)
-							printk(ST_DEB_MSG
-							       "st%d: ILI but enough data received %ld %d.\n",
-							       dev, count, (STp->buffer)->buffer_bytes);
-#endif
+                                                DEBC(printk(ST_DEB_MSG
+                                                            "st%d: ILI but enough data received %ld %d.\n",
+                                                            dev, count, (STp->buffer)->buffer_bytes));
 						if (STps->drv_block >= 0)
 							STps->drv_block += 1;
 						if (st_int_ioctl(inode, MTBSR, 1))
@@ -1441,12 +1430,9 @@
 					else
 						(STp->buffer)->buffer_bytes =
 						    bytes - transfer * STp->block_size;
-#if DEBUG
-					if (debugging)
-						printk(ST_DEB_MSG
-						       "st%d: EOF detected (%d bytes read).\n",
-						       dev, (STp->buffer)->buffer_bytes);
-#endif
+                                        DEBC(printk(ST_DEB_MSG
+                                                    "st%d: EOF detected (%d bytes read).\n",
+                                                    dev, (STp->buffer)->buffer_bytes));
 				} else if (SCpnt->sense_buffer[2] & 0x40) {
 					if (STps->eof == ST_FM)
 						STps->eof = ST_EOD_1;
@@ -1457,28 +1443,21 @@
 					else
 						(STp->buffer)->buffer_bytes =
 						    bytes - transfer * STp->block_size;
-#if DEBUG
-					if (debugging)
-						printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n",
-						       dev, (STp->buffer)->buffer_bytes);
-#endif
+
+                                        DEBC(printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n",
+                                                    dev, (STp->buffer)->buffer_bytes));
 				}
 			}
 			/* end of EOF, EOM, ILI test */ 
 			else {	/* nonzero sense key */
-#if DEBUG
-				if (debugging)
-					printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev);
-#endif
+                                DEBC(printk(ST_DEB_MSG
+                                            "st%d: Tape error while reading.\n", dev));
 				STps->drv_block = (-1);
 				if (STps->eof == ST_FM &&
 				    (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
-#if DEBUG
-					if (debugging)
-						printk(ST_DEB_MSG
-						       "st%d: Zero returned for first BLANK CHECK after EOF.\n",
-						       dev);
-#endif
+                                        DEBC(printk(ST_DEB_MSG
+                                                    "st%d: Zero returned for first BLANK CHECK after EOF.\n",
+                                                    dev));
 					STps->eof = ST_EOD_2;	/* First BLANK_CHECK after FM */
 				} else	/* Some other extended sense code */
 					retval = (-EIO);
@@ -1529,10 +1508,12 @@
 	if (!scsi_block_when_processing_errors(STp->device)) {
 		return -ENXIO;
 	}
+
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
 		return -ENXIO;
 	}
+
 	if (STp->ready != ST_READY) {
 		if (STp->ready == ST_NO_TAPE)
 			return (-ENOMEDIUM);
@@ -1542,12 +1523,11 @@
 	STm = &(STp->modes[STp->current_mode]);
 	if (!STm->defined)
 		return (-ENXIO);
-#if DEBUG
+        DEB(
 	if (!STp->in_use) {
 		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
 		return (-EIO);
-	}
-#endif
+	} ) /* end DEB */
 
 	if (STp->can_partitions &&
 	    (total = update_partition(inode)) < 0)
@@ -1573,11 +1553,12 @@
 			return transfer;
 		STps->rw = ST_READING;
 	}
-#if DEBUG
+        DEB(
 	if (debugging && STps->eof != ST_NOEOF)
 		printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev,
 		       STps->eof, (STp->buffer)->buffer_bytes);
-#endif
+        ) /* end DEB */
+
 	if ((STp->buffer)->buffer_bytes == 0 &&
 	    STps->eof >= ST_EOD_1) {
 		if (STps->eof < ST_EOD) {
@@ -1586,6 +1567,7 @@
 		}
 		return (-EIO);	/* EOM or Blank Check */
 	}
+
 	/* Check the buffer writability before any tape movement. Don't alter
 	   buffer data. */
 	if (copy_from_user(&i, buf, 1) != 0 ||
@@ -1610,13 +1592,16 @@
 				return special;
 			}
 		}
+
 		/* Move the data from driver buffer to user buffer */
 		if ((STp->buffer)->buffer_bytes > 0) {
-#if DEBUG
+                        DEB(
 			if (debugging && STps->eof != ST_NOEOF)
-				printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev,
-				       STps->eof, (STp->buffer)->buffer_bytes, count - total);
-#endif
+				printk(ST_DEB_MSG
+                                       "st%d: EOF up (%d). Left %d, needed %d.\n", dev,
+				       STps->eof, (STp->buffer)->buffer_bytes,
+                                       count - total);
+                        ) /* end DEB */
 			transfer = (STp->buffer)->buffer_bytes < count - total ?
 			    (STp->buffer)->buffer_bytes : count - total;
 			i = from_buffer(STp->buffer, buf, transfer);
@@ -1631,15 +1616,18 @@
 			buf += transfer;
 			total += transfer;
 		}
+
 		if (STp->block_size == 0)
 			break;	/* Read only one variable length block */
 
-	}			/* for (total = 0, special = 0; total < count && !special; ) */
+	}			/* for (total = 0, special = 0;
+                                   total < count && !special; ) */
 
 	if (SCpnt != NULL) {
 		scsi_release_command(SCpnt);
 		SCpnt = NULL;
 	}
+
 	/* Change the eof state if no data from tape or buffer */
 	if (total == 0) {
 		if (STps->eof == ST_FM_HIT) {
@@ -1678,11 +1666,9 @@
 	       STp->scsi2_logical);
 	printk(KERN_INFO
 	       "st%d:    sysv: %d\n", dev, STm->sysv);
-#if DEBUG
-	printk(KERN_INFO
-	       "st%d:    debugging: %d\n",
-	       dev, debugging);
-#endif
+        DEB(printk(KERN_INFO
+                   "st%d:    debugging: %d\n",
+                   dev, debugging);)
 }
 
 
@@ -1699,12 +1685,11 @@
 	if (!STm->defined) {
 		memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
 		modes_defined = TRUE;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n",
-			       dev, STp->current_mode);
-#endif
+                DEBC(printk(ST_DEB_MSG
+                            "st%d: Initialized mode %d definition from mode 0\n",
+                            dev, STp->current_mode));
 	}
+
 	code = options & MT_ST_OPTIONS;
 	if (code == MT_ST_BOOLEANS) {
 		STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
@@ -1720,9 +1705,7 @@
 			STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
 		STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
 		STm->sysv = (options & MT_ST_SYSV) != 0;
-#if DEBUG
-		debugging = (options & MT_ST_DEBUGGING) != 0;
-#endif
+		DEB( debugging = (options & MT_ST_DEBUGGING) != 0; )
 		st_log_options(STp, STm, dev);
 	} else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
 		value = (code == MT_ST_SETBOOLEANS);
@@ -1751,15 +1734,15 @@
 			STp->scsi2_logical = value;
 		if ((options & MT_ST_SYSV) != 0)
 			STm->sysv = value;
-#if DEBUG
+                DEB(
 		if ((options & MT_ST_DEBUGGING) != 0)
-			debugging = value;
-#endif
+			debugging = value; )
 		st_log_options(STp, STm, dev);
 	} else if (code == MT_ST_WRITE_THRESHOLD) {
 		value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
 		if (value < 1 || value > st_buffer_size) {
-			printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n",
+			printk(KERN_WARNING
+                               "st%d: Write threshold %d too small or too large.\n",
 			       dev, value);
 			return (-EIO);
 		}
@@ -1784,8 +1767,8 @@
 			       (value & ~MT_ST_SET_LONG_TIMEOUT));
 		} else {
 			STp->timeout = value * HZ;
-			printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev,
-			       value);
+			printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n",
+                               dev, value);
 		}
 	} else if (code == MT_ST_DEF_OPTIONS) {
 		code = (options & ~MT_ST_CLEAR_DEFAULT);
@@ -1793,7 +1776,8 @@
 		if (code == MT_ST_DEF_DENSITY) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
 				STm->default_density = (-1);
-				printk(KERN_INFO "st%d: Density default disabled.\n", dev);
+				printk(KERN_INFO "st%d: Density default disabled.\n",
+                                       dev);
 			} else {
 				STm->default_density = value & 0xff;
 				printk(KERN_INFO "st%d: Density default set to %x\n",
@@ -1802,16 +1786,19 @@
 		} else if (code == MT_ST_DEF_DRVBUFFER) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
 				STp->default_drvbuffer = 0xff;
-				printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev);
+				printk(KERN_INFO
+                                       "st%d: Drive buffer default disabled.\n", dev);
 			} else {
 				STp->default_drvbuffer = value & 7;
-				printk(KERN_INFO "st%d: Drive buffer default set to %x\n",
+				printk(KERN_INFO
+                                       "st%d: Drive buffer default set to %x\n",
 				       dev, STp->default_drvbuffer);
 			}
 		} else if (code == MT_ST_DEF_COMPRESSION) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
 				STm->default_compression = ST_DONT_TOUCH;
-				printk(KERN_INFO "st%d: Compression default disabled.\n", dev);
+				printk(KERN_INFO
+                                       "st%d: Compression default disabled.\n", dev);
 			} else {
 				STm->default_compression = (value & 1 ? ST_YES : ST_NO);
 				printk(KERN_INFO "st%d: Compression default set to %x\n",
@@ -1858,30 +1845,23 @@
 	dev = TAPE_NR(SCpnt->request.rq_dev);
 
 	if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n",
+                            dev));
 		scsi_release_command(SCpnt);
 		SCpnt = NULL;
 		return (-EIO);
 	}
-#if DEBUG
-	if (debugging)
-		printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
-		       ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0));
-#endif
+        DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
+                    ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0)));
 
 	/* Check if compression can be changed */
 	if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
 		scsi_release_command(SCpnt);
 		SCpnt = NULL;
 		return (-EIO);
 	}
+
 	/* Do the change */
 	if (state)
 		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK;
@@ -1899,19 +1879,13 @@
 	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
 
 	if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
 		scsi_release_command(SCpnt);
 		SCpnt = NULL;
 		return (-EIO);
 	}
-#if DEBUG
-	if (debugging)
-		printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
-		       dev, state);
-#endif
+        DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
+		       dev, state));
 
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
@@ -1959,11 +1933,8 @@
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n",
-			    dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n",
+			    dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
 		if (fileno >= 0)
 			fileno += arg;
 		blkno = 0;
@@ -1978,15 +1949,14 @@
 		cmd[2] = (ltmp >> 16);
 		cmd[3] = (ltmp >> 8);
 		cmd[4] = ltmp;
-#if DEBUG
-		if (debugging) {
-			if (cmd[2] & 0x80)
-				ltmp = 0xff000000;
-			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-			printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n",
-			       dev, (-ltmp));
-		}
-#endif
+                DEBC(
+                     if (cmd[2] & 0x80)
+                     	ltmp = 0xff000000;
+                     ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+                     printk(ST_DEB_MSG
+                            "st%d: Spacing tape backward over %ld filemarks.\n",
+                            dev, (-ltmp));
+		)
 		if (fileno >= 0)
 			fileno -= arg;
 		blkno = (-1);	/* We can't know the block number */
@@ -1998,11 +1968,8 @@
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev,
-			       cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev,
+			       cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
 		if (blkno >= 0)
 			blkno += arg;
 		at_sm &= (arg == 0);
@@ -2014,14 +1981,13 @@
 		cmd[2] = (ltmp >> 16);
 		cmd[3] = (ltmp >> 8);
 		cmd[4] = ltmp;
-#if DEBUG
-		if (debugging) {
-			if (cmd[2] & 0x80)
-				ltmp = 0xff000000;
-			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-			printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
-		}
-#endif
+                DEBC(
+                     if (cmd[2] & 0x80)
+                          ltmp = 0xff000000;
+                     ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+                     printk(ST_DEB_MSG
+                            "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
+		)
 		if (blkno >= 0)
 			blkno -= arg;
 		at_sm &= (arg == 0);
@@ -2032,11 +1998,8 @@
 		cmd[2] = (arg >> 16);
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev,
-			       cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev,
+                            cmd[2] * 65536 + cmd[3] * 256 + cmd[4]));
 		if (arg != 0) {
 			blkno = fileno = (-1);
 			at_sm = 1;
@@ -2049,15 +2012,13 @@
 		cmd[2] = (ltmp >> 16);
 		cmd[3] = (ltmp >> 8);
 		cmd[4] = ltmp;
-#if DEBUG
-		if (debugging) {
-			if (cmd[2] & 0x80)
+                DEBC(
+                     if (cmd[2] & 0x80)
 				ltmp = 0xff000000;
-			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-			printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n",
-			       dev, (-ltmp));
-		}
-#endif
+                     ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+                     printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n",
+                            dev, (-ltmp));
+		)
 		if (arg != 0) {
 			blkno = fileno = (-1);
 			at_sm = 1;
@@ -2074,16 +2035,14 @@
 		cmd[3] = (arg >> 8);
 		cmd[4] = arg;
 		timeout = STp->timeout;
-#if DEBUG
-		if (debugging) {
-			if (cmd_in == MTWEOF)
-				printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev,
+                DEBC(
+                     if (cmd_in == MTWEOF)
+                               printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev,
 				 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-			else
+                     else
 				printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev,
 				 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-		}
-#endif
+		)
 		if (fileno >= 0)
 			fileno += arg;
 		blkno = 0;
@@ -2095,10 +2054,7 @@
 		cmd[1] = 1;	/* Don't wait for completion */
 		timeout = STp->timeout;
 #endif
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev));
 		fileno = blkno = at_sm = 0;
 		break;
 	case MTOFFL:
@@ -2113,14 +2069,10 @@
 		if (cmd_in != MTOFFL &&
 		    arg >= 1 + MT_ST_HPLOADER_OFFSET
 		    && arg <= 6 + MT_ST_HPLOADER_OFFSET) {
-#if DEBUG
-			if (debugging) {
-				printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
-				       dev, (cmd[4]) ? "" : "un",
-				       arg - MT_ST_HPLOADER_OFFSET);
-			}
-#endif
-			cmd[3] = arg - MT_ST_HPLOADER_OFFSET;	/* MediaID field of C1553A */
+                        DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+                                    dev, (cmd[4]) ? "" : "un",
+                                    arg - MT_ST_HPLOADER_OFFSET));
+			cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
 		}
 #if ST_NOWAIT
 		cmd[1] = 1;	/* Don't wait for completion */
@@ -2128,21 +2080,16 @@
 #else
 		timeout = STp->long_timeout;
 #endif
-#if DEBUG
-		if (debugging) {
+                DEBC(
 			if (cmd_in != MTLOAD)
 				printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
 			else
 				printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
-		}
-#endif
+		)
 		fileno = blkno = at_sm = 0;
 		break;
 	case MTNOP:
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: No op on tape.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: No op on tape.\n", dev));
 		return 0;	/* Should do something ? */
 		break;
 	case MTRETEN:
@@ -2152,10 +2099,7 @@
 		timeout = STp->timeout;
 #endif
 		cmd[4] = 3;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev));
 		fileno = blkno = at_sm = 0;
 		break;
 	case MTEOM:
@@ -2173,10 +2117,8 @@
 			fileno = (-1);
 		cmd[0] = SPACE;
 		cmd[1] = 3;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n",
+                            dev));
 		blkno = 0;
 		at_sm = 0;
 		break;
@@ -2191,29 +2133,20 @@
 #else
 		timeout = STp->long_timeout * 8;
 #endif
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev));
 		fileno = blkno = at_sm = 0;
 		break;
 	case MTLOCK:
 		chg_eof = FALSE;
 		cmd[0] = ALLOW_MEDIUM_REMOVAL;
 		cmd[4] = SCSI_REMOVAL_PREVENT;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev);
-#endif	/* ; */
+                DEBC(printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev));
 		break;
 	case MTUNLOCK:
 		chg_eof = FALSE;
 		cmd[0] = ALLOW_MEDIUM_REMOVAL;
 		cmd[4] = SCSI_REMOVAL_ALLOW;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev);
-#endif	/* ; */
+                DEBC(printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev));
 		break;
 	case MTSETBLK:		/* Set block length */
 	case MTSETDENSITY:	/* Set tape density */
@@ -2250,28 +2183,29 @@
 		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
 			ltmp = arg & MT_ST_BLKSIZE_MASK;
 			if (cmd_in == MTSETBLK)
-				STp->blksize_changed = TRUE;	/* At least we tried ;-) */
+				STp->blksize_changed = TRUE; /* At least we tried ;-) */
 		} else
 			ltmp = STp->block_size;
 		(STp->buffer)->b_data[9] = (ltmp >> 16);
 		(STp->buffer)->b_data[10] = (ltmp >> 8);
 		(STp->buffer)->b_data[11] = ltmp;
 		timeout = STp->timeout;
-#if DEBUG
-		if (debugging) {
+                DEBC(
 			if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
-				printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev,
+				printk(ST_DEB_MSG
+                                       "st%d: Setting block size to %d bytes.\n", dev,
 				       (STp->buffer)->b_data[9] * 65536 +
 				       (STp->buffer)->b_data[10] * 256 +
 				       (STp->buffer)->b_data[11]);
 			if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
-				printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev,
+				printk(ST_DEB_MSG
+                                       "st%d: Setting density code to %x.\n", dev,
 				       (STp->buffer)->b_data[4]);
 			if (cmd_in == MTSETDRVBUFFER)
-				printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev,
+				printk(ST_DEB_MSG
+                                       "st%d: Setting drive buffer code to %d.\n", dev,
 				    ((STp->buffer)->b_data[2] >> 4) & 7);
-		}
-#endif
+		)
 		break;
 	default:
 		return (-ENOSYS);
@@ -2331,8 +2265,8 @@
 			}
 			STp->partition = 0;
 		}
-	} else {		/* SCSI command was not completely successful. Don't return
-				   from this block without releasing the SCSI command block! */
+	} else { /* SCSI command was not completely successful. Don't return
+                    from this block without releasing the SCSI command block! */
 
 		if (SCpnt->sense_buffer[2] & 0x40) {
 			if (cmd_in != MTBSF && cmd_in != MTBSFM &&
@@ -2340,6 +2274,7 @@
 				STps->eof = ST_EOM_OK;
 			STps->drv_block = 0;
 		}
+
 		undone = (
 				 (SCpnt->sense_buffer[3] << 24) +
 				 (SCpnt->sense_buffer[4] << 16) +
@@ -2446,10 +2381,7 @@
 	    (STp->device->scsi_level >= SCSI_2 &&
 	     ((STp->buffer)->b_data[0] & 4) != 0)) {
 		*block = *partition = 0;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev));
 		result = (-EIO);
 	} else {
 		result = 0;
@@ -2468,12 +2400,8 @@
 			    (STp->buffer)->b_data[1] == 0)	/* BOP of partition 0 */
 				STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
 		}
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
-			       *block, *partition);
-#endif
-
+                DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
+                            *block, *partition));
 	}
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
@@ -2502,13 +2430,10 @@
 	timeout = STp->long_timeout;
 	STps = &(STp->ps[STp->partition]);
 
-#if DEBUG
-	if (debugging)
-		printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n",
-		       dev, block, partition);
-	if (partition < 0)
-		return (-EIO);
-#endif
+        DEBC(printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n",
+                    dev, block, partition));
+	DEB(if (partition < 0)
+		return (-EIO); )
 
 	/* Update the location at the partition we are leaving */
 	if ((!STp->can_partitions && partition != 0) ||
@@ -2520,13 +2445,12 @@
 		else {
 			STps->last_block_valid = TRUE;
 			STps->last_block_visited = blk;
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n",
-				       dev, blk, STp->partition);
-#endif
+                        DEBC(printk(ST_DEB_MSG
+                                    "st%d: Visited block %d for partition %d saved.\n",
+                                    dev, blk, STp->partition));
 		}
 	}
+
 	memset(scmd, 0, 10);
 	if ((STp->device)->scsi_level < SCSI_2) {
 		scmd[0] = QFA_SEEK_BLOCK;
@@ -2545,11 +2469,9 @@
 		if (STp->partition != partition) {
 			scmd[1] |= 2;
 			scmd[8] = partition;
-#if DEBUG
-			if (debugging)
-				printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n",
-				       dev, STp->partition, partition);
-#endif
+                        DEBC(printk(ST_DEB_MSG
+                                    "st%d: Trying to change partition from %d to %d\n",
+                                    dev, STp->partition, partition));
 		}
 	}
 #if ST_NOWAIT
@@ -2655,17 +2577,12 @@
 	SCpnt = NULL;
 
 	if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n",
+                            dev));
 		result = (-EIO);
 	} else {
 		result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result));
 	}
 
 	return result;
@@ -2691,20 +2608,16 @@
 	if (size <= 0) {
 		length = 8;
 		bp[MODE_HEADER_LENGTH + 3] = 0;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev);
-#endif
+                DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n",
+                            dev));
 	} else {
 		length = 10;
 		bp[MODE_HEADER_LENGTH + 3] = 1;
 		bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff;
 		bp[MODE_HEADER_LENGTH + 9] = size & 0xff;
-#if DEBUG
-		if (debugging)
-			printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n",
-			       dev, size);
-#endif
+                DEBC(printk(ST_DEB_MSG
+                            "st%d: Formatting tape with two partition (1 = %d MB).\n",
+                            dev, size));
 	}
 	bp[MODE_HEADER_LENGTH + 6] = 0;
 	bp[MODE_HEADER_LENGTH + 7] = 0;
@@ -2752,12 +2665,12 @@
 	int dev = TAPE_NR(inode->i_rdev);
 
 	STp = &(scsi_tapes[dev]);
-#if DEBUG
+        DEB(
 	if (debugging && !STp->in_use) {
 		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
 		return (-EIO);
-	}
-#endif
+	} ) /* end DEB */
+
 	STm = &(STp->modes[STp->current_mode]);
 	STps = &(STp->ps[STp->partition]);
 
@@ -2782,7 +2695,8 @@
 			return (-EFAULT);
 
 		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
-			printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
+			printk(KERN_WARNING
+                               "st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
 			return (-EPERM);
 		}
 		if (!STm->defined &&
@@ -2792,7 +2706,8 @@
 		if (!(STp->device)->was_reset) {
 
 			if (STps->eof == ST_FM_HIT) {
-				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || mtc.mt_op == MTEOM) {
+				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
+                                    mtc.mt_op == MTEOM) {
 					mtc.mt_count -= 1;
 					if (STps->drv_file >= 0)
 						STps->drv_file += 1;
@@ -2802,8 +2717,10 @@
 						STps->drv_file += 1;
 				}
 			}
+
 			if (mtc.mt_op == MTSEEK) {
-				/* Old position must be restored if partition will be changed */
+				/* Old position must be restored if partition will be
+                                   changed */
 				i = !STp->can_partitions ||
 				    (STp->new_partition != STp->partition);
 			} else {
@@ -2832,7 +2749,8 @@
 			if (STp->door_locked != ST_UNLOCKED &&
 			    STp->door_locked != ST_LOCK_FAILS) {
 				if (st_int_ioctl(inode, MTLOCK, 0)) {
-					printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n",
+					printk(KERN_NOTICE
+                                               "st%d: Could not relock door after bus reset.\n",
 					       dev);
 					STp->door_locked = ST_UNLOCKED;
 				}
@@ -2850,6 +2768,7 @@
 		if (mtc.mt_op == MTSETDRVBUFFER &&
 		    (mtc.mt_count & MT_ST_OPTIONS) != 0)
 			return st_set_options(inode, mtc.mt_count);
+
 		if (mtc.mt_op == MTSETPART) {
 			if (!STp->can_partitions ||
 			    mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
@@ -2862,6 +2781,7 @@
 			STp->new_partition = mtc.mt_count;
 			return 0;
 		}
+
 		if (mtc.mt_op == MTMKPART) {
 			if (!STp->can_partitions)
 				return (-EINVAL);
@@ -2878,15 +2798,18 @@
 			STps->drv_block = STps->drv_file = 0;
 			return 0;
 		}
+
 		if (mtc.mt_op == MTSEEK) {
 			i = set_location(inode, mtc.mt_count, STp->new_partition, 0);
 			if (!STp->can_partitions)
 				STp->ps[0].rw = ST_IDLE;
 			return i;
 		}
+
 		if (STp->can_partitions && STp->ready == ST_READY &&
 		    (i = update_partition(inode)) < 0)
 			return i;
+
 		if (mtc.mt_op == MTCOMPRESSION)
 			return st_compression(STp, (mtc.mt_count & 1));
 		else
@@ -2916,9 +2839,11 @@
 				(STp->mt_status)->mt_blkno +=
 				    (STp->buffer)->buffer_bytes / STp->block_size;
 			else if (STps->rw == ST_READING)
-				(STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes +
-				  STp->block_size - 1) / STp->block_size;
+				(STp->mt_status)->mt_blkno -=
+                                        ((STp->buffer)->buffer_bytes +
+                                         STp->block_size - 1) / STp->block_size;
 		}
+
 		(STp->mt_status)->mt_gstat = 0;
 		if (STp->drv_write_prot)
 			(STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
@@ -2945,7 +2870,8 @@
 			(STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
 		if (STps->at_sm)
 			(STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
-		if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
+		if (STm->do_async_writes ||
+                    (STm->do_buffer_writes && STp->block_size != 0) ||
 		    STp->drv_buffer != 0)
 			(STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff);
 
@@ -3014,7 +2940,8 @@
 		} else {	/* Got something, continue */
 
 			for (b_size = PAGE_SIZE;
-			     st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;)
+			     st_buffer_size >
+                                     tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;)
 				b_size *= 2;
 
 			for (segs = 1, got = tb->sg[0].length;
@@ -3024,11 +2951,13 @@
 				if (tb->sg[segs].address == NULL) {
 					if (st_buffer_size - got <=
 					    (ST_FIRST_SG - segs) * b_size / 2) {
-						b_size /= 2;	/* Large enough for the rest of the buffers */
+						b_size /= 2; /* Large enough for the
+                                                                rest of the buffers */
 						continue;
 					}
 					for (i = 0; i < segs - 1; i++)
-						scsi_init_free(tb->sg[i].address, tb->sg[i].length);
+						scsi_init_free(tb->sg[i].address,
+                                                               tb->sg[i].length);
 					scsi_init_free((char *) tb, tb->this_size);
 					tb = NULL;
 					break;
@@ -3040,6 +2969,7 @@
 			}
 		}
 	}
+
 	if (!tb) {
 		printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n",
 		       st_nbr_buffers);
@@ -3048,16 +2978,13 @@
 	tb->sg_segs = tb->orig_sg_segs = segs;
 	tb->b_data = tb->sg[0].address;
 
-#if DEBUG
-	if (debugging) {
-		printk(ST_DEB_MSG
-		       "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
-		 st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
-		printk(ST_DEB_MSG
-		       "st: segment sizes: first %d, last %d bytes.\n",
-		       tb->sg[0].length, tb->sg[segs - 1].length);
-	}
-#endif
+        DEBC(printk(ST_DEB_MSG
+                    "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
+                    st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
+             printk(ST_DEB_MSG
+                    "st: segment sizes: first %d, last %d bytes.\n",
+                    tb->sg[0].length, tb->sg[segs - 1].length);
+	)
 	tb->in_use = 0;
 	tb->dma = need_dma;
 	tb->buffer_size = got;
@@ -3094,7 +3021,7 @@
 		    (unsigned char *) scsi_init_malloc(b_size, priority);
 		if (STbuffer->sg[segs].address == NULL) {
 			if (new_size - got <= (max_segs - segs) * b_size / 2) {
-				b_size /= 2;	/* Large enough for the rest of the buffers */
+				b_size /= 2; /* Large enough for the rest of the buffers */
 				continue;
 			}
 			printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n",
@@ -3109,12 +3036,9 @@
 		STbuffer->buffer_size = got;
 		segs++;
 	}
-#if DEBUG
-	if (debugging)
-		printk(ST_DEB_MSG
-		       "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n",
-		 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size);
-#endif
+        DEBC(printk(ST_DEB_MSG
+                    "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n",
+                    got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size));
 
 	return TRUE;
 }
@@ -3129,11 +3053,11 @@
 		scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length);
 		STbuffer->buffer_size -= STbuffer->sg[i].length;
 	}
-#if DEBUG
+        DEB(
 	if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
 		printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n",
 		       STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
-#endif
+        ) /* end DEB */
 	STbuffer->sg_segs = STbuffer->orig_sg_segs;
 }
 
@@ -3244,7 +3168,8 @@
 				len = strlen(parms[i].name);
 				if (!strncmp(stp, parms[i].name, len) &&
 				    (*(stp + len) == ':' || *(stp + len) == '=')) {
-					*parms[i].val = simple_strtoul(stp + len + 1, NULL, 0);
+					*parms[i].val =
+                                                simple_strtoul(stp + len + 1, NULL, 0);
 					break;
 				}
 			}
@@ -3296,6 +3221,7 @@
 		SDp->attached--;
 		return 1;
 	}
+
 	for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
 		if (!tpnt->device)
 			break;
@@ -3309,6 +3235,7 @@
 	else
 		scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
 
+        tpnt->inited = 0;
 	tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
 	tpnt->dirty = 0;
 	tpnt->in_use = 0;
@@ -3392,7 +3319,8 @@
 
 	if (!st_registered) {
 		if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
-			printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
+			printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
+                               MAJOR_NR);
 			return 1;
 		}
 		st_registered++;
@@ -3412,10 +3340,9 @@
 		unregister_chrdev(SCSI_TAPE_MAJOR, "st");
 		return 1;
 	}
-#if DEBUG
-	printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
-	       st_buffer_size, st_write_threshold);
-#endif
+
+        DEB(printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
+                   st_buffer_size, st_write_threshold));
 
 	memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape));
 	for (i = 0; i < st_template.dev_max; ++i) {
@@ -3447,7 +3374,8 @@
 	for (i = st_nbr_buffers = 0; i < target_nbr; i++) {
 		if (!new_tape_buffer(TRUE, TRUE)) {
 			if (i == 0) {
-				printk(KERN_INFO "No tape buffers allocated at initialization.\n");
+				printk(KERN_INFO
+                                       "No tape buffers allocated at initialization.\n");
 				break;
 			}
 			printk(KERN_INFO "Number of tape buffers adjusted.\n");
@@ -3509,10 +3437,12 @@
 					for (j = 0; j < st_buffers[i]->sg_segs; j++)
 						scsi_init_free((char *) st_buffers[i]->sg[j].address,
 							       st_buffers[i]->sg[j].length);
-					scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size);
+					scsi_init_free((char *) st_buffers[i],
+                                                       st_buffers[i]->this_size);
 				}
 			}	
-			scsi_init_free((char *) st_buffers, st_template.dev_max * sizeof(ST_buffer *));
+			scsi_init_free((char *) st_buffers,
+                                       st_template.dev_max * sizeof(ST_buffer *));
 		}
 	}
 	st_template.dev_max = 0;
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.3.22/linux/drivers/scsi/st.h	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/st.h	Tue Oct 19 11:57:45 1999
@@ -104,6 +104,7 @@
 	unsigned char density;
 	unsigned char door_locked;
 	unsigned char rew_at_close;
+	unsigned char inited;
 	int block_size;
 	int min_block;
 	int max_block;
diff -u --recursive --new-file v2.3.22/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.3.22/linux/drivers/scsi/u14-34f.h	Mon Oct  4 15:49:30 1999
+++ linux/drivers/scsi/u14-34f.h	Fri Oct 22 12:47:52 1999
@@ -18,7 +18,9 @@
 
 #define U14_34F_VERSION "5.11.00"
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
 
 #define ULTRASTOR_14_34F {                                                   \
                 name:         "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
diff -u --recursive --new-file v2.3.22/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.3.22/linux/drivers/sgi/char/sgiserial.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sgi/char/sgiserial.c	Sat Oct 16 10:50:48 1999
@@ -408,6 +408,7 @@
 			show_state();
 			return;
 		} else if (ch == 2) {
+			show_buffers();
 			return;
 		}
 		/* It is a 'keyboard interrupt' ;-) */
diff -u --recursive --new-file v2.3.22/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.3.22/linux/drivers/sound/dev_table.h	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sound/dev_table.h	Thu Oct 21 13:38:12 1999
@@ -33,7 +33,7 @@
 #define SNDCARD_WAVEFRONT               41
 #define SNDCARD_OPL3SA2                 42
 #define SNDCARD_OPL3SA2_MPU             43
-#define SNDCARD_WAVEARTIST              44	/* Rebel Waveartist */
+#define SNDCARD_WAVEARTIST              44	/* Waveartist */
 #define SNDCARD_OPL3SA2_MSS             45	/* Originally missed */
 #define SNDCARD_AD1816                  88
 
diff -u --recursive --new-file v2.3.22/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.3.22/linux/drivers/sound/maestro.c	Fri Oct 15 15:25:14 1999
+++ linux/drivers/sound/maestro.c	Mon Oct 18 11:26:31 1999
@@ -847,7 +847,7 @@
 
 	__maestro_write(ess->card,reg,data);
 
-	spin_unlock_irqrestore(&card->lock,flags);
+	spin_unlock_irqrestore(&ess->card->lock,flags);
 }
 
 static u16 __maestro_read(struct ess_card *card, u16 reg)
diff -u --recursive --new-file v2.3.22/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.3.22/linux/drivers/sound/sound_core.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sound/sound_core.c	Mon Oct 18 11:26:31 1999
@@ -58,6 +58,9 @@
 #ifdef CONFIG_SOUND_MSNDPIN
 extern int msnd_pinnacle_init(void);
 #endif
+#ifdef CONFIG_SOUND_CMPCI
+extern init_cmpci(void);
+#endif
 
 /*
  *	Low level list operator. Scan the ordered list, find a hole and
diff -u --recursive --new-file v2.3.22/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c
--- v2.3.22/linux/drivers/sound/waveartist.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/sound/waveartist.c	Thu Oct 21 13:38:12 1999
@@ -1,14 +1,15 @@
 /*
- * drivers/sound/waveartist.c
+ * linux/drivers/sound/waveartist.c
  *
  * The low level driver for the RWA010 Rockwell Wave Artist
- * codec chip used in the Corel Computer NetWinder.
+ * codec chip used in the Rebel.com NetWinder.
  *
  * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk)
+ * and Pat Beirne (patb@corel.ca)
  */
 
 /*
- * Copyright (C) by Corel Computer 1998
+ * Copyright (C) by Rebel.com 1998-1999
  *
  * RWA010 specs received under NDA from Rockwell
  *
@@ -29,19 +30,17 @@
 
 #define debug_flg (0)
 
-#define DEB(x)
-#define DDB(x)
-#define DEB1(x)
-
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
+#include <linux/spinlock.h>
 
 #include <asm/dec21285.h>
 #include <asm/hardware.h>
+#include <asm/system.h>
 
 #include "soundmodule.h"
 #include "sound_config.h"
@@ -54,45 +53,24 @@
 #define _ISA_IRQ(x) (x)
 #endif
 
-#define	VNC_TIMER_PERIOD (HZ/4)	//check slider 4 times/sec
-
-#define	MIXER_PRIVATE3_RESET	0x53570000
-#define	MIXER_PRIVATE3_READ	0x53570001
-#define	MIXER_PRIVATE3_WRITE	0x53570002
-
-#define	VNC_INTERNAL_SPKR	0x01	//the sw mute on/off control bit
-#define	VNC_INTERNAL_MIC	0x10	//the hw internal/handset mic bit
-
-/* Use RECSRC = speaker to mark the internal microphone
- *
- * Some cheating involved here: there is no way to relay
- * to the system, which microphone in in use
- * (left = handset, or right = internal)
- *
- * So while I do not flag SPEAKER in the Recording Devices
- * Mask, when on internal
- *
- * mike - I set the speaker bit hi. Some mixers can be
- * confused a bit...
- */
-
-#define POSSIBLE_RECORDING_DEVICES	(SOUND_MASK_LINE |\
-					 SOUND_MASK_MIC |\
-					 SOUND_MASK_LINE1)	//Line1 = analog phone
-
-#define SUPPORTED_MIXER_DEVICES		(SOUND_MASK_SYNTH |\
-					 SOUND_MASK_PCM |\
-					 SOUND_MASK_LINE |\
-					 SOUND_MASK_MIC | \
-					 SOUND_MASK_LINE1 |\
-					 SOUND_MASK_RECLEV |\
-					 SOUND_MASK_VOLUME)
+#define POSSIBLE_RECORDING_DEVICES	(SOUND_MASK_LINE       |\
+					 SOUND_MASK_MIC	       |\
+					 SOUND_MASK_LINE1)
+
+#define SUPPORTED_MIXER_DEVICES		(SOUND_MASK_SYNTH      |\
+					 SOUND_MASK_PCM        |\
+					 SOUND_MASK_LINE       |\
+					 SOUND_MASK_MIC        |\
+					 SOUND_MASK_LINE1      |\
+					 SOUND_MASK_RECLEV     |\
+					 SOUND_MASK_VOLUME     |\
+					 SOUND_MASK_IMIX)
 
 static unsigned short levels[SOUND_MIXER_NRDEVICES] = {
 	0x5555,		/* Master Volume	 */
 	0x0000,		/* Bass			 */
 	0x0000,		/* Treble		 */
-	0x5555,		/* Synth (FM)		 */
+	0x2323,		/* Synth (FM)		 */
 	0x4b4b,		/* PCM			 */
 	0x0000,		/* PC Speaker		 */
 	0x0000,		/* Ext Line		 */
@@ -129,15 +107,20 @@
 	int		dev_no;
 
 	/* Mixer parameters */
-	unsigned short	*levels;
-	int		handset_state;
-	signed int	slider_vol;	   /* hardware slider volume */
+	unsigned short	*levels;	   /* cache of volume settings   */
 	int		recmask;	   /* currently enabled recording device! */
-	int             supported_devices; /* SUPPORTED_MIXER_DEVICES */
+	int             supported_devices; /* SUPPORTED_MIXER_DEVICES    */
 	int             rec_devices;	   /* POSSIBLE_RECORDING_DEVICES */
-	int		handset_mute_sw	:1;/* 1 - handset controlled in sw */
-	int		use_slider	:1;/* use slider setting for o/p vol */
-	int		mute_state	:1;
+
+#ifdef CONFIG_ARCH_NETWINDER
+	signed int	slider_vol;	   /* hardware slider volume     */
+	unsigned int	handset_detect	:1;
+	unsigned int	telephone_detect:1;
+	unsigned int	no_autoselect	:1;/* handset/telephone autoselects a path */
+	unsigned int	spkr_mute_state	:1;/* set by ioctl or autoselect */
+	unsigned int	line_mute_state	:1;/* set by ioctl or autoselect */
+	unsigned int	use_slider	:1;/* use slider setting for o/p vol */
+#endif
 } wavnc_info;
 
 typedef struct wavnc_port_info {
@@ -147,271 +130,18 @@
 	int		audio_format;
 } wavnc_port_info;
 
-static int		 nr_waveartist_devs;
-static wavnc_info	 adev_info[MAX_AUDIO_DEV];
-
-static int waveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level);
-
-/*
- * Corel Netwinder specifics...
- */
-static struct timer_list vnc_timer;
-extern spinlock_t gpio_lock;
-
-static void
-vnc_mute(wavnc_info *devc, int mute)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&gpio_lock, flags);
-	cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE);
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
-	devc->mute_state = mute;
-}
-
-static int
-vnc_volume_slider(wavnc_info *devc)
-{
-	static signed int old_slider_volume;
-	unsigned long flags;
-	signed int volume = 255;
-
-	*CSR_TIMER1_LOAD = 0x00ffffff;
-
-	save_flags(flags);
-	cli();
-
-	outb(0xFF, 0x201);
-	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;
-
-	while (volume && (inb(0x201) & 0x01))
-		volume--;
-
-	*CSR_TIMER1_CNTL = 0;
-
-	restore_flags(flags);
-	
-	volume = 0x00ffffff - *CSR_TIMER1_VALUE;
-
+static int		nr_waveartist_devs;
+static wavnc_info	adev_info[MAX_AUDIO_DEV];
+static spinlock_t	waveartist_lock = SPIN_LOCK_UNLOCKED;
 
-#ifndef REVERSE
-	volume = 150 - (volume >> 5);
-#else
-	volume = (volume >> 6) - 25;
+#ifndef machine_is_netwinder
+#define machine_is_netwinder() 0
 #endif
 
-	if (volume < 0)
-		volume = 0;
-
-	if (volume > 100)
-		volume = 100;
-
-	/*
-	 * slider quite often reads +-8, so debounce this random noise
-	 */
-	if ((volume - old_slider_volume) > 7 ||
-	    (old_slider_volume - volume) > 7) {
-		old_slider_volume = volume;
-
-		DEB(printk("Slider volume: %d.\n", old_slider_volume));
-	}
-
-	return old_slider_volume;
-}
-
-static int
-vnc_slider(wavnc_info *devc)
-{
-	signed int slider_volume;
-	unsigned int temp;
-
-	/*
-	 * read the "buttons" state.
-	 *  Bit 4 = handset present,
-	 *  Bit 5 = offhook
-	 */
-	// the state should be "querable" via a private IOCTL call
-	temp = inb(0x201) & 0x30;
-
-	if (!devc->handset_mute_sw &&
-	    (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) {
-		devc->handset_state = temp;
-		devc->handset_mute_sw = 0;
-
-		vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0);
-	}
-
-	slider_volume = vnc_volume_slider(devc);
-
-	/*
-	 * If we're using software controlled volume, and
-	 * the slider moves by more than 20%, then we
-	 * switch back to slider controlled volume.
-	 */
-	if (devc->slider_vol > slider_volume) {
-		if (devc->slider_vol - slider_volume > 20)
-			devc->use_slider = 1;
-	} else {
-		if (slider_volume - devc->slider_vol > 20)
-			devc->use_slider = 1;
-	}
-
-	/*
-	 * use only left channel
-	 */
-	temp = levels[SOUND_MIXER_VOLUME] & 0xFF;
-
-	if (slider_volume != temp && devc->use_slider) {
-		devc->slider_vol = slider_volume;
-
-		waveartist_mixer_set(devc, SOUND_MIXER_VOLUME,
-			slider_volume | slider_volume << 8);
-
-		return 1;
-	}
-
-	return 0;
-}
-
-static void
-vnc_slider_tick(unsigned long data)
-{
-	int next_timeout;
-
-	if (vnc_slider(adev_info + data))
-		next_timeout = 5;	// mixer reported change
-	else
-		next_timeout = VNC_TIMER_PERIOD;
-
-	mod_timer(&vnc_timer, jiffies + next_timeout);
-}
-
-static int
-vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
-	wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
-	int val, temp;
-
-	if (cmd == SOUND_MIXER_PRIVATE1) {
-		/*
-		 * Use this call to override the automatic handset
-		 * behaviour - ignore handset.
-		 *  bit 7 = total control over handset - do not
-		 *          to plug/unplug
-		 *  bit 4 = internal mic
-		 *  bit 0 = mute internal speaker
-		 */
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-
-		devc->handset_mute_sw = val;
-
-		temp = val & VNC_INTERNAL_SPKR;
-		if (devc->mute_state != temp)
-			vnc_mute(devc, temp);
-
-		devc->handset_state = val & VNC_INTERNAL_MIC;
-		waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
-		return 0;
-	}
-#if 0
-	if (cmd == SOUND_MIXER_PRIVATE2) {
-#define VNC_SOUND_PAUSE         0x53    //to pause the DSP
-#define VNC_SOUND_RESUME        0x57    //to unpause the DSP
-		int             val;
-
-		val = *(int *) arg;
-
-		printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val);
-
-		if (val == VNC_SOUND_PAUSE) {
-			wa_sendcmd(0x16);    //PAUSE the ADC
-		} else if (val == VNC_SOUND_RESUME) {
-			wa_sendcmd(0x18);    //RESUME the ADC
-		} else {
-			return -EINVAL;      //invalid parameters...
-		}
-		return 0;
-	}
-
-	if (cmd == SOUND_MIXER_PRIVATE3) {
-		long unsigned   flags;
-		int             mixer_reg[15];	//reg 14 is actually a command: read,write,reset
-
-		int             val;
-		int             i;
-
-		val = *(int *) arg;
-
-		if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT))
-			return (-EFAULT);
-
-		memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg));
-
-		if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) { 	//reset command??
-			wavnc_mixer_reset(devc);
-			return (0);
-		} else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) {	//write command??
-//			printk("WaveArtist Mixer: Private write command.\n");
-
-			wa_sendcmd(0x32);	//Pair1 - word 1 and 5
-			wa_sendcmd(mixer_reg[0]);
-			wa_sendcmd(mixer_reg[4]);
-
-			wa_sendcmd(0x32);	//Pair2 - word 2 and 6
-			wa_sendcmd(mixer_reg[1]);
-			wa_sendcmd(mixer_reg[5]);
-
-			wa_sendcmd(0x32);	//Pair3 - word 3 and 7
-			wa_sendcmd(mixer_reg[2]);
-			wa_sendcmd(mixer_reg[6]);
-
-			wa_sendcmd(0x32);	//Pair4 - word 4 and 8
-			wa_sendcmd(mixer_reg[3]);
-			wa_sendcmd(mixer_reg[7]);
-
-			wa_sendcmd(0x32);	//Pair5 - word 9 and 10
-			wa_sendcmd(mixer_reg[8]);
-			wa_sendcmd(mixer_reg[9]);
-
-			wa_sendcmd(0x0031);		//set left and right PCM
-			wa_sendcmd(mixer_reg[0x0A]);
-			wa_sendcmd(mixer_reg[0x0B]);
-
-			wa_sendcmd(0x0131);		//set left and right FM
-			wa_sendcmd(mixer_reg[0x0C]);
-			wa_sendcmd(mixer_reg[0x0D]);
-
-			return 0;
-		} else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) {	//read command?
-//			printk("WaveArtist Mixer: Private read command.\n");
-
-			//first read all current values...
-			save_flags(flags);
-			cli();
-
-			for (i = 0; i < 14; i++) {
-				wa_sendcmd((i << 8) + 0x30);	// get ready for command nn30H
-
-				while (!(inb(STATR) & CMD_RF)) {
-				};	//wait for response ready...
-
-				mixer_reg[i] = inw(CMDR);
-			}
-			restore_flags(flags);
-
-			if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT))
-				return (-EFAULT);
-
-			memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg));
-			return 0;
-		} else
-			return -EINVAL;
-	}
-#endif
-	return -EINVAL;
-}
+static struct timer_list vnc_timer;
+static void vnc_configure_mixer(wavnc_info *devc);
+static int vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg);
+static void vnc_slider_tick(unsigned long data);
 
 static inline void
 waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set)
@@ -472,7 +202,7 @@
 	} while (timeout--);
 
 	if (timeout == 0) {
-		printk("WaveArtist: reset timeout ");
+		printk(KERN_WARNING "WaveArtist: reset timeout ");
 		if (res != (unsigned int)-1)
 			printk("(res=%04X)", res);
 		printk("\n");
@@ -481,6 +211,10 @@
 	return 0;
 }
 
+/* Helper function to send and receive words
+ * from WaveArtist.  It handles all the handshaking
+ * and can send or receive multiple words.
+ */
 static int
 waveartist_cmd(wavnc_info *devc,
 		int nr_cmd, unsigned int *cmd,
@@ -554,6 +288,32 @@
 	return timed_out ? 1 : 0;
 }
 
+/*
+ * Send one command word
+ */
+static inline int
+waveartist_cmd1(wavnc_info *devc, unsigned int cmd)
+{
+	return waveartist_cmd(devc, 1, &cmd, 0, NULL);
+}
+
+/*
+ * Send one command, receive one word
+ */
+static inline unsigned int
+waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd)
+{
+	unsigned int ret;
+
+	waveartist_cmd(devc, 1, &cmd, 1, &ret);
+
+	return ret;
+}
+
+/*
+ * Send a double command, receive one
+ * word (and throw it away)
+ */
 static inline int
 waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg)
 {
@@ -562,11 +322,12 @@
 	vals[0] = cmd;
 	vals[1] = arg;
 
-	waveartist_cmd(devc, 2, vals, 1, vals);
-
-	return 0;
+	return waveartist_cmd(devc, 2, vals, 1, vals);
 }
 
+/*
+ * Send a triple command
+ */
 static inline int
 waveartist_cmd3(wavnc_info *devc, unsigned int cmd,
 		unsigned int arg1, unsigned int arg2)
@@ -581,72 +342,18 @@
 }
 
 static int
-waveartist_sendcmd(struct address_info *hw, unsigned int cmd)
-{
-	int count;
-
-	if (debug_flg & DEBUG_CMD)
-		printk("waveartist_sendcmd: cmd=0x%04X...", cmd);
-
-	udelay(10);
-
-	if (inb(hw->io_base + STATR) & CMD_RF) {
-		/*
-		 * flush the port
-		 */
-		count = inw(hw->io_base + CMDR);
-
-		udelay(10);
-
-		if (debug_flg & DEBUG_CMD)
-			printk(" flushed %04X...", count);
-	}
-
-	/*
-	 * preset timeout at 5000 loops
-	 */
-	count = 5000;
-
-	while (count --)
-		if (inb(hw->io_base + STATR) & CMD_WE) {
-			/* wait till CMD_WE is high
-			 * then output the command
-			 */
-			outw(cmd, hw->io_base + CMDR);
-			break;
-		}
-
-	/* ready BEFORE timeout?
-	 */
-	if (debug_flg & DEBUG_CMD)
-		printk(" %s\n", count ? "Done OK." : "Error!");
-
-	udelay(10);
-
-	return count ? 0 : 1;
-}
-
-static int
-waveartist_getrev(struct address_info *hw, char *rev)
+waveartist_getrev(wavnc_info *devc, char *rev)
 {
-	int temp;
+	unsigned int temp[2];
+	unsigned int cmd = WACMD_GETREV;
 
-	waveartist_sendcmd(hw, 0);
-	udelay(20);
-	temp = inw(hw->io_base + CMDR);
-	udelay(20);
-	inw(hw->io_base + CMDR);	// discard second word == 0
+	waveartist_cmd(devc, 1, &cmd, 2, temp);
 
-	rev[0] = temp >> 8;
-	rev[1] = temp & 255;
+	rev[0] = temp[0] >> 8;
+	rev[1] = temp[0] & 255;
 	rev[2] = '\0';
 
-	return temp;
-}
-
-inline void
-waveartist_mute(wavnc_info *devc, int mute)
-{
+	return temp[0];
 }
 
 static void waveartist_halt_output(int dev);
@@ -667,10 +374,9 @@
 	devc  = (wavnc_info *) audio_devs[dev]->devc;
 	portc = (wavnc_port_info *) audio_devs[dev]->portc;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 	if (portc->open_mode || (devc->open_mode & mode)) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&waveartist_lock, flags);
 		return -EBUSY;
 	}
 
@@ -683,13 +389,7 @@
 		devc->record_dev = dev;
 	if (mode & OPEN_WRITE)
 		devc->playback_dev = dev;
-	restore_flags(flags);
-
-	/*
-	 * Mute output until the playback really starts. This
-	 * decreases clicking (hope so).
-	 */
-	waveartist_mute(devc, 1);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 
 	return 0;
 }
@@ -701,8 +401,7 @@
 	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;
 	unsigned long	flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	waveartist_halt(dev);
 
@@ -710,9 +409,7 @@
 	devc->open_mode &= ~portc->open_mode;
 	portc->open_mode = 0;
 
-	waveartist_mute(devc, 1);
-
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 }
 
 static void
@@ -747,18 +444,17 @@
 			 */
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	/*
 	 * set sample count
 	 */
-	waveartist_cmd2(devc, 0x0024, count);
+	waveartist_cmd2(devc, WACMD_OUTPUTSIZE, count);
 
 	devc->xfer_count = count;
 	devc->audio_mode |= PCM_ENABLE_OUTPUT;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 }
 
 static void
@@ -791,19 +487,17 @@
 			 */
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	/*
 	 * set sample count
 	 */
-	waveartist_cmd2(devc, 0x0014, count);
-	waveartist_mute(devc, 0);
+	waveartist_cmd2(devc, WACMD_INPUTSIZE, count);
 
 	devc->xfer_count = count;
 	devc->audio_mode |= PCM_ENABLE_INPUT;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 }
 
 static int
@@ -869,40 +563,42 @@
 	speed = waveartist_get_speed(portc);
 	bits  = waveartist_get_bits(portc);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits))
-		printk("waveartist: error setting the record format to %d\n",
-		       portc->audio_format);
+		printk(KERN_WARNING "waveartist: error setting the "
+		       "record format to %d\n", portc->audio_format);
 
 	if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels))
-		printk("waveartist: error setting record to %d channels\n",
-		       portc->channels);
+		printk(KERN_WARNING "waveartist: error setting record "
+		       "to %d channels\n", portc->channels);
 
 	/*
 	 * write cmd SetSampleSpeedTimeConstant
 	 */
 	if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed))
-		printk("waveartist: error setting the record speed "
-		       "to %dHz.\n", portc->speed);
+		printk(KERN_WARNING "waveartist: error setting the record "
+		       "speed to %dHz.\n", portc->speed);
 
 	if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1))
-		printk("waveartist: error setting the record data path "
-		       "to 0x%X\n", 1);
+		printk(KERN_WARNING "waveartist: error setting the record "
+		       "data path to 0x%X\n", 1);
 
 	if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits))
-		printk("waveartist: error setting the record format to %d\n",
-		       portc->audio_format);
+		printk(KERN_WARNING "waveartist: error setting the record "
+		       "format to %d\n", portc->audio_format);
 
 	devc->xfer_count = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 	waveartist_halt_input(dev);
 
 	if (debug_flg & DEBUG_INTR) {
-		printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR));
-		printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR));
-		printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT));
+		printk("WA CTLR reg: 0x%02X.\n",
+		       inb(devc->hw.io_base + CTLR));
+		printk("WA STAT reg: 0x%02X.\n",
+		       inb(devc->hw.io_base + STATR));
+		printk("WA IRQS reg: 0x%02X.\n",
+		       inb(devc->hw.io_base + IRQSTAT));
 	}
 
 	return 0;
@@ -922,28 +618,27 @@
 	speed = waveartist_get_speed(portc);
 	bits  = waveartist_get_bits(portc);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) &&
 	    waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed))
-		printk("waveartist: error setting the playback speed "
-		       "to %dHz.\n", portc->speed);
+		printk(KERN_WARNING "waveartist: error setting the playback "
+		       "speed to %dHz.\n", portc->speed);
 
 	if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels))
-		printk("waveartist: error setting the playback to"
-		       " %d channels\n", portc->channels);
+		printk(KERN_WARNING "waveartist: error setting the playback "
+		       "to %d channels\n", portc->channels);
 
 	if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0))
-		printk("waveartist: error setting the playback data path "
-		       "to 0x%X\n", 0);
+		printk(KERN_WARNING "waveartist: error setting the playback "
+		       "data path to 0x%X\n", 0);
 
 	if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits))
-		printk("waveartist: error setting the playback format to %d\n",
-		       portc->audio_format);
+		printk(KERN_WARNING "waveartist: error setting the playback "
+		       "format to %d\n", portc->audio_format);
 
 	devc->xfer_count = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 	waveartist_halt_output(dev);
 
 	if (debug_flg & DEBUG_INTR) {
@@ -961,7 +656,6 @@
 	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;
 	wavnc_info	*devc;
 
-
 	if (portc->open_mode & OPEN_WRITE)
 		waveartist_halt_output(dev);
 
@@ -978,19 +672,13 @@
 	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;
 	unsigned long	flags;
 
-	save_flags(flags);
-	cli();
-
-	waveartist_mute(devc, 1);
-
-//RMK	disable_dma(audio_devs[dev]->dmap_in->dma);
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	/*
 	 * Stop capture
 	 */
-	waveartist_sendcmd(&devc->hw, 0x17);
+	waveartist_cmd1(devc, WACMD_INPUTSTOP);
 
-//RMK	enable_dma(audio_devs[dev]->dmap_in->dma);
 	devc->audio_mode &= ~PCM_ENABLE_INPUT;
 
 	/*
@@ -1002,7 +690,7 @@
 
 //	devc->audio_mode &= ~PCM_ENABLE_INPUT;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 }
 
 static void
@@ -1011,16 +699,9 @@
 	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;
 	unsigned long	flags;
 
-	save_flags(flags);
-	cli();
-
-	waveartist_mute(devc, 1);
-
-//RMK	disable_dma(audio_devs[dev]->dmap_out->dma);
-
-	waveartist_sendcmd(&devc->hw, 0x27);
+	spin_lock_irqsave(&waveartist_lock, flags);
 
-//RMK	enable_dma(audio_devs[dev]->dmap_out->dma);
+	waveartist_cmd1(devc, WACMD_OUTPUTSTOP);
 
 	devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
 
@@ -1033,7 +714,7 @@
 
 //	devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 }
 
 static void
@@ -1052,8 +733,7 @@
 		printk("\n");
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&waveartist_lock, flags);
 
 	state &= devc->audio_mode;
 
@@ -1062,18 +742,16 @@
 		/*
 		 * enable ADC Data Transfer to PC
 		 */
-		waveartist_sendcmd(&devc->hw, 0x15);
+		waveartist_cmd1(devc, WACMD_INPUTSTART);
 
 	if (portc->open_mode & OPEN_WRITE &&
 	    state & PCM_ENABLE_OUTPUT)
 		/*
 		 * enable DAC data transfer from PC
 		 */
-		waveartist_sendcmd(&devc->hw, 0x25);
+		waveartist_cmd1(devc, WACMD_OUTPUTSTART);
 
-	waveartist_mute(devc, 0);
-
-	restore_flags(flags);
+	spin_unlock_irqrestore(&waveartist_lock, flags);
 }
 
 static int
@@ -1158,7 +836,7 @@
 	if (status & IRQ_REQ)	/* Clear interrupt */
 		waveartist_iack(devc);
 	else
-		printk("waveartist: unexpected interrupt\n");
+		printk(KERN_WARNING "waveartist: unexpected interrupt\n");
 
 #ifdef CONFIG_AUDIO
 	if (irqstatus & 0x01) {
@@ -1175,12 +853,12 @@
 			temp = 0;
 		}
 		if (temp)	//default:
-			printk("WaveArtist: Unknown interrupt\n");
+			printk(KERN_WARNING "waveartist: Unknown interrupt\n");
 	}
 #endif
 	if (irqstatus & 0x2)
 		// We do not use SB mode natively...
-		printk("WaveArtist: Unexpected SB interrupt...\n");
+		printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n");
 }
 
 /* -------------------------------------------------------------------------
@@ -1198,6 +876,9 @@
 
 #define SCALE(lev,max)	((lev) * (max) / 100)
 
+	if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT)
+		whichDev = SOUND_MIXER_VOLUME;
+
 	switch(whichDev) {
 	case SOUND_MIXER_VOLUME:
 		mask  = 0x000e;
@@ -1208,6 +889,8 @@
 		break;
 
 	case SOUND_MIXER_LINE:
+		if ((devc->recmask & SOUND_MASK_LINE) == 0)
+			return;
 		mask  = 0x07c0;
 		reg_l = 0x000;
 		reg_r = 0x400;
@@ -1216,6 +899,8 @@
 		break;
 
 	case SOUND_MIXER_MIC:
+		if ((devc->recmask & SOUND_MASK_MIC) == 0)
+			return;
 		mask  = 0x0030;
 		reg_l = 0x200;
 		reg_r = 0x600;
@@ -1232,6 +917,8 @@
 		break;
 
 	case SOUND_MIXER_LINE1:
+		if ((devc->recmask & SOUND_MASK_LINE1) == 0)
+			return;
 		mask  = 0x003e;
 		reg_l = 0x000;
 		reg_r = 0x400;
@@ -1240,12 +927,14 @@
 		break;
 
 	case SOUND_MIXER_PCM:
-		waveartist_cmd3(devc, 0x0031, SCALE(lev_left,  32767),
+		waveartist_cmd3(devc, WACMD_SET_LEVEL,
+				SCALE(lev_left,  32767),
 				SCALE(lev_right, 32767));
 		return;
 
 	case SOUND_MIXER_SYNTH:
-		waveartist_cmd3(devc, 0x0131, SCALE(lev_left,  32767),
+		waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL,
+				SCALE(lev_left,  32767),
 				SCALE(lev_right, 32767));
 		return;
 
@@ -1254,7 +943,7 @@
 	}
 
 	/* read left setting */
-	vals[0] = reg_l + 0x30;
+	vals[0] = reg_l + WACMD_GET_LEVEL;
 	waveartist_cmd(devc, 1, vals, 1, vals + 1);
 
 	/* read right setting */
@@ -1265,7 +954,7 @@
 	vals[2] = (vals[2] & ~mask) | (lev_right & mask);
 
 	/* write left,right back */
-	vals[0] = 0x32;
+	vals[0] = WACMD_SET_MIXER;
 	waveartist_cmd(devc, 3, vals, 0, NULL);
 }
 
@@ -1273,20 +962,6 @@
 waveartist_select_input(wavnc_info *devc, unsigned int input)
 {
 	unsigned int vals[3];
-#if 1
-	/* New mixer programming - switch recording source
-	 * using R/L_ADC_Mux_Select.  We are playing with
-	 * left/right mux bit fields in reg 9.
-	 *
-	 * We can not switch Mux_Select while recording, so
-	 * for microphones, enable both left and right and
-	 * play with levels only!
-	 *
-	 * Unfortunately, we need to select the src of mono
-	 * recording (left or right) before starting the
-	 * recording - so can not dynamically switch between
-	 * handset amd internal microphones...
-	 */
 
 	/*
 	 * Get reg 9
@@ -1304,48 +979,14 @@
 		printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n",
 			vals[1] & 0x07, (vals[1] >> 3) & 0x07);
 
-	vals[1] &= ~0x03F;	//kill current left/right mux input select
+	/*
+	 * kill current left/right mux input select
+	 */
+	vals[1] &= ~0x03F;
 
 	switch (input) {
-		/*
-		 * Handset or internal MIC
-		 */
 	case SOUND_MASK_MIC:
 		/*
-		 * handset not plugged in?
-		 */
-		if (devc->handset_state & VNC_INTERNAL_MIC) {
-			/*
-			 * set mono recording from right mic
-			 */
-			waveartist_sendcmd(&devc->hw, 0x0134);
-#if 0
-			/*
-			 * right=mic, left=none
-			 */
-			vals[1] |= 0x0028;
-			/*
-			 * pretend int mic
-			 */
-			devc->rec_devices |= SOUND_MASK_SPEAKER;
-#endif
-		} else {
-			/*
-			 * set mono rec from left mic
-			 */
-			waveartist_sendcmd(&devc->hw, 0x0034);
-#if 0
-			/*
-			 * right=none, left=mic
-			 */
-			vals[1] |= 0x0005;
-			/*
-			 * show no int mic
-			 */
-			devc->rec_devices &= ~SOUND_MASK_SPEAKER;
-#endif
-		}
-		/*
 		 * right=mic, left=mic
 		 */
 		vals[1] |= 0x002D;
@@ -1353,10 +994,6 @@
 
 	case SOUND_MASK_LINE1:
 		/*
-		 * set mono rec from left aux1
-		 */
-		waveartist_sendcmd(&devc->hw, 0x0034);
-		/*
 		 * right=none, left=Aux1;
 		 */
 		vals[1] |= 0x0004;
@@ -1364,10 +1001,6 @@
 
 	case SOUND_MASK_LINE:
 		/*
-		 * set mono rec from left (default)
-		 */
-		waveartist_sendcmd(&devc->hw, 0x0034);
-		/*
 		 * right=Line, left=Line;
 		 */
 		vals[1] |= 0x0012;
@@ -1378,101 +1011,10 @@
 		printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input,
 			vals[1] & 0x07, (vals[1] >> 3) & 0x07);
 
-#else
-	/* This part is good, if input connected to
-	 * a mixer, so can be used for record-only modes...
-	 */
-
-	/*
-	 * get reg 4
-	 */
-	vals[0] = 0x0330;
-	waveartist_cmd(devc, 1, vals, 1, vals + 1);
-
-	/*
-	 * get reg 8
-	 */
-	vals[0] = 0x0730;
-	waveartist_cmd(devc, 1, vals, 1, vals + 2);
-
-	if (debug_flg & DEBUG_MIXER)
-		printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n",
-			vals[1], vals[2]);
-
-	/*
-	 * kill current left/right mux input select
-	 */
-	vals[1] &= ~0x07F8;
-	vals[2] &= ~0x07F8;
-
-	switch (input) {
-		/*
-		 * handset or internal mic
-		 */
-	case SOUND_MASK_MIC:
-		/*
-		 * handset not plugged in?
-		 */
-		if (devc->handset_state & VNC_INTERNAL_MIC) {
-			/*
-			 * set mono recording from right mic
-			 */
-			waveartist_sendcmd(&devc->hw, 0x0134);
-			/*
-			 * left = none, right = mic, RX filter gain
-			 */
-			vals[1] |= 0x0C00;
-			vals[2] |= 0x0C88;
-			/*
-			 * pretend int mic
-			 */
-			devc->rec_devices |= SOUND_MASK_SPEAKER;
-		} else {
-			/*
-			 * set mono rec from left mic
-			 */
-			waveartist_sendcmd(&devc->hw, 0x0034);
-			/*
-			 * left = mic, RX filter gain, right = none;
-			 */
-			vals[1] |= 0x0C88;
-			vals[2] |= 0x0C00;
-			/*
-			 * show no int mic
-			 */
-			devc->rec_devices &= ~SOUND_MASK_SPEAKER;
-		}
-		break;
-
-	case SOUND_MASK_LINE1:
-		/*
-		 * set mono rec from left aux1
-		 */
-		waveartist_sendcmd(&devc->hw, 0x0034);
-		/*
-		 * left = Aux1, right = none
-		 */
-		vals[1] |= 0x0C40;
-		vals[2] |= 0x0C00;
-		break;
-	
-	case SOUND_MASK_LINE:
-		/*
-		 * left = Line, right = Line
-		 */
-		vals[1] |= 0x0C10;
-		vals[2] |= 0x0C10;
-		break;
-	}
-
-	if (debug_flg & DEBUG_MIXER)
-		printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n",
-			level, vals[1], vals[2]);
-#endif
 	/*
 	 * and finally - write the reg pair back....
 	 */
-	vals[0] = 0x32;
+	vals[0] = WACMD_SET_MIXER;
 
 	waveartist_cmd(devc, 3, vals, 0, NULL);
 }
@@ -1482,8 +1024,7 @@
 {
 	unsigned int lev_left  = level & 0x007f;
 	unsigned int lev_right = (level & 0x7f00) >> 8;
-
-	int left, right, devmask, changed, i;
+	int left, right, devmask;
 
 	left = level & 0x7f;
 	right = (level & 0x7f00) >> 8;
@@ -1493,85 +1034,38 @@
 			whichDev, level);
 
 	switch (whichDev) {
-	/* Master volume (0-7)
-	 * We have 3 bits on the Left/Right Mixer Gain,
-	 * bits 3,2,1 on 3 and 7
-	 */
-	case SOUND_MIXER_VOLUME:
+	case SOUND_MIXER_VOLUME:	/* master volume (0-7)       */
+	case SOUND_MIXER_LINE:		/* external line (0-31)      */
+	case SOUND_MIXER_MIC:		/* mono mic (0-3)            */
+	case SOUND_MIXER_RECLEV:	/* recording level (0-7)     */
+	case SOUND_MIXER_LINE1:		/* mono external aux1 (0-31) */
+	case SOUND_MIXER_PCM:		/* Waveartist PCM (0-32767)  */
+	case SOUND_MIXER_SYNTH:		/* internal synth (0-31)     */
+	case SOUND_MIXER_IMIX:		/* recording feedback        */
 		devc->levels[whichDev] = lev_left | lev_right << 8;
 		waveartist_mixer_update(devc, whichDev);
 		break;
 
-
-	/* External line (0-31)
-	 * use LOUT/ROUT bits 10...6, reg 1 and 5
-	 */
-	case SOUND_MIXER_LINE:
-		devc->levels[whichDev] = lev_left | lev_right << 8;
-		waveartist_mixer_update(devc, whichDev);
-		break;
-
-	/* Mono microphone (0-3) mute,
-	 * 0db,10db,20db
-	 */
-	case SOUND_MIXER_MIC:
-#if 1
-		devc->levels[whichDev] = lev_left | lev_right << 8;
-#else
-		/* we do not need to mute volume of
-		 * an unused mic - it is simply unused...
-		 */
-		if (devc->handset_state & VNC_INTERNAL_MIC)
-			devc->levels[whichDev] = lev_right << 8;
-		else
-			levels[whichDev] = lev_left;
-#endif
-		waveartist_mixer_update(devc, whichDev);
-		break;
-
-	/* Recording level (0-7)
-	 */
-	case SOUND_MIXER_RECLEV:
-		devc->levels[whichDev] = lev_left | lev_right << 8;
-		waveartist_mixer_update(devc, whichDev);
-		break;
-
-	/* Mono External Aux1 (0-31)
-	 * use LINE1 bits 5...1, reg 1 and 5
-	 */
-	case SOUND_MIXER_LINE1:
-		devc->levels[whichDev] = lev_left | lev_right << 8;
-		waveartist_mixer_update(devc, whichDev);
-		break;
-
-	/* WaveArtist PCM (0-32767)
-	 */
-	case SOUND_MIXER_PCM:
-		devc->levels[whichDev] = lev_left | lev_right << 8;
-		waveartist_mixer_update(devc, whichDev);
-		break;
-
-	/* Internal synthesizer (0-31)
-	 */
-	case SOUND_MIXER_SYNTH:
-		devc->levels[whichDev] = lev_left | lev_right << 8;
-		waveartist_mixer_update(devc, whichDev);
-		break;
-
-
 	/* Select recording input source
 	 */
 	case SOUND_MIXER_RECSRC:
-		devmask = level & POSSIBLE_RECORDING_DEVICES;
+		devmask = level & devc->rec_devices;
 
-		changed = devmask ^ devc->recmask;
-		devc->recmask = devmask;
+#ifdef CONFIG_ARCH_NETWINDER
+		if (machine_is_netwinder())
+			vnc_configure_mixer(devc);
+		else
+#endif
+		{
+			waveartist_select_input(devc, level);
 
-		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-			if (changed & (1 << i))
-				waveartist_mixer_update(devc, i);
+			/*
+			 * if record monitoring is on, make sure the bit is set
+			 */
+			if (devc->levels[SOUND_MIXER_IMIX])
+				waveartist_mixer_update(devc, SOUND_MIXER_IMIX);
+		}
 
-		waveartist_select_input(devc, level);
 		/*
 		 * do not save in "levels", return current setting
 		 */
@@ -1595,53 +1089,54 @@
 	/*
 	 * reset mixer cmd
 	 */
-	waveartist_sendcmd(&devc->hw, 0x33);
+	waveartist_cmd1(devc, WACMD_RST_MIXER);
 
 	/*
-	 * set input for ADC to come from
-	 * a mux (left and right) == reg 9,
-	 * initially none
+	 * set input for ADC to come from 'quiet'
+	 * turn on default modes
 	 */
-	waveartist_cmd3(devc, 0x0032, 0x9800, 0xa836);
+	waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836);
 
 	/*
 	 * set mixer input select to none, RX filter gains 0 db
 	 */
-	waveartist_cmd3(devc, 0x0032, 0x4c00, 0x8c00);
+	waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00);
 
 	/*
 	 * set bit 0 reg 2 to 1 - unmute MonoOut
 	 */
-	waveartist_cmd3(devc, 0x0032, 0x2801, 0x6800);
-
-	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-		waveartist_mixer_update(devc, i);
+	waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800);
 
 	/* set default input device = internal mic
 	 * current recording device = none
-	 * no handset
 	 */
 	devc->recmask = 0;
-	devc->handset_state = VNC_INTERNAL_MIC;
-//	waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
 
-	/*
-	 * start from enabling the hw setting
-	 */
-	devc->handset_mute_sw = 0;
+	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+		waveartist_mixer_update(devc, i);
+
 	devc->supported_devices = SUPPORTED_MIXER_DEVICES;
 	devc->rec_devices = POSSIBLE_RECORDING_DEVICES;
+
+	if (machine_is_netwinder()) {
+		devc->supported_devices |= SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT;
+		devc->rec_devices |= SOUND_MASK_PHONEIN;
+	}
 }
 
 static int
 waveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
 	wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+	int ret;
 
-	if (cmd == SOUND_MIXER_PRIVATE1 ||
-	    cmd == SOUND_MIXER_PRIVATE2 ||
-	    cmd == SOUND_MIXER_PRIVATE3)
-		return vnc_private_ioctl(dev, cmd, arg);
+#ifdef CONFIG_ARCH_NETWINDER
+	if (machine_is_netwinder()) {
+		ret = vnc_private_ioctl(dev, cmd, arg);
+		if (ret != -ENOIOCTLCMD)
+			return ret;
+	}
+#endif
 
 	if (((cmd >> 8) & 0xff) == 'M') {
 		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
@@ -1650,30 +1145,14 @@
 			if (get_user(val, (int *)arg))
 				return -EFAULT;
 
-			/*
-			 * special case for master volume: if we
-			 * received this call - switch from hw
-			 * volume control to a software volume
-			 * control, till the hw volume is modified
-			 * to signal that user wants to be back in
-			 * hardware...
-			 */
-			if ((cmd & 0xff) == SOUND_MIXER_VOLUME)
-				devc->use_slider = 0;
-
 			return waveartist_mixer_set(devc, cmd & 0xff, val);
 		} else {
-			int ret;
-
 			/*
 			 * Return parameters
 			 */
 			switch (cmd & 0xff) {
 			case SOUND_MIXER_RECSRC:
 				ret = devc->recmask;
-
-				if (devc->handset_state & VNC_INTERNAL_MIC)
-					ret |= SOUND_MASK_SPEAKER;
 				break;
 
 			case SOUND_MIXER_DEVMASK:
@@ -1700,7 +1179,7 @@
 					return -EINVAL;
 			}
 
-			return put_user(ret, (int *)arg) ? -EINVAL : 0;
+			return put_user(ret, (int *)arg) ? -EFAULT : 0;
 		}
 	}
 
@@ -1725,7 +1204,7 @@
 
 	sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name);
 
-	if (waveartist_getrev(&devc->hw, rev)) {
+	if (waveartist_getrev(devc, rev)) {
 		strcat(dev_name, " rev. ");
 		strcat(dev_name, rev);
 	}
@@ -1758,20 +1237,20 @@
 	waveartist_iack(devc);
 
 	if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) {
-		printk("%s: IRQ %d in use\n",
+		printk(KERN_ERR "%s: IRQ %d in use\n",
 			devc->hw.name, devc->hw.irq);
 		goto uninstall;
 	}
 
 	if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) {
-		printk("%s: Can't allocate DMA%d\n",
+		printk(KERN_ERR "%s: Can't allocate DMA%d\n",
 			devc->hw.name, devc->hw.dma);
 		goto uninstall_irq;
 	}
 
 	if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA)
 		if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) {
-			printk("%s: can't allocate DMA%d\n",
+			printk(KERN_ERR "%s: can't allocate DMA%d\n",
 				devc->hw.name, devc->hw.dma2);
 			goto uninstall_dma;
 		}
@@ -1809,22 +1288,24 @@
 	wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
 	if (nr_waveartist_devs >= MAX_AUDIO_DEV) {
-		printk("waveartist: too many audio devices\n");
+		printk(KERN_WARNING "waveartist: too many audio devices\n");
 		return 0;
 	}
 
 	if (check_region(hw_config->io_base, 15))  {
-		printk("WaveArtist: I/O port conflict\n");
+		printk(KERN_WARNING "WaveArtist: I/O port conflict\n");
 		return 0;
 	}
 
 	if (hw_config->irq > _ISA_IRQ(15) || hw_config->irq < _ISA_IRQ(0)) {
-		printk("WaveArtist: Bad IRQ %d\n", hw_config->irq);
+		printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n",
+		       hw_config->irq);
 		return 0;
 	}
 
 	if (hw_config->dma != _ISA_DMA(3)) {
-		printk("WaveArtist: Bad DMA %d\n", hw_config->dma);
+		printk(KERN_WARNING "WaveArtist: Bad DMA %d\n",
+		       hw_config->dma);
 		return 0;
 	}
 
@@ -1864,15 +1345,18 @@
 	if (devc->dev_no < 0)
 		release_region(hw->io_base, 15);
 	else {
-		init_timer(&vnc_timer);
-		vnc_timer.function = vnc_slider_tick;
-		vnc_timer.expires  = jiffies;
-		vnc_timer.data     = nr_waveartist_devs;
-		add_timer(&vnc_timer);
+#ifdef CONFIG_ARCH_NETWINDER
+		if (machine_is_netwinder()) {
+			init_timer(&vnc_timer);
+			vnc_timer.function = vnc_slider_tick;
+			vnc_timer.expires  = jiffies;
+			vnc_timer.data     = nr_waveartist_devs;
+			add_timer(&vnc_timer);
 
+			vnc_configure_mixer(devc);
+		}
+#endif
 		nr_waveartist_devs += 1;
-
-		vnc_mute(devc, 0);
 	}
 }
 
@@ -1891,6 +1375,11 @@
 	if (devc != NULL) {
 		int mixer;
 
+#ifdef CONFIG_ARCH_NETWINDER
+		if (machine_is_netwinder())
+			del_timer(&vnc_timer);
+#endif
+
 		release_region(devc->hw.io_base, 15);
 
 		waveartist_set_ctlr(&devc->hw, DMA1_IE|DMA0_IE, 0);
@@ -1904,8 +1393,6 @@
 		    devc->hw.dma2 != NO_DMA)
 			sound_free_dma(devc->hw.dma2);
 
-		del_timer(&vnc_timer);
-
 		mixer = audio_devs[devc->dev_no]->mixer_dev;
 
 		if (mixer >= 0)
@@ -1919,7 +1406,356 @@
 		for (; i < nr_waveartist_devs; i++)
 			adev_info[i] = adev_info[i + 1];
 	} else
-		printk("waveartist: can't find device to unload\n");
+		printk(KERN_WARNING "waveartist: can't find device "
+		       "to unload\n");
+}
+
+/*
+ * Rebel.com Netwinder specifics...
+ */
+
+#define	VNC_TIMER_PERIOD (HZ/4)	//check slider 4 times/sec
+
+#define	MIXER_PRIVATE3_RESET	0x53570000
+#define	MIXER_PRIVATE3_READ	0x53570001
+#define	MIXER_PRIVATE3_WRITE	0x53570002
+
+#define	VNC_MUTE_INTERNAL_SPKR	0x01	//the sw mute on/off control bit
+#define	VNC_MUTE_LINE_OUT	0x10
+#define VNC_PHONE_DETECT	0x20
+#define VNC_HANDSET_DETECT	0x40
+#define VNC_DISABLE_AUTOSWITCH	0x80
+
+extern spinlock_t gpio_lock;
+
+static inline void
+vnc_update_spkr_mute(wavnc_info *devc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+	cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE);
+	spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static void
+vnc_mute_lout(wavnc_info *devc, int mute)
+{
+}
+
+static int
+vnc_volume_slider(wavnc_info *devc)
+{
+	static signed int old_slider_volume;
+	unsigned long flags;
+	signed int volume = 255;
+
+	*CSR_TIMER1_LOAD = 0x00ffffff;
+
+	save_flags(flags);
+	cli();
+
+	outb(0xFF, 0x201);
+	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;
+
+	while (volume && (inb(0x201) & 0x01))
+		volume--;
+
+	*CSR_TIMER1_CNTL = 0;
+
+	restore_flags(flags);
+	
+	volume = 0x00ffffff - *CSR_TIMER1_VALUE;
+
+
+#ifndef REVERSE
+	volume = 150 - (volume >> 5);
+#else
+	volume = (volume >> 6) - 25;
+#endif
+
+	if (volume < 0)
+		volume = 0;
+
+	if (volume > 100)
+		volume = 100;
+
+	/*
+	 * slider quite often reads +-8, so debounce this random noise
+	 */
+	if (abs(volume - old_slider_volume) > 7) {
+		old_slider_volume = volume;
+
+		if (debug_flg & DEBUG_MIXER)
+			printk(KERN_DEBUG "Slider volume: %d.\n", volume);
+	}
+
+	return old_slider_volume;
+}
+
+static void
+vnc_configure_mixer(wavnc_info *devc)
+{
+	u_int vals[3];
+
+	if (!devc->no_autoselect) {
+		if (devc->handset_detect) {
+			devc->recmask = SOUND_MASK_LINE1;
+			devc->spkr_mute_state = devc->line_mute_state = 1;
+		} else if (devc->telephone_detect) {
+			devc->recmask = SOUND_MASK_PHONEIN;
+			devc->spkr_mute_state = devc->line_mute_state = 1;
+		} else {
+			/* unless someone has asked for LINE-IN,
+			 * we default to MIC
+			 */
+			if ((devc->recmask & SOUND_MASK_LINE) == 0)
+				devc->recmask = SOUND_MASK_MIC;
+			devc->spkr_mute_state = devc->line_mute_state = 0;
+		}
+		vnc_update_spkr_mute(devc);
+		vnc_mute_lout(devc, devc->spkr_mute_state);
+	}
+
+	/* Ok.  At this point, we have done the autoswitch logic, or we
+	 * have had a command from an ioctl.  We have a valid devc->recmask.
+	 * Now we have to connect up the hardware to reflect the recmask.
+	 */
+	vals[1] = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x800);
+	vals[2] = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x900);
+
+	vals[1] &= ~0x3f;
+
+	switch(devc->recmask) {
+	case SOUND_MASK_MIC:		/* builtin mic */
+		waveartist_cmd1(devc, WACMD_SET_MONO | 0x100);	/* right */
+		vals[1] |= 0x28;
+		break;
+
+	case SOUND_MASK_LINE1:		/* out handset */
+		waveartist_cmd1(devc, WACMD_SET_MONO);		/* left */
+		vals[1] |= 0x05;
+		break;
+
+	case SOUND_MASK_PHONEIN:	/* our telephone mic */
+		waveartist_cmd1(devc, WACMD_SET_MONO);		/* left */
+		vals[1] |= 0x04;
+		break;
+
+	case SOUND_MASK_LINE:		/* stereo line in */
+		vals[1] |= 12;
+		break;
+
+	default:
+		return;
+	}
+
+	vals[0] = WACMD_SET_MIXER;
+	waveartist_cmd(devc, 3, vals, 0, NULL);
+
+	waveartist_mixer_update(devc, SOUND_MIXER_IMIX);
+}
+
+static int
+vnc_slider(wavnc_info *devc)
+{
+	signed int slider_volume;
+	unsigned int temp, old_hs, old_td;
+
+	/*
+	 * read the "buttons" state.
+	 *  Bit 4 = handset present,
+	 *  Bit 5 = offhook
+	 */
+	temp = inb(0x201) & 0x30;
+
+	old_hs = devc->handset_detect;
+	old_td = devc->telephone_detect;
+
+	devc->handset_detect = !(temp & 0x10);
+	devc->telephone_detect = !!(temp & 0x20);
+
+	if (!devc->no_autoselect &&
+	    (old_hs != devc->handset_detect ||
+	     old_td != devc->telephone_detect))
+		vnc_configure_mixer(devc);
+
+	slider_volume = vnc_volume_slider(devc);
+
+	/*
+	 * If we're using software controlled volume, and
+	 * the slider moves by more than 20%, then we
+	 * switch back to slider controlled volume.
+	 */
+	if (abs(devc->slider_vol - slider_volume) > 20)
+		devc->use_slider = 1;
+
+	/*
+	 * use only left channel
+	 */
+	temp = levels[SOUND_MIXER_VOLUME] & 0xFF;
+
+	if (slider_volume != temp && devc->use_slider) {
+		devc->slider_vol = slider_volume;
+
+		waveartist_mixer_set(devc, SOUND_MIXER_VOLUME,
+			slider_volume | slider_volume << 8);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+vnc_slider_tick(unsigned long data)
+{
+	int next_timeout;
+
+	if (vnc_slider(adev_info + data))
+		next_timeout = 5;	// mixer reported change
+	else
+		next_timeout = VNC_TIMER_PERIOD;
+
+	mod_timer(&vnc_timer, jiffies + next_timeout);
+}
+
+static int
+vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+	wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+	int val;
+
+	switch (cmd) {
+	case SOUND_MIXER_PRIVATE1:
+	{
+		u_int prev_spkr_mute, prev_line_mute, prev_auto_state;
+		int val;
+
+		get_user_ret(val, (int *)arg, -EFAULT);
+
+		/* check if parameter is logical */
+		if (val & ~(VNC_MUTE_INTERNAL_SPKR |
+			    VNC_MUTE_LINE_OUT |
+			    VNC_DISABLE_AUTOSWITCH))
+			return -EINVAL;
+
+		prev_auto_state = devc->no_autoselect;
+		prev_spkr_mute  = devc->spkr_mute_state;
+		prev_line_mute  = devc->line_mute_state;
+
+		devc->no_autoselect   = (val & VNC_DISABLE_AUTOSWITCH) ? 1 : 0;
+		devc->spkr_mute_state = (val & VNC_MUTE_INTERNAL_SPKR) ? 1 : 0;
+		devc->line_mute_state = (val & VNC_MUTE_LINE_OUT) ? 1 : 0;
+
+		if (prev_spkr_mute != devc->spkr_mute_state)
+			vnc_update_spkr_mute(devc);
+
+		if (prev_line_mute != devc->line_mute_state)
+			vnc_mute_lout(devc, devc->line_mute_state);
+
+		if (prev_auto_state != devc->no_autoselect)
+			vnc_configure_mixer(devc);
+		waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
+		return 0;
+	}
+
+	case SOUND_MIXER_PRIVATE2:
+		get_user_ret(val, (int *)arg, -EFAULT);
+
+		switch (val) {
+#define VNC_SOUND_PAUSE         0x53    //to pause the DSP
+#define VNC_SOUND_RESUME        0x57    //to unpause the DSP
+		case VNC_SOUND_PAUSE:
+			waveartist_cmd1(devc, 0x16);
+			break;
+
+		case VNC_SOUND_RESUME:
+			waveartist_cmd1(devc, 0x18);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		return 0;
+
+	/* private ioctl to allow bulk access to waveartist */
+	case SOUND_MIXER_PRIVATE3:
+	{
+		unsigned long	flags;
+		int		mixer_reg[15], i, val;
+
+		get_user_ret(val, (int *)arg, -EFAULT);
+		copy_from_user_ret(mixer_reg, (void *)val, sizeof(mixer_reg), -EFAULT);
+
+		switch (mixer_reg[14]) {
+		case MIXER_PRIVATE3_RESET:
+			waveartist_mixer_reset(devc);
+			break;
+
+		case MIXER_PRIVATE3_WRITE:
+			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[0], mixer_reg[4]);
+			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[1], mixer_reg[5]);
+			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[2], mixer_reg[6]);
+			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[3], mixer_reg[7]);
+			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[8], mixer_reg[9]);
+
+			waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[10], mixer_reg[11]);
+			waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[12], mixer_reg[13]);
+			break;
+
+		case MIXER_PRIVATE3_READ:
+			spin_lock_irqsave(&waveartist_lock, flags);
+
+			for (i = 0x30; i < 14 << 8; i += 1 << 8)
+				waveartist_cmd(devc, 1, &i, 1, mixer_reg + (i >> 8));
+
+			spin_unlock_irqrestore(&waveartist_lock, flags);
+
+			copy_to_user_ret((void *)val, mixer_reg, sizeof(mixer_reg), -EFAULT);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	/* read back the state from PRIVATE1 */
+	case SOUND_MIXER_PRIVATE4:
+		val = (devc->spkr_mute_state  ? VNC_MUTE_INTERNAL_SPKR : 0) |
+		      (devc->line_mute_state  ? VNC_MUTE_LINE_OUT      : 0) |
+		      (devc->handset_detect   ? VNC_HANDSET_DETECT     : 0) |
+		      (devc->telephone_detect ? VNC_PHONE_DETECT       : 0) |
+		      (devc->no_autoselect    ? VNC_DISABLE_AUTOSWITCH : 0);
+
+		return put_user(val, (int *)arg) ? -EFAULT : 0;
+	}
+
+	if (((cmd >> 8) & 0xff) == 'M') {
+		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+			/*
+			 * special case for master volume: if we
+			 * received this call - switch from hw
+			 * volume control to a software volume
+			 * control, till the hw volume is modified
+			 * to signal that user wants to be back in
+			 * hardware...
+			 */
+			if ((cmd & 0xff) == SOUND_MIXER_VOLUME)
+				devc->use_slider = 0;
+		} else if ((cmd & 0xff) == SOUND_MIXER_STEREODEVS) {
+			val = devc->supported_devices &
+				~(SOUND_MASK_IMIX |
+				  SOUND_MASK_MIC |
+				  SOUND_MASK_LINE1 |
+				  SOUND_MASK_PHONEIN |
+				  SOUND_MASK_PHONEOUT);
+			return put_user(val, (int *)arg) ? -EFAULT : 0;
+		}
+	}
+
+	return -ENOIOCTLCMD;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.22/linux/drivers/sound/waveartist.h linux/drivers/sound/waveartist.h
--- v2.3.22/linux/drivers/sound/waveartist.h	Thu Jun 17 01:11:35 1999
+++ linux/drivers/sound/waveartist.h	Thu Oct 21 13:38:12 1999
@@ -1,5 +1,8 @@
-
-// def file for Rockwell RWA010 chip set, as installed in Corel NetWinder
+/*
+ * linux/drivers/sound/waveartist.h
+ *
+ * def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder
+ */
 
 //registers
 #define CMDR	0
@@ -33,7 +36,8 @@
 
 //commands
 
-#define	WACMD_SYSTEMID	0
+#define	WACMD_SYSTEMID		0x00
+#define WACMD_GETREV		0x00
 #define	WACMD_INPUTFORMAT	0x10	//0-8S, 1-16S, 2-8U
 #define	WACMD_INPUTCHANNELS	0x11	//1-Mono, 2-Stereo
 #define	WACMD_INPUTSPEED	0x12	//sampling rate
@@ -56,8 +60,11 @@
 #define	WACMD_OUTPUTRESUME	0x28	//resume ADC
 #define	WACMD_OUTPUTPIO		0x29	//PIO ADC
 
+#define	WACMD_GET_LEVEL		0x30
+#define	WACMD_SET_LEVEL		0x31
+#define	WACMD_SET_MIXER		0x32
+#define	WACMD_RST_MIXER		0x33
+#define	WACMD_SET_MONO		0x34
 
-
-
-int             wa_sendcmd(unsigned int cmd);
-int             wa_writecmd(unsigned int cmd, unsigned int arg);
+int wa_sendcmd(unsigned int cmd);
+int wa_writecmd(unsigned int cmd, unsigned int arg);
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.22/linux/drivers/usb/cpia.c	Sat Oct  9 11:47:50 1999
+++ linux/drivers/usb/cpia.c	Sat Oct 16 19:15:32 1999
@@ -356,7 +356,7 @@
 			int i;
 			int y, u, y1, v, r, g, b;
 
-			/* We want atleast 2 bytes for the length */
+			/* We want at least 2 bytes for the length */
 			if (scratch_left(data) < 2)
 				goto out;
 
@@ -536,8 +536,9 @@
 	return totlen;
 }
 
-static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
+static int cpia_isoc_irq(int status, void *__buffer, int len, void *isocdesc)
 {
+	void *dev_id = ((struct usb_isoc_desc *)isocdesc)->context;
 	struct usb_cpia *cpia = (struct usb_cpia *)dev_id;
 	struct cpia_sbuf *sbuf;
 	int i;
@@ -584,6 +585,12 @@
 	cpia->cursbuf = 0;
 	cpia->scratchlen = 0;
 
+	/* Alternate interface 3 is is the biggest frame size */
+	if (usb_set_interface(cpia->dev, 1, 3) < 0) {
+		printk("usb_set_interface error\n");
+		return -EBUSY;
+	}
+
 	/* We double buffer the Iso lists */
 	err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
 		cpia, &cpia->sbuf[0].isodesc);
@@ -618,7 +625,7 @@
 	for (fx = 0; fx < FRAMES_PER_DESC; fx++)
 		id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
 
-	/* and the desc. [1] */
+	/* and for desc. [1] */
 	id = cpia->sbuf[1].isodesc;
 	id->start_type = 0;             /* will follow the first desc. */
 	id->callback_frames = 10;	/* on every 10th frame */
@@ -628,17 +635,16 @@
 	for (fx = 0; fx < FRAMES_PER_DESC; fx++)
 		id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
 
-	usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
-	usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
+	err = usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
+	if (err)
+		printk(KERN_ERR "CPiA USB driver error (%d) on usb_run_isoc\n", err);
+	err = usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
+	if (err)
+		printk(KERN_ERR "CPiA USB driver error (%d) on usb_run_isoc\n", err);
 
 #ifdef CPIA_DEBUG
 	printk("done scheduling\n");
 #endif
-	/* Alternate interface 3 is is the biggest frame size */
-	if (usb_set_interface(cpia->dev, 1, 3) < 0) {
-		printk("usb_set_interface error\n");
-		return -EBUSY;
-	}
 
 #if 0
 	if (usb_cpia_grab_frame(dev, 120) < 0) {
@@ -915,11 +921,8 @@
 			p.brightness = 180 << 8;	/* XXX */
 			p.contrast = 192 << 8;		/* XXX */
 			p.whiteness = 105 << 8;		/* XXX */
-#if 0
 			p.depth = 24;
-#endif
-			p.depth = 16;
-			p.palette = VIDEO_PALETTE_YUYV;
+			p.palette = VIDEO_PALETTE_RGB24;
 
 			if (copy_to_user(arg, &p, sizeof(p)))
 				return -EFAULT;
@@ -940,6 +943,8 @@
 #ifdef CPIA_DEBUG
 			printk("Attempting to set palette %d, depth %d\n",
 				p.palette, p.depth);
+			printk("SPICT: brightness=%d, hue=%d, colour=%d, contrast=%d, whiteness=%d\n",
+				p.brightness, p.hue, p.colour, p.contrast, p.whiteness);
 #endif
 
 			return 0;
@@ -1009,7 +1014,6 @@
 		{
 			struct video_mmap vm;
 
-
 			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
 				return -EFAULT;
 
@@ -1090,11 +1094,26 @@
 
 			return cpia_new_frame(cpia, -1);
 		}
+		case VIDIOCGFBUF:
+		{
+			struct video_buffer vb;
+
+#ifdef CPIA_DEBUG
+			printk("GFBUF\n");
+#endif
+
+			memset(&vb, 0, sizeof(vb));
+			vb.base = NULL;	/* frame buffer not supported, not used */
+
+			if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+				return -EFAULT;
+
+ 			return 0;
+ 		}
 		case VIDIOCKEY:
 			return 0;
 		case VIDIOCCAPTURE:
 			return -EINVAL;
-		case VIDIOCGFBUF:
 		case VIDIOCSFBUF:
 			return -EINVAL;
 		case VIDIOCGTUNER:
@@ -1333,4 +1352,3 @@
 	usb_cpia_cleanup();
 }
 #endif
-
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/hp_scanner.c linux/drivers/usb/hp_scanner.c
--- v2.3.22/linux/drivers/usb/hp_scanner.c	Fri Oct 15 15:25:14 1999
+++ linux/drivers/usb/hp_scanner.c	Sat Oct 16 19:15:32 1999
@@ -192,7 +192,7 @@
 		
 		if (partial) {
 			count = this_read = partial;
-		} else if (result == USB_ST_TIMEOUT || result == 15) {
+		} else if (result == USB_ST_TIMEOUT || result == 15) { 	/* FIXME: 15 ??? */
 			if(!maxretry--) {
 				printk(KERN_DEBUG "read_scanner: maxretry timeout\n");
 				return -ETIME;
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.3.22/linux/drivers/usb/inits.h	Sat Oct  9 11:47:50 1999
+++ linux/drivers/usb/inits.h	Sat Oct 16 19:15:32 1999
@@ -1,13 +1,14 @@
-int usb_kbd_init(void);
+int usb_acm_init(void);
 int usb_audio_init(void);
 int usb_hub_init(void);
-int usb_acm_init(void);
-int usb_printer_init(void);
 void usb_hub_cleanup(void);
+int usb_kbd_init(void);
+void usb_major_init(void);
 void usb_mouse_cleanup(void);
-int usb_scsi_init(void);
 int usb_hp_scanner_init(void);
 void usb_hp_scanner_cleanup(void);
+int usb_printer_init(void);
 int proc_usb_init (void);
 void proc_usb_cleanup (void);
+int usb_scsi_init(void);
 int usb_serial_init (void);
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.22/linux/drivers/usb/printer.c	Fri Oct 15 15:25:14 1999
+++ linux/drivers/usb/printer.c	Tue Oct 19 10:27:12 1999
@@ -25,37 +25,47 @@
 #define NAK_TIMEOUT (HZ)				/* stall wait for printer */
 #define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT)	/* should not take 1 minute a page! */
 
+#define BIG_BUF_SIZE			8192
+
+/*
+ * USB Printer Requests
+ */
+#define USB_PRINTER_REQ_GET_DEVICE_ID	0
+#define USB_PRINTER_REQ_GET_PORT_STATUS	1
+#define USB_PRINTER_REQ_SOFT_RESET	2
+
 #define MAX_PRINTERS	8
 
 struct pp_usb_data {
 	struct usb_device 	*pusb_dev;
-	__u8			isopen;			/* nz if open */
-	__u8			noinput;		/* nz if no input stream */
+	__u8			isopen;			/* True if open */
+	__u8			noinput;		/* True if no input stream */
 	__u8			minor;			/* minor number of device */
 	__u8			status;			/* last status from device */
 	int			maxin, maxout;		/* max transfer size in and out */
 	char			*obuf;			/* transfer buffer (out only) */
 	wait_queue_head_t	wait_q;			/* for timeouts */
 	unsigned int		last_error;		/* save for checking */
+	int			bulk_in_ep;		/* Bulk IN endpoint */
+	int			bulk_out_ep;		/* Bulk OUT endpoint */
+	int			bulk_in_index;		/* endpoint[bulk_in_index] */
+	int			bulk_out_index;		/* endpoint[bulk_out_index] */
 };
 
 static struct pp_usb_data *minor_data[MAX_PRINTERS];
 
 #define PPDATA(x) ((struct pp_usb_data *)(x))
 
-unsigned char printer_read_status(struct pp_usb_data *p)
+static unsigned char printer_read_status(struct pp_usb_data *p)
 {
 	__u8 status;
-	devrequest dr;
 	struct usb_device *dev = p->pusb_dev;
 
-	dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80;
-	dr.request = 1;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 1;
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1, HZ)) {
-		return 0;
+	if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+		USB_PRINTER_REQ_GET_PORT_STATUS,
+		USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
+		0, 0, &status, 1, HZ)) {
+ 		return 0;
 	}
 	return status;
 }
@@ -90,24 +100,21 @@
 	return status;
 }
 
-void printer_reset(struct pp_usb_data *p)
+static void printer_reset(struct pp_usb_data *p)
 {
-	devrequest dr;
 	struct usb_device *dev = p->pusb_dev;
 
-	dr.requesttype = USB_TYPE_CLASS | USB_RECIP_OTHER;
-	dr.request = 2;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 0;
-	dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ);
+	usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+		USB_PRINTER_REQ_SOFT_RESET,
+		USB_TYPE_CLASS | USB_RECIP_OTHER,
+		0, 0, NULL, 0, HZ);
 }
 
 static int open_printer(struct inode * inode, struct file * file)
 {
 	struct pp_usb_data *p;
 
-	if(MINOR(inode->i_rdev) >= MAX_PRINTERS ||
+	if (MINOR(inode->i_rdev) >= MAX_PRINTERS ||
 	   !minor_data[MINOR(inode->i_rdev)]) {
 		return -ENODEV;
 	}
@@ -141,7 +148,7 @@
 	p->isopen = 0;
 	file->private_data = NULL;
 	/* free the resources if the printer is no longer around */
-	if(!p->pusb_dev) {
+	if (!p->pusb_dev) {
 		minor_data[p->minor] = NULL;
 		kfree(p);
 	}
@@ -158,12 +165,7 @@
 	unsigned long partial;
 	int result = USB_ST_NOERROR;
 	int maxretry;
-	int endpoint_num;
-	struct usb_interface_descriptor *interface;
 	
-	interface = p->pusb_dev->config->interface->altsetting;
-	endpoint_num = (interface->endpoint[1].bEndpointAddress & 0x0f);
-
 	do {
 		char *obuf = p->obuf;
 		unsigned long thistime;
@@ -179,7 +181,7 @@
 				return bytes_written ? bytes_written : -EINTR;
 			}
 			result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
-					 usb_sndbulkpipe(p->pusb_dev, endpoint_num),
+					 usb_sndbulkpipe(p->pusb_dev, p->bulk_out_ep),
 					 obuf, thistime, &partial, HZ*20);
 			if (partial) {
 				obuf += partial;
@@ -187,7 +189,7 @@
 				maxretry = MAX_RETRY_COUNT;
 			}
 			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
-				if(!maxretry--)
+				if (!maxretry--)
 					return -ETIME;
                                 interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT);
 				continue;
@@ -214,21 +216,15 @@
        char * buffer, size_t count, loff_t *ppos)
 {
 	struct pp_usb_data *p = file->private_data;
-	int read_count;
+	int read_count = 0;
 	int this_read;
 	char buf[64];
 	unsigned long partial;
 	int result;
-	int endpoint_num;
-	struct usb_interface_descriptor *interface;
 	
-	interface = p->pusb_dev->config->interface->altsetting;
-	endpoint_num = (interface->endpoint[0].bEndpointAddress & 0x0f);
-
 	if (p->noinput)
 		return -EINVAL;
 
-	read_count = 0;
 	while (count) {
 		if (signal_pending(current)) {
 			return read_count ? read_count : -EINTR;
@@ -238,7 +234,7 @@
 		this_read = (count > sizeof(buf)) ? sizeof(buf) : count;
 
 		result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
-			  usb_rcvbulkpipe(p->pusb_dev, endpoint_num),
+			  usb_rcvbulkpipe(p->pusb_dev, p->bulk_in_ep),
 			  buf, this_read, &partial, HZ*20);
 
 		/* unlike writes, we don't retry a NAK, just stop now */
@@ -266,8 +262,8 @@
 	/*
 	 * FIXME - this will not cope with combined printer/scanners
 	 */
-	if ((dev->descriptor.bDeviceClass != 7 &&
-	     dev->descriptor.bDeviceClass != 0) ||
+	if ((dev->descriptor.bDeviceClass != USB_CLASS_PRINTER &&
+	    dev->descriptor.bDeviceClass != 0) ||
 	    dev->descriptor.bNumConfigurations != 1 ||
 	    dev->config[0].bNumInterfaces != 1) {
 		return -1;
@@ -275,34 +271,50 @@
 
 	interface = &dev->config[0].interface[0].altsetting[0];
 
-	/* Lets be paranoid (for the moment)*/
-	if (interface->bInterfaceClass != 7 ||
+	/* Let's be paranoid (for the moment). */
+	if (interface->bInterfaceClass != USB_CLASS_PRINTER ||
 	    interface->bInterfaceSubClass != 1 ||
-	    (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1)||
+	    (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1) ||
 	    interface->bNumEndpoints > 2) {
 		return -1;
 	}
 
-	if ((interface->endpoint[0].bEndpointAddress & 0xf0) != 0x00 ||
-	    interface->endpoint[0].bmAttributes != 0x02 ||
-	    (interface->bNumEndpoints > 1 && (
-		    (interface->endpoint[1].bEndpointAddress & 0xf0) != 0x80 ||
-		    interface->endpoint[1].bmAttributes != 0x02))) {
+	/* Does this (these) interface(s) support bulk transfers? */
+	if ((interface->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+	      != USB_ENDPOINT_XFER_BULK) {
+		return -1;
+	}
+	if ((interface->bNumEndpoints > 1) &&
+	      ((interface->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+	      != USB_ENDPOINT_XFER_BULK)) {
 		return -1;
 	}
 
+	/*
+	 *  Does this interface have at least one OUT endpoint
+	 *  that we can write to: endpoint index 0 or 1?
+	 */
+	if ((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+	      != USB_DIR_OUT &&
+	    (interface->bNumEndpoints > 1 &&
+	      (interface->endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+	      != USB_DIR_OUT)) {
+ 		return -1;
+ 	}
+
 	for (i=0; i<MAX_PRINTERS; i++) {
 		if (!minor_data[i])
 			break;
 	}
 	if (i >= MAX_PRINTERS) {
+		printk("No minor table space available for USB Printer\n");
 		return -1;
 	}
 
 	printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum);
 
 	if (!(dev->private = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
-		printk( KERN_DEBUG "usb_printer: no memory!\n");
+		printk(KERN_DEBUG "usb_printer: no memory!\n");
 		return -1;
 	}
 
@@ -310,48 +322,63 @@
 	minor_data[i] = PPDATA(dev->private);
 	minor_data[i]->minor = i;
 	minor_data[i]->pusb_dev = dev;
-	/* The max packet size can't be more than 64 (& will be 64 for
-	 * any decent bulk device); this calculation was silly.  -greg
-	 * minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16;
-	 */
-	minor_data[i]->maxout = 8192;
-	if (minor_data[i]->maxout > PAGE_SIZE) {
-                minor_data[i]->maxout = PAGE_SIZE;
-	}
-	if (interface->bInterfaceProtocol != 2)
+	minor_data[i]->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE;
+	if (interface->bInterfaceProtocol != 2)		/* if not bidirectional */
 		minor_data[i]->noinput = 1;
-	else {
-		minor_data[i]->maxin = interface->endpoint[1].wMaxPacketSize;
+
+	minor_data[i]->bulk_out_index =
+		((interface->endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		  == USB_DIR_OUT) ? 0 : 1;
+	minor_data[i]->bulk_in_index = minor_data[i]->noinput ? -1 :
+		(minor_data[i]->bulk_out_index == 0) ? 1 : 0;
+	minor_data[i]->bulk_in_ep = minor_data[i]->noinput ? -1 :
+		interface->endpoint[minor_data[i]->bulk_in_index].bEndpointAddress &
+		USB_ENDPOINT_NUMBER_MASK;
+	minor_data[i]->bulk_out_ep =
+		interface->endpoint[minor_data[i]->bulk_out_index].bEndpointAddress &
+		USB_ENDPOINT_NUMBER_MASK;
+	if (interface->bInterfaceProtocol == 2) {	/* if bidirectional */
+		minor_data[i]->maxin =
+			interface->endpoint[minor_data[i]->bulk_in_index].wMaxPacketSize;
 	}
 
         if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 		printk(KERN_INFO "  Failed usb_set_configuration: printer\n");
 		return -1;
 	}
+
+	printk(KERN_INFO "USB Printer Summary:\n");
+	printk(KERN_INFO "index=%d, maxout=%d, noinput=%d\n",
+		i, minor_data[i]->maxout, minor_data[i]->noinput);
+	printk(KERN_INFO "bulk_in_ix=%d, bulk_in_ep=%d, bulk_out_ix=%d, bulk_out_ep=%d\n",
+		minor_data[i]->bulk_in_index,
+		minor_data[i]->bulk_in_ep,
+		minor_data[i]->bulk_out_index,
+		minor_data[i]->bulk_out_ep);
+
 #if 0
 	{
 		__u8 status;
 		__u8 ieee_id[64];
-		devrequest dr;
 
-		/* Lets get the device id if possible */
-		dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80;
-		dr.request = 0;
-		dr.value = 0;
-		dr.index = 0;
-		dr.length = sizeof(ieee_id) - 1;
-		if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1, HZ) == 0) {
+		/* Let's get the device id if possible. */
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
+		    USB_PRINTER_REQ_GET_DEVICE_ID,
+		    USB_TYPE_CLASS | USB_RT_INTERFACE | USB_DIR_IN,
+		    0, 0, ieee_id,
+		    sizeof(ieee_id)-1, HZ) == 0) {
 			if (ieee_id[1] < sizeof(ieee_id) - 1)
 				ieee_id[ieee_id[1]+2] = '\0';
 			else
 				ieee_id[sizeof(ieee_id)-1] = '\0';
-			printk(KERN_INFO "  Printer ID is %s\n", &ieee_id[2]);
+			printk(KERN_INFO "  USB Printer ID is %s\n",
+				&ieee_id[2]);
 		}
 		status = printer_read_status(PPDATA(dev->private));
 		printk(KERN_INFO "  Status is %s,%s,%s\n",
-		       (status & 0x10) ? "Selected" : "Not Selected",
-		       (status & 0x20) ? "No Paper" : "Paper",
-		       (status & 0x08) ? "No Error" : "Error");
+		       (status & LP_PSELECD) ? "Selected" : "Not Selected",
+		       (status & LP_POUTPA)  ? "No Paper" : "Paper",
+		       (status & LP_PERRORP) ? "No Error" : "Error");
 	}
 #endif
 	return 0;
@@ -397,7 +424,13 @@
 
 int usb_printer_init(void)
 {
-	usb_register(&printer_driver);
+	if (usb_register(&printer_driver)) {
+		printk(KERN_ERR "USB Printer driver cannot register: "
+			"minor number %d already in use\n",
+			printer_driver.minor);
+		return 1;
+	}
+
 	printk(KERN_INFO "USB Printer support registered.\n");
 	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.22/linux/drivers/usb/uhci.c	Fri Oct 15 15:25:14 1999
+++ linux/drivers/usb/uhci.c	Fri Oct 22 10:48:19 1999
@@ -91,7 +91,7 @@
 /*
  * Map status to standard result codes
  *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
  * <dir_out> is True for output TDs and False for input TDs.
  */
 static int uhci_map_status(int status, int dir_out)
@@ -127,7 +127,7 @@
 {
 	unsigned int status;
 	struct uhci_td *tmp;
-	int count = 1000, bytesreceived = 0;
+	int count = 1000, actlength, explength;
 
 	if (rval)
 		*rval = 0;
@@ -147,29 +147,26 @@
 
 		if (status)
 			break;
-#if 0
-		if (debug) {
-				/* Must reset the toggle on first error */
-    				if (uhci_debug) {
-					printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
-						(unsigned int)tmp, rval ? *rval : 0);
-				}
 
-				usb_settoggle(dev->usb, uhci_endpoint(tmp->info),
-					uhci_packetout(tmp->info) ^ 1,
-					uhci_toggle(tmp->info));
-				break;
-			}
-		} else {
-			if (rval && ((tmp->info & 0xFF) == USB_PID_IN))
-				*rval += uhci_actual_length(tmp->status);
-		}
-#endif
 		/* The length field is only valid if the TD was completed */
 		if (!(tmp->status & TD_CTRL_ACTIVE) && uhci_packetin(tmp->info)) {
-			bytesreceived += uhci_actual_length(tmp->status);
+			explength = uhci_expected_length(tmp->info);
+			actlength = uhci_actual_length(tmp->status);
 			if (rval)
-				*rval += uhci_actual_length(tmp->status);
+				*rval += actlength;
+			if (explength != actlength) {
+				/* Reset the data toggle on error. */
+				if (debug || uhci_debug)
+					printk(KERN_DEBUG "Set toggle from %p rval %ld%c for status=%x to %d, exp=%d, act=%d\n",
+						tmp, rval ? *rval : 0,
+						rval ? '*' : '/', tmp->status,
+						uhci_toggle(tmp->info) ^ 1,
+						explength, actlength);
+				usb_settoggle(dev->usb, uhci_endpoint(tmp->info),
+					uhci_packetout(tmp->info),
+					uhci_toggle(tmp->info) ^ 1);
+				break;	// Short packet
+			}
 		}
 
 		if ((tmp->link & UHCI_PTR_TERM) ||
@@ -190,26 +187,24 @@
 		if (!status)
 			return USB_ST_NOERROR;
 
-		/* XXX FIXME APC BackUPS Pro kludge */
+		/* APC BackUPS Pro kludge */
 		/* It tries to send all of the descriptor instead of */
 		/*  the amount we requested */
 		if (tmp->status & TD_CTRL_IOC &&
 		    tmp->status & TD_CTRL_ACTIVE &&
-		    tmp->status & TD_CTRL_NAK /* && its a control TD */)
+		    tmp->status & TD_CTRL_NAK &&
+		    tmp->pipetype == PIPE_CONTROL)
 			return USB_ST_NOERROR;
 
-#if 0
 		/* We got to an error, but the controller hasn't finished */
-		/*  with it, yet */
+		/*  with it yet. */
 		if (tmp->status & TD_CTRL_ACTIVE)
 			return USB_ST_NOCHANGE;
-#endif
 
 		/* If this wasn't the last TD and SPD is set, ACTIVE */
 		/*  is not and NAK isn't then we received a short */
 		/*  packet */
-		if (tmp->status & TD_CTRL_SPD &&
-		    !(tmp->status & TD_CTRL_NAK))
+		if (tmp->status & TD_CTRL_SPD && !(tmp->status & TD_CTRL_NAK))
 			return USB_ST_NOERROR;
 	}
 
@@ -516,7 +511,7 @@
  * bit set. Maybe it could be extended to handle the QH's also,
  * but it doesn't seem necessary right now.
  * The layout looks as follows:
- * frame list pointer -> iso td's (if any) -> 
+ * frame list pointer -> iso td's (if any) ->
  * periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh
  */
 
@@ -532,7 +527,7 @@
 	td->backptr = &uhci->fl->frame[framenum];
 	td->link = uhci->fl->frame[framenum];
 	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
-		nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+		nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
 		nexttd->backptr = &td->link;
 	}
 	wmb();
@@ -550,7 +545,7 @@
 	spin_lock_irqsave(&framelist_lock, flags);
 	*(td->backptr) = td->link;
 	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
-		nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+		nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
 		nexttd->backptr = td->backptr;
 	}
 	spin_unlock_irqrestore(&framelist_lock, flags);
@@ -568,7 +563,7 @@
 		unsigned frn = inw(uhci->io_addr + USBFRNUM);
 		__u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES];
 		if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
-			struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15);
+			struct uhci_td *tdl = (struct uhci_td *)uhci_ptr_to_virt(link);
 			for (;;) {
 				if (tdl == td) {
 					printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n");
@@ -576,9 +571,9 @@
 				}
 				if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH))
 					break;
-				tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15);
+				tdl = (struct uhci_td *)uhci_ptr_to_virt(tdl->link);
 			}
-		}	
+		}
 	}
 }
 
@@ -603,6 +598,7 @@
 	/* Remove it from the skeleton */
 	uhci_remove_qh(td->qh->skel, td->qh);
 	uhci_qh_free(td->qh);
+
 	do {
 		nextlink = curtd->link;
 
@@ -612,10 +608,11 @@
 
 		uhci_remove_td(curtd);
 		uhci_td_free(curtd);
+
 		if (nextlink & UHCI_PTR_TERM)	/* Tail? */
 			break;
 
-		curtd = bus_to_virt(nextlink & ~UHCI_PTR_BITS);
+		curtd = (struct uhci_td *)uhci_ptr_to_virt(nextlink);
 		if (!--maxcount) {
 			printk(KERN_ERR "runaway td's!?\n");
 			break;
@@ -624,7 +621,7 @@
 }
 
 /*
- * Request a interrupt handler..
+ * Request an interrupt handler..
  *
  * Returns 0 (success) or negative (failure).
  * Also returns/sets a "handle pointer" that release_irq can use to stop this
@@ -665,9 +662,8 @@
 	td->bandwidth_alloc = bustime;
 
 	/* if period 0, set _REMOVE flag */
-	if (period == 0) {
+	if (!period)
 		td->flags |= UHCI_TD_REMOVE;
-	}
 
 	qh->skel = &dev->uhci->skelqh[__interval_to_skel(period)];
 
@@ -690,7 +686,7 @@
  *
  * This function can NOT be called from an interrupt.
  */
-int uhci_release_irq(struct usb_device *usb, void *handle)
+static int uhci_release_irq(struct usb_device *usb, void *handle)
 {
 	struct uhci_td *td;
 	struct uhci_qh *qh;
@@ -699,12 +695,13 @@
 	if (!td)
 		return USB_ST_INTERNALERROR;
 
+	qh = td->qh;
+
 	/* Remove it from the internal irq_list */
 	uhci_remove_irq_list(td);
 
 	/* Remove the interrupt TD and QH */
 	uhci_remove_td(td);
-	qh = td->qh;
 	uhci_remove_qh(qh->skel, qh);
 
 	if (td->completed != NULL)
@@ -744,7 +741,7 @@
  */
 static int uhci_init_isoc (struct usb_device *usb_dev,
 				unsigned int pipe,
-				int frame_count,        /* bandwidth % = 100 * this / 1000 */
+				int frame_count,        /* bandwidth % = 100 * this / 1024 */
 				void *context,
 				struct usb_isoc_desc **isocdesc)
 {
@@ -896,7 +893,7 @@
 			}
 		} /* end START_RELATIVE */
 		else
-  		if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
+		if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
 			ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame);
 			if (ix < START_FRAME_FUDGE || /* too small */
 			    ix > CAN_SCHEDULE_FRAMES) { /* too large */
@@ -999,6 +996,7 @@
 		td->completed = isocdesc->callback_fn;
 		uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc); /* TBD: D.K. ??? */
 	}
+
 	return 0;
 } /* end uhci_run_isoc */
 
@@ -1028,6 +1026,7 @@
 	}
 
 	for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) {
+		/* Deactivate and unlink */
 		uhci_remove_frame_list(uhci, td);
 		td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
 	} /* end for ix */
@@ -1044,9 +1043,9 @@
 	if (isocdesc->start_frame >= 0)
 		uhci_kill_isoc(isocdesc);
 
-	/* Remove all td's from the IRQ list. */
-	for(i = 0; i < isocdesc->frame_count; i++)
-		uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i);
+	/* Remove all TD's from the IRQ list. */
+	for (i = 0; i < isocdesc->frame_count; i++)
+		uhci_remove_irq_list(((struct uhci_td *)isocdesc->td) + i);
 
 	/* Free the associate memory. */
 	if (isocdesc->td)
@@ -1137,7 +1136,8 @@
  * there is no restriction on length of transfers
  * anymore
  */
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout)
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd,
+				void *data, int len, int timeout)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_td *first, *td, *prevtd;
@@ -1147,6 +1147,9 @@
 	__u32 nextlink;
 	unsigned long bytesrequested = len;
 	unsigned long bytesread = 0;
+#ifdef DUMP_RAW
+	unsigned char *orig_data = (unsigned char *) data;
+#endif
 
 	first = td = uhci_td_alloc(dev);
 	if (!td)
@@ -1176,8 +1179,10 @@
 
 	prevtd = td;
 	td = uhci_td_alloc(dev);
-	if (!td)
-		return -ENOMEM;
+	if (!td) {
+		uhci_td_free(prevtd);
+ 		return -ENOMEM;
+	}
 
 	prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
 
@@ -1261,9 +1266,29 @@
 	if (uhci_debug && ret) {
 		__u8 *p = (__u8 *)cmd;
 
+		printk("dev %d, pipe %X requested %ld bytes, got %ld, status=%d:\n",
+			usb_dev->devnum, pipe, bytesrequested, bytesread, ret);
 		printk(KERN_DEBUG "Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
 		       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
 	}
+
+#ifdef DUMP_RAW
+	if (!ret && usb_pipein(pipe)) {	/* good Input control msg */
+		int i;
+
+		printk (KERN_CRIT "ctrl msg [%02x %02x %04x %04x %04x] on pipe %x returned:\n",
+			cmd->requesttype, cmd->request,
+			cmd->value, cmd->index, cmd->length, pipe);
+		for (i = 0; i < bytesrequested; ) {
+			printk(" %02x", orig_data[i]);
+			if (++i % 16 == 0)
+				printk("\n");
+		}
+		if (i % 16 != 0)
+			printk("\n");
+	}
+#endif
+
 	return ret;
 }
 
@@ -1344,7 +1369,7 @@
 	if (!td)
 		return -ENOMEM;
 
-        prevtd = first; //This is fake, but at least it's not NULL
+	prevtd = first;		// This is fake, but at least it's not NULL
 	while (len > 0) {
 		/* Build the TD for control status */
 		int pktsze = len;
@@ -1376,7 +1401,7 @@
 		usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 	}
 
-	td->link = 1;				/* Terminate */
+	td->link = UHCI_PTR_TERM;			/* Terminate */
 	td->status |= TD_CTRL_IOC;
 
 	/* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
@@ -1619,7 +1644,6 @@
 	} while (nr < maxchild);
 }
 
-#if 0
 static int fixup_isoc_desc (struct uhci_td *td)
 {
 	struct usb_isoc_desc    *isocdesc = td->dev_id;
@@ -1647,7 +1671,7 @@
 		if ((frm->frame_status = uhci_map_status (uhci_status_bits (prtd->status),
 		    uhci_packetout (prtd->info))))
 			isocdesc->error_count++;
-             
+
 		prtd++;
 		frm++;
 		if (++fx >= isocdesc->frame_count) {    /* wrap fx, prtd, and frm */
@@ -1671,8 +1695,106 @@
 
 	return 0;
 }
-#endif /* 0 */
 
+int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval)
+{
+	struct usb_isoc_desc *isocdesc = td->dev_id;
+	int ret;
+
+	/*
+	 * Fixup the isocdesc for the driver:  total_completed_frames,
+	 * error_count, total_length, frames array.
+	 *
+	 * ret = callback_fn (int error_count, void *buffer,
+	 * 		      int len, void *isocdesc);
+	 */
+
+	fixup_isoc_desc (td);
+
+	ret = td->completed (isocdesc->error_count, bus_to_virt (td->buffer),
+				isocdesc->total_length, isocdesc);
+
+	/*
+	 * Isoc. handling of return value from td->completed (callback function)
+	 */
+
+	switch (ret) {
+	case CB_CONTINUE:       /* similar to the REMOVE condition below */
+		/* TBD */
+		uhci_td_free (td);
+		break;
+
+	case CB_REUSE:          /* similar to the re-add condition below,
+				 * but Not ACTIVE */
+		/* TBD */
+		/* usb_dev = td->dev->usb; */
+
+		list_add(&td->irq_list, &uhci->interrupt_list);
+
+		td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK |
+				TD_CTRL_LS | TD_CTRL_IOS | TD_CTRL_IOC)) |
+				TD_CTRL_IOC;
+
+		/* The HC removes it, so re-add it */
+		/* Insert into a QH? */
+		uhci_insert_td_in_qh(td->qh, td);
+		break;
+
+	case CB_RESTART:        /* similar to re-add, but mark ACTIVE */
+		/* TBD */
+		/* usb_dev = td->dev->usb; */
+
+		list_add(&td->irq_list, &uhci->interrupt_list);
+
+		td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK |
+				TD_CTRL_LS | TD_CTRL_IOS | TD_CTRL_IOC)) |
+				TD_CTRL_ACTIVE | TD_CTRL_IOC;
+
+		/* The HC removes it, so re-add it */
+		uhci_insert_td_in_qh(td->qh, td);
+		break;
+
+	case CB_ABORT:          /* kill/abort */
+		/* TBD */
+		uhci_kill_isoc (isocdesc);
+		break;
+	} /* end isoc. TD switch */
+
+	return 0;
+}
+
+int uhci_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval)
+{
+	if (td->completed(status, bus_to_virt(td->buffer), rval, td->dev_id)) {
+		struct usb_device *usb_dev = td->dev->usb;
+
+		list_add(&td->irq_list, &uhci->interrupt_list);
+
+		usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info));
+		td->info &= ~(1 << TD_TOKEN_TOGGLE);	/* clear data toggle */
+		td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info),
+			uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */
+		td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+		/* The HC only removes it when it completed */
+		/* successfully, so force remove and re-add it. */
+		uhci_remove_td(td);
+		uhci_insert_td_in_qh(td->qh, td);
+	} else if (td->flags & UHCI_TD_REMOVE) {
+		struct usb_device *usb_dev = td->dev->usb;
+
+		/* marked for removal */
+		td->flags &= ~UHCI_TD_REMOVE;
+		usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info));
+		uhci_remove_qh(td->qh->skel, td->qh);
+		uhci_qh_free(td->qh);
+		if (td->pipetype == PIPE_INTERRUPT)
+			usb_release_bandwidth(usb_dev, td->bandwidth_alloc);
+		uhci_td_free(td);
+	}
+
+	return 0;
+}
+ 
 static void uhci_interrupt_notify(struct uhci *uhci)
 {
 	struct list_head *tmp, *head = &uhci->interrupt_list;
@@ -1690,39 +1812,18 @@
 		/*  TD's completed successfully */
 		status = uhci_td_result(td->dev, td, &rval, 0);
 
-		if ((status == USB_ST_NOERROR) && (td->status & TD_CTRL_ACTIVE))
+		if (status == USB_ST_NOCHANGE)
 			continue;
 
 		/* remove from IRQ list */
 		list_del(&td->irq_list);
 		INIT_LIST_HEAD(&td->irq_list);
 
-		if (td->completed(status, bus_to_virt(td->buffer), rval,
-		    td->dev_id)) {
-			struct usb_device *usb_dev = td->dev->usb;
-
-			list_add(&td->irq_list, &uhci->interrupt_list);
-
-			usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
-			td->info &= ~(1 << 19); /* clear data toggle */
-			td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info),
-				uhci_packetout(td->info)) << 19; /* toggle between data0 and data1 */
-			td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-			/* The HC only removes it when it completed */
-			/* successfully, so force remove and re-add it */
-			uhci_remove_td(td);
-			uhci_insert_td_in_qh(td->qh, td);
-		} else if (td->flags & UHCI_TD_REMOVE) {
-			struct usb_device *usb_dev = td->dev->usb;
-
-			/* marked for removal */
-			td->flags &= ~UHCI_TD_REMOVE;
-			usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), uhci_packetout(td->info));
-			uhci_remove_qh(td->qh->skel, td->qh);
-			uhci_qh_free(td->qh);
-			uhci_td_free(td);
-			if (td->pipetype == PIPE_INTERRUPT)
-				usb_release_bandwidth(usb_dev, td->bandwidth_alloc);
+		if (td->pipetype == PIPE_ISOCHRONOUS) {
+			uhci_isoc_callback(uhci, td, status, rval);
+		}
+		else {
+			uhci_callback(uhci, td, status, rval);
 		}
 
 		/* If completed does not wants to reactivate, then */
@@ -1800,7 +1901,8 @@
 	td->link = uhci->fl->frame[0];
 	td->backptr = &uhci->fl->frame[0];
 	td->status = TD_CTRL_IOC;
-	td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN;	/* (ignored) input packet, 16 bytes, device 127 */
+	td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN;
+		/* (ignored) input packet, 16 bytes, device 127 */
 	td->buffer = 0;
 	td->qh = NULL;
 	td->pipetype = -1;
@@ -1843,7 +1945,8 @@
 	}
 
 	/* Turn on all interrupts */
-	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+		io_addr + USBINTR);
 
 	/* Start at frame 0 */
 	outw(0, io_addr + USBFRNUM);
@@ -2168,6 +2271,8 @@
 
                 /* disable legacy emulation */
                 pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+		pci_enable_device(dev);
 
 		return found_uhci(dev->irq, io_addr, io_size);
 	}
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.22/linux/drivers/usb/uhci.h	Fri Oct 15 15:25:14 1999
+++ linux/drivers/usb/uhci.h	Fri Oct 22 10:48:19 1999
@@ -125,6 +125,7 @@
 #define TD_TOKEN_TOGGLE		19
 
 #define uhci_maxlen(token)	((token) >> 21)
+#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ 
 #define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
 #define uhci_endpoint(token)	(((token) >> 15) & 0xf)
 #define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
@@ -181,12 +182,6 @@
  */
 struct uhci;
 
-#if 0
-#define UHCI_MAXTD	64
-
-#define UHCI_MAXQH	16
-#endif
-
 /* The usb device part must be first! Not anymore -jerdfelt */
 struct uhci_device {
 	struct usb_device	*usb;
@@ -194,10 +189,6 @@
 	atomic_t		refcnt;
 
 	struct uhci		*uhci;
-#if 0
-	struct uhci_qh		qh[UHCI_MAXQH];		/* These are the "common" qh's for each device */
-	struct uhci_td		td[UHCI_MAXTD];
-#endif
 
 	unsigned long		data[16];
 };
@@ -278,7 +269,7 @@
  * and we should meet that frequency when requested to do so.
  * This will require some change(s) to the UHCI skeleton.
  */
-static inline int __interval_to_skel(interval)
+static inline int __interval_to_skel(int interval)
 {
 	if (interval < 16) {
 		if (interval < 4) {
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.22/linux/drivers/usb/usb.c	Fri Oct 15 15:25:14 1999
+++ linux/drivers/usb/usb.c	Sat Oct 16 19:15:32 1999
@@ -789,10 +789,7 @@
 	dr.index = 1;
 	dr.length = 0;
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
-		return -1;
-
-	return 0;
+	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ);
 }
 
 /* keyboards want a nonzero duration according to HID spec, but
@@ -807,10 +804,7 @@
 	dr.index = 1;
 	dr.length = 0;
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
-		return -1;
-
-	return 0;
+	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ);
 }
 
 static void usb_set_maxpacket(struct usb_device *dev)
@@ -873,8 +867,8 @@
 
 	if (result)
 	    return result;
-	if (status & 1)
-	    return 1;		/* still halted */
+	if (status & 1)		/* endpoint status is Halted */
+	    return USB_ST_STALL;		/* still halted */
 #endif
 	usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp));
 
@@ -888,6 +882,7 @@
 int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 {
 	devrequest dr;
+	int err;
 
 	dr.requesttype = 1;
 	dr.request = USB_REQ_SET_INTERFACE;
@@ -895,8 +890,9 @@
 	dr.index = interface;
 	dr.length = 0;
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
-		return -1;
+	err = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ);
+	if (err)
+		return err;
 
 	dev->ifnum = interface;
 	dev->actconfig->interface[interface].act_altsetting = alternate;
@@ -946,10 +942,7 @@
 	dr.index = index;
 	dr.length = size;
 
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ))
-		return -1;
-
-	return 0;
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ);
 }
 
 int usb_get_configuration(struct usb_device *dev)
@@ -1056,10 +1049,13 @@
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
  * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
  */
 int usb_new_device(struct usb_device *dev)
 {
 	int addr;
+	int err;
 
 	printk(KERN_INFO "USB new device connect, assigned device number %d\n",
 		dev->devnum);
@@ -1073,8 +1069,10 @@
 	dev->devnum = 0;
 
 	/* Slow devices */
-	if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) {
-		printk(KERN_ERR "usbcore: USB device not responding, giving up\n");
+	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+	if (err) {
+		printk(KERN_ERR "usbcore: USB device not responding, giving up (error=%d)\n",
+			err);
 		dev->devnum = -1;
 		return 1;
 	}
@@ -1090,16 +1088,20 @@
 
 	dev->devnum = addr;
 
-	if (usb_set_address(dev)) {
-		printk(KERN_ERR "usbcore: USB device not accepting new address\n");
+	err = usb_set_address(dev);
+	if (err) {
+		printk(KERN_ERR "usbcore: USB device not accepting new address (error=%d)\n",
+			err);
 		dev->devnum = -1;
 		return 1;
 	}
 
 	wait_ms(10);	/* Let the SET_ADDRESS settle */
 
-	if (usb_get_device_descriptor(dev)) {
-		printk(KERN_ERR "usbcore: unable to get device descriptor\n");
+	err = usb_get_device_descriptor(dev);
+	if (err) {
+		printk(KERN_ERR "usbcore: unable to get device descriptor (error=%d)\n",
+			err);
 		dev->devnum = -1;
 		return 1;
 	}
@@ -1324,7 +1326,6 @@
 	if (register_chrdev(180,"usb",&usb_fops)) {
 		printk("unable to get major %d for usb devices\n",
 		       MISC_MAJOR);
-		return -EIO;
 	}
 }
 
diff -u --recursive --new-file v2.3.22/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.22/linux/drivers/usb/usb.h	Fri Oct 15 15:25:14 1999
+++ linux/drivers/usb/usb.h	Fri Oct 22 10:48:19 1999
@@ -199,31 +199,32 @@
 } devrequest __attribute__ ((packed));
 
 /* 
- * Status codes (these follow OHCI controllers condition codes)
+ * Status codes (these [used to] follow OHCI controllers condition codes)
  */
-#define USB_ST_NOERROR		0x0
-#define USB_ST_CRC		0x1
-#define USB_ST_BITSTUFF		0x2
-#define USB_ST_DTMISMATCH	0x3	/* data toggle mismatch */
-#define USB_ST_STALL		0x4
-#define USB_ST_NORESPONSE	0x5	/* device not responding/handshaking */
-#define USB_ST_PIDCHECK		0x6	/* Check bits on PID failed */
-#define USB_ST_PIDUNDEF		0x7	/* PID unexpected/undefined */
-#define USB_ST_DATAOVERRUN	0x8
-#define USB_ST_DATAUNDERRUN	0x9
-#define USB_ST_RESERVED1	0xA
-#define USB_ST_RESERVED2	0xB
-#define USB_ST_BUFFEROVERRUN	0xC
-#define USB_ST_BUFFERUNDERRUN	0xD
-#define USB_ST_RESERVED3	0xE
-#define USB_ST_RESERVED4	0xF
+#define USB_ST_NOERROR		0
+#define USB_ST_CRC		-1
+#define USB_ST_BITSTUFF		-2
+#define USB_ST_DTMISMATCH	-3	/* data toggle mismatch */
+#define USB_ST_STALL		-4
+#define USB_ST_NORESPONSE	-5	/* device not responding/handshaking */
+#define USB_ST_PIDCHECK		-6	/* Check bits on PID failed */
+#define USB_ST_PIDUNDEF		-7	/* PID unexpected/undefined */
+#define USB_ST_DATAOVERRUN	-8
+#define USB_ST_DATAUNDERRUN	-9
+#define USB_ST_RESERVED1	-10
+#define USB_ST_RESERVED2	-11
+#define USB_ST_BUFFEROVERRUN	-12
+#define USB_ST_BUFFERUNDERRUN	-13
+#define USB_ST_RESERVED3	-14
+#define USB_ST_RESERVED4	-15
 
 /* internal errors */
-#define USB_ST_REMOVED		0x100
-#define USB_ST_TIMEOUT		0x110
-#define USB_ST_INTERNALERROR	-1
-#define USB_ST_NOTSUPPORTED	-2
-#define USB_ST_BANDWIDTH_ERROR	-3
+#define USB_ST_REMOVED		-100
+#define USB_ST_TIMEOUT		-101
+#define USB_ST_INTERNALERROR	-200
+#define USB_ST_NOTSUPPORTED	-201
+#define USB_ST_BANDWIDTH_ERROR	-202
+#define USB_ST_NOCHANGE		-203
 
 
 /*
@@ -684,7 +685,6 @@
 int usb_set_protocol(struct usb_device *dev, int protocol);
 int usb_set_interface(struct usb_device *dev, int interface, int alternate);
 int usb_set_idle(struct usb_device *dev, int duration, int report_id);
-int usb_set_interface(struct usb_device *dev, int interface, int alternate);
 int usb_set_configuration(struct usb_device *dev, int configuration);
 int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size);
 char *usb_string(struct usb_device *dev, int index);
@@ -722,7 +722,7 @@
 void usb_show_string(struct usb_device *dev, char *id, int index);
 
 #ifdef USB_DEBUG
-#define PRINTD(format, args...) printk("usb: " format "\n" , ## args);
+#define PRINTD(format, args...) printk(KERN_DEBUG "usb: " format "\n" , ## args);
 #else /* NOT DEBUGGING */
 #define PRINTD(fmt, arg...) do {} while (0)
 #endif /* USB_DEBUG */
diff -u --recursive --new-file v2.3.22/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.22/linux/drivers/video/Config.in	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/Config.in	Mon Oct 18 18:05:08 1999
@@ -96,6 +96,7 @@
 	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
 	 fi
 	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
+	 bool '  ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
 	 bool '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
       fi
    fi
diff -u --recursive --new-file v2.3.22/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.22/linux/drivers/video/Makefile	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/Makefile	Mon Oct 18 18:05:08 1999
@@ -113,6 +113,10 @@
   endif
 endif
 
+ifeq ($(CONFIG_FB_ATY128),y)
+L_OBJS += aty128fb.o
+endif
+
 ifeq ($(CONFIG_FB_IGA),y)
 L_OBJS += igafb.o
 endif
diff -u --recursive --new-file v2.3.22/linux/drivers/video/aty128.h linux/drivers/video/aty128.h
--- v2.3.22/linux/drivers/video/aty128.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty128.h	Mon Oct 18 11:37:43 1999
@@ -0,0 +1,594 @@
+/*  $Id: aty128.h,v 1.1 1999/10/12 11:00:40 geert Exp $
+ *  linux/drivers/video/aty128.h
+ *  Register definitions for ATI Rage128 boards
+ *
+ *  Anthony Tong <atong@uiuc.edu>, 1999
+ */
+
+#ifndef REG_RAGE128_H
+#define REG_RAGE128_H
+
+#define MM_INDEX				0x0000
+#define MM_DATA					0x0004
+#define CLOCK_CNTL_INDEX			0x0008
+#define CLOCK_CNTL_DATA				0x000c
+#define BIOS_0_SCRATCH				0x0010
+#define BIOS_1_SCRATCH				0x0014
+#define BIOS_2_SCRATCH				0x0018
+#define BIOS_3_SCRATCH				0x001c
+#define BUS_CNTL				0x0030
+#define BUS_CNTL1				0x0034
+#define MEM_VGA_WP_SEL				0x0038
+#define MEM_VGA_RP_SEL				0x003c
+#define GEN_INT_CNTL				0x0040
+#define GEN_INT_STATUS				0x0044
+#define CRTC_GEN_CNTL				0x0050
+#define CRTC_EXT_CNTL				0x0054
+#define DAC_CNTL				0x0058
+#define CRTC_STATUS				0x005c
+#define GPIO_MONID				0x0068
+#define I2C_CNTL_1				0x0094
+#define PALETTE_INDEX				0x00b0
+#define PALETTE_DATA				0x00b4
+#define CONFIG_CNTL				0x00e0
+#define CONFIG_XSTRAP				0x00e4
+#define CONFIG_BONDS				0x00e8
+#define GEN_RESET_CNTL				0x00f0
+#define GEN_STATUS				0x00f4
+#define CONFIG_MEMSIZE				0x00f8
+#define CONFIG_APER_0_BASE			0x0100
+#define CONFIG_APER_1_BASE			0x0104
+#define CONFIG_APER_SIZE			0x0108
+#define CONFIG_REG_1_BASE			0x010c
+#define CONFIG_REG_APER_SIZE			0x0110
+#define CONFIG_MEMSIZE_EMBEDDED			0x0114
+#define TEST_DEBUG_CNTL				0x0120
+#define TEST_DEBUG_MUX				0x0124
+#define HW_DEBUG				0x0128
+#define TEST_DEBUG_OUT				0x012c
+#define HOST_PATH_CNTL				0x0130
+#define SW_SEMAPHORE				0x013c
+#define MEM_CNTL				0x0140
+#define EXT_MEM_CNTL				0x0144
+#define MEM_ADDR_CONFIG				0x0148
+#define MEM_INTF_CNTL				0x014c
+#define MEM_STR_CNTL				0x0150
+#define MEM_INIT_LAT_TIMER			0x0154
+#define MEM_SDRAM_MODE_REG			0x0158
+#define AGP_BASE				0x0170
+#define AGP_CNTL				0x0174
+#define AGP_APER_OFFSET				0x0178
+#define PCI_GART_PAGE				0x017c
+#define PC_NGUI_MODE				0x0180
+#define PC_NGUI_CTLSTAT				0x0184
+#define VIDEOMUX_CNTL				0x0190
+#define MPP_TB_CONFIG				0x01C0
+#define MPP_GP_CONFIG				0x01C8
+#define VIPH_CONTROL				0x01D0
+#define CRTC_H_TOTAL_DISP			0x0200
+#define CRTC_H_SYNC_STRT_WID			0x0204
+#define CRTC_V_TOTAL_DISP			0x0208
+#define CRTC_V_SYNC_STRT_WID			0x020c
+#define CRTC_VLINE_CRNT_VLINE			0x0210
+#define CRTC_CRNT_FRAME				0x0214
+#define CRTC_GUI_TRIG_VLINE			0x0218
+#define CRTC_DEBUG				0x021c
+#define CRTC_OFFSET				0x0224
+#define CRTC_OFFSET_CNTL			0x0228
+#define CRTC_PITCH				0x022c
+#define OVR_CLR					0x0230
+#define OVR_WID_LEFT_RIGHT			0x0234
+#define OVR_WID_TOP_BOTTOM			0x0238
+#define SNAPSHOT_VH_COUNTS			0x0240
+#define SNAPSHOT_F_COUNT			0x0244
+#define N_VIF_COUNT				0x0248
+#define SNAPSHOT_VIF_COUNT			0x024c
+#define CUR_OFFSET				0x0260
+#define CUR_HORZ_VERT_POSN			0x0264
+#define CUR_HORZ_VERT_OFF			0x0268
+#define CUR_CLR0				0x026c
+#define CUR_CLR1				0x0270
+#define DAC_CRC_SIG				0x02cc
+#define DDA_CONFIG				0x02e0
+#define DDA_ON_OFF				0x02e4
+#define VGA_DDA_CONFIG				0x02e8
+#define VGA_DDA_ON_OFF				0x02ec
+#define OV0_Y_X_START				0x0400
+#define OV0_Y_X_END				0x0404
+#define OV0_EXCLUSIVE_HORZ			0x0408
+#define OV0_EXCLUSIVE_VERT			0x040c
+#define OV0_REG_LOAD_CNTL			0x0410
+#define OV0_SCALE_CNTL				0x0420
+#define OV0_V_INC				0x0424
+#define OV0_P1_V_ACCUM_INIT			0x0428
+#define OV0_P23_V_ACCUM_INIT			0x042c
+#define OV0_P1_BLANK_LINES_AT_TOP		0x0430
+#define OV0_P23_BLANK_LINES_AT_TOP		0x0434
+#define OV0_VID_BUF0_BASE_ADRS			0x0440
+#define OV0_VID_BUF1_BASE_ADRS			0x0444
+#define OV0_VID_BUF2_BASE_ADRS			0x0448
+#define OV0_VID_BUF3_BASE_ADRS			0x044c
+#define OV0_VID_BUF4_BASE_ADRS			0x0450
+#define OV0_VID_BUF5_BASE_ADRS			0x0454
+#define OV0_VID_BUF_PITCH0_VALUE		0x0460
+#define OV0_VID_BUF_PITCH1_VALUE		0x0464
+#define OV0_OCTWORDS_PER_LINE_M1		0x046c
+#define OV0_AUTO_FLIP_CNTRL			0x0470
+#define OV0_DEINTERLACE_PATTERN			0x0474
+#define OV0_H_INC				0x0480
+#define OV0_STEP_BY				0x0484
+#define OV0_P1_H_ACCUM_INIT			0x0488
+#define OV0_P23_H_ACCUM_INIT			0x048c
+#define OV0_P1_X_START_END			0x0494
+#define OV0_P2_X_START_END			0x0498
+#define OV0_P3_X_START_END			0x049c
+#define OV0_FILTER_CNTL				0x04a0
+#define OV0_FOUR_TAP_COEF_0			0x04b0
+#define OV0_FOUR_TAP_COEF_1			0x04b4
+#define OV0_FOUR_TAP_COEF_2			0x04b8
+#define OV0_FOUR_TAP_COEF_3			0x04bc
+#define OV0_FOUR_TAP_COEF_4			0x04c0
+#define OV0_COLOR_CNTL				0x04e0
+#define OV0_VIDEO_KEY_CLR			0x04e4
+#define OV0_VIDEO_KEY_MASK			0x04e8
+#define OV0_GRAPHICS_KEY_CLR			0x04ec
+#define OV0_GRAPHICS_KEY_MASK			0x04f0
+#define OV0_KEY_CNTL				0x04f4
+#define OV0_TEST				0x04f8
+#define SUBPIC_CNTL				0x0540
+#define PM4_BUFFER_OFFSET			0x0700
+#define PM4_BUFFER_CNTL				0x0704
+#define PM4_BUFFER_WM_CNTL			0x0708
+#define PM4_BUFFER_DL_RPTR_ADDR			0x070c
+#define PM4_BUFFER_DL_RPTR			0x0710
+#define PM4_BUFFER_DL_WPTR			0x0714
+#define PM4_VC_FPU_SETUP			0x071c
+#define PM4_FPU_CNTL				0x0720
+#define PM4_VC_FORMAT				0x0724
+#define PM4_VC_CNTL				0x0728
+#define PM4_VC_I01				0x072c
+#define PM4_VC_VLOFF				0x0730
+#define PM4_VC_VLSIZE				0x0734
+#define PM4_IW_INDOFF				0x0738
+#define PM4_IW_INDSIZE				0x073c
+#define PM4_FPU_FPX0				0x0740
+#define CRC_CMDFIFO_ADDR			0x0740
+#define PM4_FPU_FPY0				0x0744
+#define CRC_CMDFIFO_DOUT			0x0744
+#define PM4_FPU_FPX1				0x0748
+#define PM4_FPU_FPY1				0x074c
+#define PM4_FPU_FPX2				0x0750
+#define PM4_FPU_FPY2				0x0754
+#define PM4_FPU_FPY3				0x0758
+#define PM4_FPU_FPY4				0x075c
+#define PM4_FPU_FPY5				0x0760
+#define PM4_FPU_FPY6				0x0764
+#define PM4_FPU_FPR				0x0768
+#define PM4_FPU_FPG				0x076c
+#define PM4_FPU_FPB				0x0770
+#define PM4_FPU_FPA				0x0774
+#define PM4_FPU_INTXY0				0x0780
+#define PM4_FPU_INTXY1				0x0784
+#define PM4_FPU_INTXY2				0x0788
+#define PM4_FPU_INTARGB				0x078c
+#define PM4_FPU_FPTWICEAREA			0x0790
+#define PM4_FPU_DMAJOR01			0x0794
+#define PM4_FPU_DMAJOR12			0x0798
+#define PM4_FPU_DMAJOR02			0x079c
+#define PM4_FPU_STAT				0x07a0
+#define PM4_STAT				0x07b8
+#define PM4_TEST_CNTL				0x07d0
+#define PM4_MICROCODE_ADDR			0x07d4
+#define PM4_MICROCODE_RADDR			0x07d8
+#define PM4_MICROCODE_DATAH			0x07dc
+#define PM4_MICROCODE_DATAL			0x07e0
+#define PM4_CMDFIFO_ADDR			0x07e4
+#define PM4_CMDFIFO_DATAH			0x07e8
+#define PM4_CMDFIFO_DATAL			0x07ec
+#define PM4_BUFFER_ADDR				0x07f0
+#define PM4_BUFFER_DATAH			0x07f4
+#define PM4_BUFFER_DATAL			0x07f8
+#define PM4_MICRO_CNTL				0x07fc
+#define VID_BUFFER_CONTROL			0x0900
+#define CAP_INT_CNTL				0x0908
+#define CAP_INT_STATUS				0x090c
+#define CAP0_BUF0_OFFSET			0x0920
+#define CAP0_BUF1_OFFSET			0x0924
+#define CAP0_BUF0_EVEN_OFFSET			0x0928
+#define CAP0_BUF1_EVEN_OFFSET			0x092c
+#define CAP0_BUF_PITCH				0x0930
+#define CAP0_V_WINDOW				0x0934
+#define CAP0_H_WINDOW				0x0938
+#define CAP0_VBI_ODD_OFFSET			0x093c
+#define CAP0_VBI_EVEN_OFFSET			0x0940
+#define CAP0_VBI_V_WINDOW			0x0944
+#define CAP0_VBI_H_WINDOW			0x0948
+#define CAP0_PORT_MODE_CNTL			0x094c
+#define CAP0_TRIG_CNTL				0x0950
+#define CAP0_DEBUG				0x0954
+#define CAP0_CONFIG				0x0958
+#define CAP0_ANC_ODD_OFFSET			0x095c
+#define CAP0_ANC_EVEN_OFFSET			0x0960
+#define CAP0_ANC_H_WINDOW			0x0964
+#define CAP0_VIDEO_SYNC_TEST			0x0968
+#define CAP0_ONESHOT_BUF_OFFSET			0x096c
+#define CAP0_BUF_STATUS				0x0970
+#define CAP0_DWNSC_XRATIO			0x0978
+#define CAP0_XSHARPNESS				0x097c
+#define CAP1_BUF0_OFFSET			0x0990
+#define CAP1_BUF1_OFFSET			0x0994
+#define CAP1_BUF0_EVEN_OFFSET			0x0998
+#define CAP1_BUF1_EVEN_OFFSET			0x099c
+#define CAP1_BUF_PITCH				0x09a0
+#define CAP1_V_WINDOW				0x09a4
+#define CAP1_H_WINDOW				0x09a8
+#define CAP1_VBI_ODD_OFFSET			0x09ac
+#define CAP1_VBI_EVEN_OFFSET			0x09b0
+#define CAP1_VBI_V_WINDOW			0x09b4
+#define CAP1_VBI_H_WINDOW			0x09b8
+#define CAP1_PORT_MODE_CNTL			0x09bc
+#define CAP1_TRIG_CNTL				0x09c0
+#define CAP1_DEBUG				0x09c4
+#define CAP1_CONFIG				0x09c8
+#define CAP1_ANC_ODD_OFFSET			0x09cc
+#define CAP1_ANC_EVEN_OFFSET			0x09d0
+#define CAP1_ANC_H_WINDOW			0x09d4
+#define CAP1_VIDEO_SYNC_TEST			0x09d8
+#define CAP1_ONESHOT_BUF_OFFSET			0x09dc
+#define CAP1_BUF_STATUS				0x09e0
+#define CAP1_DWNSC_XRATIO			0x09e8
+#define CAP1_XSHARPNESS				0x09ec
+#define BM_FRAME_BUF_OFFSET			0x0a00
+#define BM_SYSTEM_MEM_ADDR			0x0a04
+#define BM_COMMAND				0x0a08
+#define BM_STATUS				0x0a0c
+#define BM_QUEUE_STATUS				0x0a10
+#define BM_QUEUE_FREE_STATUS			0x0A14
+#define BM_CHUNK_0_VAL				0x0a18
+#define BM_CHUNK_1_VAL				0x0a1C
+#define BM_VIP0_BUF				0x0A20
+#define BM_VIP0_ACTIVE				0x0A24
+#define BM_VIP1_BUF				0x0A30
+#define BM_VIP1_ACTIVE				0x0A34
+#define BM_VIP2_BUF				0x0A40
+#define BM_VIP2_ACTIVE				0x0A44
+#define BM_VIP3_BUF				0x0A50
+#define BM_VIP3_ACTIVE				0x0A54
+#define BM_VIDCAP_BUF0				0x0a60
+#define BM_VIDCAP_BUF1				0x0a64
+#define BM_VIDCAP_BUF2				0x0a68
+#define BM_VIDCAP_ACTIVE			0x0a6c
+#define BM_GUI					0x0a80
+#define SURFACE_DELAY				0x0b00
+
+/******************************************************************************
+ *                  GUI Block Memory Mapped Registers                         *
+ *                     These registers are FIFOed.                            *
+ *****************************************************************************/
+#define PM4_FIFO_DATA_EVEN			0x1000
+#define PM4_FIFO_DATA_ODD			0x1004
+
+#define DST_OFFSET				0x1404
+#define DST_PITCH				0x1408
+#define DST_WIDTH				0x140c
+#define DST_HEIGHT				0x1410
+#define SRC_X					0x1414
+#define SRC_Y					0x1418
+#define DST_X					0x141c
+#define DST_Y					0x1420
+#define SRC_PITCH_OFFSET			0x1428
+#define DST_PITCH_OFFSET			0x142c
+#define SRC_Y_X					0x1434
+#define DST_Y_X					0x1438
+#define DST_HEIGHT_WIDTH			0x143c
+#define DP_GUI_MASTER_CNTL			0x146c
+#define BRUSH_SCALE				0x1470
+#define BRUSH_Y_X				0x1474
+#define DP_BRUSH_BKGD_CLR			0x1478
+#define DP_BRUSH_FRGD_CLR			0x147c
+#define BRUSH_DATA0				0x1480
+#define BRUSH_DATA1				0x1484
+#define BRUSH_DATA2				0x1488
+#define BRUSH_DATA3				0x148c
+#define BRUSH_DATA4				0x1490
+#define BRUSH_DATA5				0x1494
+#define BRUSH_DATA6				0x1498
+#define BRUSH_DATA7				0x149c
+#define BRUSH_DATA8				0x14a0
+#define BRUSH_DATA9				0x14a4
+#define BRUSH_DATA10				0x14a8
+#define BRUSH_DATA11				0x14ac
+#define BRUSH_DATA12				0x14b0
+#define BRUSH_DATA13				0x14b4
+#define BRUSH_DATA14				0x14b8
+#define BRUSH_DATA15				0x14bc
+#define BRUSH_DATA16				0x14c0
+#define BRUSH_DATA17				0x14c4
+#define BRUSH_DATA18				0x14c8
+#define BRUSH_DATA19				0x14cc
+#define BRUSH_DATA20				0x14d0
+#define BRUSH_DATA21				0x14d4
+#define BRUSH_DATA22				0x14d8
+#define BRUSH_DATA23				0x14dc
+#define BRUSH_DATA24				0x14e0
+#define BRUSH_DATA25				0x14e4
+#define BRUSH_DATA26				0x14e8
+#define BRUSH_DATA27				0x14ec
+#define BRUSH_DATA28				0x14f0
+#define BRUSH_DATA29				0x14f4
+#define BRUSH_DATA30				0x14f8
+#define BRUSH_DATA31				0x14fc
+#define BRUSH_DATA32				0x1500
+#define BRUSH_DATA33				0x1504
+#define BRUSH_DATA34				0x1508
+#define BRUSH_DATA35				0x150c
+#define BRUSH_DATA36				0x1510
+#define BRUSH_DATA37				0x1514
+#define BRUSH_DATA38				0x1518
+#define BRUSH_DATA39				0x151c
+#define BRUSH_DATA40				0x1520
+#define BRUSH_DATA41				0x1524
+#define BRUSH_DATA42				0x1528
+#define BRUSH_DATA43				0x152c
+#define BRUSH_DATA44				0x1530
+#define BRUSH_DATA45				0x1534
+#define BRUSH_DATA46				0x1538
+#define BRUSH_DATA47				0x153c
+#define BRUSH_DATA48				0x1540
+#define BRUSH_DATA49				0x1544
+#define BRUSH_DATA50				0x1548
+#define BRUSH_DATA51				0x154c
+#define BRUSH_DATA52				0x1550
+#define BRUSH_DATA53				0x1554
+#define BRUSH_DATA54				0x1558
+#define BRUSH_DATA55				0x155c
+#define BRUSH_DATA56				0x1560
+#define BRUSH_DATA57				0x1564
+#define BRUSH_DATA58				0x1568
+#define BRUSH_DATA59				0x156c
+#define BRUSH_DATA60				0x1570
+#define BRUSH_DATA61				0x1574
+#define BRUSH_DATA62				0x1578
+#define BRUSH_DATA63				0x157c
+#define DST_WIDTH_X				0x1588
+#define DST_HEIGHT_WIDTH_8			0x158c
+#define SRC_X_Y					0x1590
+#define DST_X_Y					0x1594
+#define DST_WIDTH_HEIGHT			0x1598
+#define DST_WIDTH_X_INCY			0x159c
+#define DST_HEIGHT_Y				0x15a0
+#define DST_X_SUB				0x15a4
+#define DST_Y_SUB				0x15a8
+#define SRC_OFFSET				0x15ac
+#define SRC_PITCH				0x15b0
+#define DST_HEIGHT_WIDTH_BW			0x15b4
+#define CLR_CMP_CNTL				0x15c0
+#define CLR_CMP_CLR_SRC				0x15c4
+#define CLR_CMP_CLR_DST				0x15c8
+#define CLR_CMP_MASK				0x15cc
+#define DP_SRC_FRGD_CLR				0x15d8
+#define DP_SRC_BKGD_CLR				0x15dc
+#define GUI_SCRATCH_REG0			0x15e0
+#define GUI_SCRATCH_REG1			0x15e4
+#define GUI_SCRATCH_REG2			0x15e8
+#define GUI_SCRATCH_REG3			0x15ec
+#define GUI_SCRATCH_REG4			0x15f0
+#define GUI_SCRATCH_REG5			0x15f4
+#define LEAD_BRES_ERR				0x1600
+#define LEAD_BRES_INC				0x1604
+#define LEAD_BRES_DEC				0x1608
+#define TRAIL_BRES_ERR				0x160c
+#define TRAIL_BRES_INC				0x1610
+#define TRAIL_BRES_DEC				0x1614
+#define TRAIL_X					0x1618
+#define LEAD_BRES_LNTH				0x161c
+#define TRAIL_X_SUB				0x1620
+#define LEAD_BRES_LNTH_SUB			0x1624
+#define DST_BRES_ERR				0x1628
+#define DST_BRES_INC				0x162c
+#define DST_BRES_DEC				0x1630
+#define DST_BRES_LNTH				0x1634
+#define DST_BRES_LNTH_SUB			0x1638
+#define SC_LEFT					0x1640
+#define SC_RIGHT				0x1644
+#define SC_TOP					0x1648
+#define SC_BOTTOM				0x164c
+#define SRC_SC_RIGHT				0x1654
+#define SRC_SC_BOTTOM				0x165c
+#define AUX_SC_CNTL				0x1660
+#define AUX1_SC_LEFT				0x1664
+#define AUX1_SC_RIGHT				0x1668
+#define AUX1_SC_TOP				0x166c
+#define AUX1_SC_BOTTOM				0x1670
+#define AUX2_SC_LEFT				0x1674
+#define AUX2_SC_RIGHT				0x1678
+#define AUX2_SC_TOP				0x167c
+#define AUX2_SC_BOTTOM				0x1680
+#define AUX3_SC_LEFT				0x1684
+#define AUX3_SC_RIGHT				0x1688
+#define AUX3_SC_TOP				0x168c
+#define AUX3_SC_BOTTOM				0x1690
+#define GUI_DEBUG0				0x16a0
+#define GUI_DEBUG1				0x16a4
+#define GUI_TIMEOUT				0x16b0
+#define GUI_TIMEOUT0				0x16b4
+#define GUI_TIMEOUT1				0x16b8
+#define GUI_PROBE				0x16bc
+#define DP_CNTL					0x16c0
+#define DP_DATATYPE				0x16c4
+#define DP_MIX					0x16c8
+#define DP_WRITE_MASK				0x16cc
+#define DP_CNTL_XDIR_YDIR_YMAJOR		0x16d0
+#define DEFAULT_OFFSET				0x16e0
+#define DEFAULT_PITCH				0x16e4
+#define DEFAULT_SC_BOTTOM_RIGHT			0x16e8
+#define SC_TOP_LEFT				0x16ec
+#define SC_BOTTOM_RIGHT				0x16f0
+#define SRC_SC_BOTTOM_RIGHT			0x16f4
+#define WAIT_UNTIL				0x1720
+#define CACHE_CNTL				0x1724
+#define GUI_STAT				0x1740
+#define PC_GUI_MODE				0x1744
+#define PC_GUI_CTLSTAT				0x1748
+#define PC_DEBUG_MODE				0x1760
+#define BRES_DST_ERR_DEC			0x1780
+#define TRAIL_BRES_T12_ERR_DEC			0x1784
+#define TRAIL_BRES_T12_INC			0x1788
+#define DP_T12_CNTL				0x178c
+#define DST_BRES_T1_LNTH			0x1790
+#define DST_BRES_T2_LNTH			0x1794
+#define HOST_DATA0				0x17c0
+#define HOST_DATA1				0x17c4
+#define HOST_DATA2				0x17c8
+#define HOST_DATA3				0x17cc
+#define HOST_DATA4				0x17d0
+#define HOST_DATA5				0x17d4
+#define HOST_DATA6				0x17d8
+#define HOST_DATA7				0x17dc
+#define HOST_DATA_LAST				0x17e0
+#define SECONDARY_SCALE_PITCH			0x1980
+#define SECONDARY_SCALE_X_INC			0x1984
+#define SECONDARY_SCALE_Y_INC			0x1988
+#define SECONDARY_SCALE_HACC			0x198c
+#define SECONDARY_SCALE_VACC			0x1990
+#define SCALE_SRC_HEIGHT_WIDTH			0x1994
+#define SCALE_OFFSET_0				0x1998
+#define SCALE_PITCH				0x199c
+#define SCALE_X_INC				0x19a0
+#define SCALE_Y_INC				0x19a4
+#define SCALE_HACC				0x19a8
+#define SCALE_VACC				0x19ac
+#define SCALE_DST_X_Y				0x19b0
+#define SCALE_DST_HEIGHT_WIDTH			0x19b4
+#define SCALE_3D_CNTL				0x1a00
+#define SCALE_3D_DATATYPE			0x1a20
+#define SETUP_CNTL				0x1bc4
+#define SOLID_COLOR				0x1bc8
+#define WINDOW_XY_OFFSET			0x1bcc
+#define DRAW_LINE_POINT				0x1bd0
+#define SETUP_CNTL_PM4				0x1bd4
+#define DST_PITCH_OFFSET_C			0x1c80
+#define DP_GUI_MASTER_CNTL_C			0x1c84
+#define SC_TOP_LEFT_C				0x1c88
+#define SC_BOTTOM_RIGHT_C			0x1c8c
+
+#define CLR_CMP_MASK_3D				0x1A28
+#define MISC_3D_STATE_CNTL_REG			0x1CA0
+#define MC_SRC1_CNTL				0x19D8
+#define TEX_CNTL				0x1800
+
+/* CONSTANTS */
+#define GUI_ACTIVE				0x80000000
+#define ENGINE_IDLE				0x0
+
+#define PLL_WR_EN				0x00000080
+
+#define CLK_PIN_CNTL				0x0001
+#define PPLL_CNTL				0x0002
+#define PPLL_REF_DIV				0x0003
+#define PPLL_DIV_0				0x0004
+#define PPLL_DIV_1				0x0005
+#define PPLL_DIV_2				0x0006
+#define PPLL_DIV_3				0x0007
+#define VCLK_ECP_CNTL				0x0008
+#define HTOTAL_CNTL				0x0009
+#define X_MPLL_REF_FB_DIV			0x000a
+#define XPLL_CNTL				0x000b
+#define XDLL_CNTL				0x000c
+#define XCLK_CNTL				0x000d
+#define MPLL_CNTL				0x000e
+#define MCLK_CNTL				0x000f
+#define AGP_PLL_CNTL				0x0010
+#define FCP_CNTL				0x0012
+#define PLL_TEST_CNTL				0x0013
+
+#define PPLL_RESET				0x01
+#define PPLL_ATOMIC_UPDATE_EN			0x10000
+#define PPLL_VGA_ATOMIC_UPDATE_EN		0x20000
+#define PPLL_REF_DIV_MASK			0x3FF
+#define PPLL_FB3_DIV_MASK			0x7FF
+#define PPLL_POST3_DIV_MASK			0x70000
+#define PPLL_ATOMIC_UPDATE_R			0x8000
+#define PPLL_ATOMIC_UPDATE_W			0x8000
+#define MEM_CFG_TYPE_MASK			0x3
+#define XCLK_SRC_SEL_MASK			0x7
+#define XPLL_FB_DIV_MASK			0xFF00
+#define X_MPLL_REF_DIV_MASK			0xFF
+
+/* CRTC control values (CRTC_GEN_CNTL) */
+#define CRTC_CSYNC_EN				0x00000010
+
+#define CRTC_PIX_WIDTH_MASK			0x00000700
+#define CRTC_PIX_WIDTH_4BPP			0x00000100
+#define CRTC_PIX_WIDTH_8BPP			0x00000200
+#define CRTC_PIX_WIDTH_15BPP			0x00000300
+#define CRTC_PIX_WIDTH_16BPP			0x00000400
+#define CRTC_PIX_WIDTH_24BPP			0x00000500
+#define CRTC_PIX_WIDTH_32BPP			0x00000600
+
+/* DAC_CNTL bit constants */                       
+#define DAC_8BIT_EN				0x00000100
+
+/* GEN_RESET_CNTL bit constants */
+#define SOFT_RESET_GUI				0x00000001
+#define SOFT_RESET_VCLK				0x00000100
+#define SOFT_RESET_PCLK				0x00000200
+#define SOFT_RESET_ECP				0x00000400
+#define SOFT_RESET_DISPENG_XCLK			0x00000800
+
+/* PC_GUI_CTLSTAT bit constants */
+#define PC_BUSY_INIT				0x10000000                 
+#define PC_BUSY_GUI				0x20000000                 
+#define PC_BUSY_NGUI				0x40000000
+#define PC_BUSY					0x80000000
+
+#define BUS_MASTER_DIS				0x00000040
+#define PM4_BUFFER_CNTL_NONPM4			0x00000000
+
+/* DP_GUI_MASTER_CNTL bit constants */
+#define	GMC_SRC_PITCH_OFFSET_DEFAULT		0x00000000
+#define GMC_DST_PITCH_OFFSET_DEFAULT		0x00000000
+#define GMC_SRC_CLIP_DEFAULT			0x00000000
+#define GMC_DST_CLIP_DEFAULT			0x00000000
+#define GMC_BRUSH_SOLIDCOLOR			0x000000d0
+#define GMC_SRC_DSTCOLOR			0x00003000
+#define GMC_BYTE_ORDER_MSB_TO_LSB		0x00000000
+#define GMC_DP_SRC_RECT				0x02000000
+#define GMC_3D_FCN_EN_CLR			0x00000000
+#define GMC_AUX_CLIP_CLEAR			0x20000000
+#define GMC_DST_CLR_CMP_FCN_CLEAR		0x10000000
+#define GMC_WRITE_MASK_SET			0x40000000
+#define GMC_DP_CONVERSION_TEMP_6500		0x00000000
+
+/* DP_GUI_MASTER_CNTL ROP3 named constants */
+#define	ROP3_PATCOPY				0x00f00000
+#define ROP3_SRCCOPY				0x00cc0000   // S
+
+#define SRC_DSTCOLOR				0x00030000
+
+/* DP_CNTL bit constants */
+#define DST_X_RIGHT_TO_LEFT			0x00000000
+#define DST_X_LEFT_TO_RIGHT			0x00000001
+#define DST_Y_BOTTOM_TO_TOP			0x00000000
+#define DST_Y_TOP_TO_BOTTOM			0x00000002
+#define DST_X_MAJOR				0x00000000
+#define DST_Y_MAJOR				0x00000004
+#define DST_X_TILE				0x00000008
+#define DST_Y_TILE				0x00000010
+#define DST_LAST_PEL				0x00000020
+#define DST_TRAIL_X_RIGHT_TO_LEFT		0x00000000
+#define DST_TRAIL_X_LEFT_TO_RIGHT		0x00000040
+#define DST_TRAP_FILL_RIGHT_TO_LEFT		0x00000000
+#define DST_TRAP_FILL_LEFT_TO_RIGHT		0x00000080
+#define DST_BRES_SIGN				0x00000100
+#define DST_HOST_BIG_ENDIAN_EN			0x00000200
+#define DST_POLYLINE_NONLAST			0x00008000
+#define DST_RASTER_STALL			0x00010000
+#define DST_POLY_EDGE				0x00040000
+
+/* DP_MIX bit constants */
+#define DP_SRC_RECT				0x00000200
+#define DP_SRC_HOST				0x00000300
+#define DP_SRC_HOST_BYTEALIGN			0x00000400
+
+#endif /* REG_RAGE128_H */
diff -u --recursive --new-file v2.3.22/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.22/linux/drivers/video/aty128fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty128fb.c	Mon Oct 18 11:37:43 1999
@@ -0,0 +1,2151 @@
+/* $Id: aty128fb.c,v 1.1 1999/10/12 11:00:43 geert Exp $
+ *  linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128
+ *
+ *  Copyright (C) Summer 1999, Anthony Tong <atong@uiuc.edu>
+ *
+ * 				Brad Douglas <brad@neruo.com>
+ *				- x86 support
+ *				- MTRR
+ *				- Probe ROM for PLL
+ *
+ *  Based off of Geert's atyfb.c and vfb.c.
+ *
+ *  TODO:
+ *		- panning
+ *		- fix 15/16 bpp on big endian arch's
+ *		- monitor sensing (DDC)
+ *		- other platform support (only ppc/x86 supported)
+ *		- PPLL_REF_DIV & XTALIN calculation
+ *		- determine MCLK from previous hardware setting
+ */
+
+/*
+ * A special note of gratitude to ATI's devrel for providing documentation,
+ * example code and hardware. Thanks Nitya.	-atong
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PPC)
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <linux/nvram.h>
+#include <video/macmodes.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "aty128.h"
+
+#undef DEBUG
+#undef CONFIG_MTRR	/* not ready? */
+
+#ifdef DEBUG
+#define DBG(x)		printk(KERN_INFO "aty128fb: %s\n",(x));
+#else
+#define DBG(x)
+#endif
+
+static char *aty128fb_name = "ATY Rage128";
+
+static struct fb_var_screeninfo default_var = {
+    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+    640, 480, 640, 480, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+    0, FB_VMODE_NONINTERLACED
+};
+
+#pragma pack(1)
+typedef struct {
+    u8 clock_chip_type;
+    u8 struct_size;
+    u8 accelerator_entry;
+    u8 VGA_entry;
+    u16 VGA_table_offset;
+    u16 POST_table_offset;
+    u16 XCLK;
+    u16 MCLK;
+    u8 num_PLL_blocks;
+    u8 size_PLL_blocks;
+    u16 PCLK_ref_freq;
+    u16 PCLK_ref_divider;
+    u32 PCLK_min_freq;
+    u32 PCLK_max_freq;
+    u16 MCLK_ref_freq;
+    u16 MCLK_ref_divider;
+    u32 MCLK_min_freq;
+    u32 MCLK_max_freq;
+    u16 XCLK_ref_freq;
+    u16 XCLK_ref_divider;
+    u32 XCLK_min_freq;
+    u32 XCLK_max_freq;
+} PLL_BLOCK;
+#pragma pack()
+
+struct aty128_meminfo {
+    u8 ML;
+    u8 MB;
+    u8 Trcd;
+    u8 Trp;
+    u8 Twr;
+    u8 CL;
+    u8 Tr2w;
+    u8 LoopLatency;
+    u8 DspOn;
+    u8 Rloop;
+};
+
+const struct aty128_meminfo sdr_128   = { 4, 4, 3, 3, 1, 3, 1, 16, 30, 16 };
+const struct aty128_meminfo sdr_64    = { 4, 8, 3, 3, 1, 3, 1, 17, 46, 17 };
+const struct aty128_meminfo sdr_sgram = { 4, 4, 1, 2, 1, 2, 1, 16, 24, 16 };
+const struct aty128_meminfo ddr_sgram = { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16 };
+
+static int currcon = 0;
+static char fontname[40] __initdata = { 0 };
+
+#if defined(CONFIG_PPC)
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
+#endif
+
+#if defined(CONFIG_MTRR)
+static int mtrr = 1;
+#endif
+
+struct aty128_constants {
+    u32 dotclock;
+    u32 ppll_min;
+    u32 ppll_max;
+    u32 ref_divider;
+    u32 xclk;
+    u32 fifo_width;
+    u32 fifo_depth;
+};
+
+struct aty128_crtc {
+    u32 gen_cntl;
+    u32 ext_cntl;
+    u32 h_total, h_sync_strt_wid;
+    u32 v_total, v_sync_strt_wid;
+    u32 pitch;
+    u32 offset, offset_cntl;
+    u32 vxres, vyres;
+    u32 bpp;
+};
+
+struct aty128_pll {
+    u32 post_divider;
+    u32 feedback_divider;
+    u32 vclk;
+};
+
+struct aty128_ddafifo {
+    u32 dda_config;
+    u32 dda_on_off;
+};
+
+/* register values for a specific mode */
+struct aty128fb_par {
+    struct aty128_crtc crtc;
+    struct aty128_pll pll;
+    struct aty128_ddafifo fifo_reg;
+    u32 accel_flags;
+};
+
+struct fb_info_aty128 {
+    struct fb_info fb_info;
+    struct aty128_constants constants;
+    unsigned long regbase_phys, regbase;
+    unsigned long frame_buffer_phys, frame_buffer;
+    const struct aty128_meminfo *mem;
+    u32 vram_size;
+    u32 BIOS_SEG;
+#ifdef CONFIG_MTRR
+    struct { int vram; int vram_valid; } mtrr;
+#endif
+    struct aty128fb_par default_par, current_par;
+    struct display disp;
+    struct { u8 red, green, blue, pad; } palette[256];
+    union {
+#ifdef FBCON_HAS_CFB16
+    u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+    u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+    u32 cfb32[16];
+#endif
+    } fbcon_cmap;
+    int blitter_may_be_busy;
+};
+
+#define round_div(n, d) ((n+(d/2))/d)
+
+    /*
+     *  Interface used by the world
+     */
+
+int aty128fb_setup(char *options);
+
+static int aty128fb_open(struct fb_info *info, int user);
+static int aty128fb_release(struct fb_info *info, int user);
+static int aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+		       struct fb_info *info);
+static int aty128fb_get_var(struct fb_var_screeninfo *var, int con,
+		       struct fb_info *info);
+static int aty128fb_set_var(struct fb_var_screeninfo *var, int con,
+		       struct fb_info *info);
+static int aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		     u_long arg, int con, struct fb_info *info);
+
+
+    /*
+     *  Interface to the low level console driver
+     */
+
+void aty128fb_init(void);
+#ifdef CONFIG_FB_OF
+void aty128fb_of_init(struct device_node *dp);
+#endif
+static int aty128fbcon_switch(int con, struct fb_info *info);
+static void aty128fbcon_blank(int blank, struct fb_info *info);
+
+
+    /*
+     *  Internal routines
+     */
+
+static void aty128_encode_fix(struct fb_fix_screeninfo *fix,
+				struct aty128fb_par *par,
+				const struct fb_info_aty128 *info);
+static void aty128_set_disp(struct display *disp,
+			struct fb_info_aty128 *info, int bpp, int accel);
+static int aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+				u_int *transp, struct fb_info *info);
+static int aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+				u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+static void aty128pci_probe(void);
+static int aty128find_ROM(struct fb_info_aty128 *info);
+static void aty128_timings(struct fb_info_aty128 *info);
+static void aty128_get_pllinfo(struct fb_info_aty128 *info);
+static void aty128_reset_engine(const struct fb_info_aty128 *info);
+static void aty128_flush_pixel_cache(const struct fb_info_aty128 *info);
+static void wait_for_fifo(u16 entries, const struct fb_info_aty128 *info);
+static void wait_for_idle(const struct fb_info_aty128 *info);
+static u32 bpp_to_depth(u32 bpp);
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_aty128_8;
+#endif
+
+
+static struct fb_ops aty128fb_ops = {
+    aty128fb_open, aty128fb_release, aty128fb_get_fix,
+    aty128fb_get_var, aty128fb_set_var, aty128fb_get_cmap,
+    aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl
+};
+
+
+    /*
+     * Functions to read from/write to the mmio registers
+     *	- endian conversions may possibly be avoided by flipping CONFIG_CNTL
+     *  or using the other register aperture? TODO.
+     */
+static inline u32
+_aty_ld_le32(volatile unsigned int regindex,
+                              const struct fb_info_aty128 *info)
+{
+    unsigned long temp;
+    u32 val;
+
+#if defined(__powerpc__)
+    eieio();
+    temp = info->regbase;
+    asm("lwbrx %0,%1,%2" : "=b"(val) : "b" (regindex), "b" (temp));
+#elif defined(__sparc_v9__)
+    temp = info->regbase + regindex;
+    asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
+#else
+    temp = info->regbase+regindex;
+    val = le32_to_cpu(*((volatile u32 *)(temp)));
+#endif
+    return val;
+}
+
+static inline void
+_aty_st_le32(volatile unsigned int regindex, u32 val,
+                               const struct fb_info_aty128 *info)
+{
+    unsigned long temp;
+
+#if defined(__powerpc__)
+    eieio();
+    temp = info->regbase;
+    asm("stwbrx %0,%1,%2" : : "b" (val), "b" (regindex), "b" (temp) :
+        "memory");
+#elif defined(__sparc_v9__)
+    temp = info->regbase + regindex;
+    asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
+#else
+    temp = info->regbase+regindex;
+    *((volatile u32 *)(temp)) = cpu_to_le32(val);
+#endif
+}
+
+static inline u8
+_aty_ld_8(volatile unsigned int regindex,
+                          const struct fb_info_aty128 *info)
+{
+#if defined(__powerpc__)
+    eieio();
+#endif
+    return *(volatile u8 *)(info->regbase+regindex);
+}
+
+static inline void
+_aty_st_8(volatile unsigned int regindex, u8 val,
+                            const struct fb_info_aty128 *info)
+{
+#if defined(__powerpc__)
+    eieio();
+#endif
+    *(volatile u8 *)(info->regbase+regindex) = val;
+}
+
+#define aty_ld_le32(regindex)		_aty_ld_le32(regindex, info)
+#define aty_st_le32(regindex, val)	_aty_st_le32(regindex, val, info)
+#define aty_ld_8(regindex)		_aty_ld_8(regindex, info)
+#define aty_st_8(regindex, val)		_aty_st_8(regindex, val, info)
+
+    /*
+     * Functions to read from/write to the pll registers
+     */
+
+#define aty_ld_pll(pll_index)		_aty_ld_pll(pll_index, info)
+#define aty_st_pll(pll_index, val)	_aty_st_pll(pll_index, val, info)
+
+static u32
+_aty_ld_pll(unsigned int pll_index,
+			const struct fb_info_aty128 *info)
+{       
+    aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F);
+    return aty_ld_le32(CLOCK_CNTL_DATA);
+}
+    
+static void
+_aty_st_pll(unsigned int pll_index, u32 val,
+			const struct fb_info_aty128 *info)
+{   
+    aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN);
+    aty_st_le32(CLOCK_CNTL_DATA, val);
+}
+ 
+/* return true when the PLL has completed an atomic update */
+static int
+aty_pll_readupdate(const struct fb_info_aty128 *info)
+{
+    return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
+}
+
+static void
+aty_pll_wait_readupdate(const struct fb_info_aty128 *info)
+{
+    unsigned long timeout = jiffies + HZ/100;	// should be more than enough
+    int reset = 1;
+
+    while (time_before(jiffies, timeout))
+	if (aty_pll_readupdate(info)) {
+	    reset = 0;
+	    break;
+	}
+
+#ifdef DEBUG
+    if (reset)	/* reset engine?? */
+	printk(KERN_ERR "aty128fb: PLL write timeout!");
+#endif
+}
+
+/* tell PLL to update */
+static void
+aty_pll_writeupdate(const struct fb_info_aty128 *info)
+{
+    aty_pll_wait_readupdate(info);
+
+    aty_st_pll(PPLL_REF_DIV,
+	aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);
+}
+
+
+/* write to the scratch register to test r/w functionality */
+static u32
+register_test(const struct fb_info_aty128 *info)
+{
+    u32 val, flag = 0;
+
+    val = aty_ld_le32(BIOS_0_SCRATCH);
+
+    aty_st_le32(BIOS_0_SCRATCH, 0x55555555);
+    if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) {
+	aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA);
+
+	if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA)
+	    flag = 1; 
+    }
+
+    aty_st_le32(BIOS_0_SCRATCH, val);	// restore value
+    return flag;
+}
+
+
+    /*
+     * Accelerator functions
+     */
+static void
+wait_for_idle(const struct fb_info_aty128 *info)
+{
+    unsigned long timeout = jiffies + HZ/20;
+    int reset = 1;
+
+    wait_for_fifo(64, info);
+
+    while (time_before(jiffies, timeout))
+	if ((aty_ld_le32(GUI_STAT) & GUI_ACTIVE) != ENGINE_IDLE) {
+	    reset = 0;
+	    break;
+	}
+
+    if (reset)
+	aty128_reset_engine(info);
+}
+
+
+static void
+wait_for_fifo(u16 entries, const struct fb_info_aty128 *info)
+{
+    unsigned long timeout = jiffies + HZ/20;
+    int reset = 1;
+
+    while (time_before(jiffies, timeout))
+	if ((aty_ld_le32(GUI_STAT) & 0x00000FFF) < entries) {
+	    reset = 0;
+	    break;
+	}
+
+    if (reset)
+	aty128_reset_engine(info);
+}
+
+
+static void
+aty128_flush_pixel_cache(const struct fb_info_aty128 *info)
+{
+    int i = 16384;
+
+    aty_st_le32(PC_NGUI_CTLSTAT, aty_ld_le32(PC_NGUI_CTLSTAT) | 0x000000ff);
+
+    while (i && (aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY))
+	i--;
+}
+
+
+static void
+aty128_reset_engine(const struct fb_info_aty128 *info)
+{
+    u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
+
+    aty128_flush_pixel_cache(info);
+
+    clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX);
+    mclk_cntl = aty_ld_pll(MCLK_CNTL);
+
+    aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000);
+
+    gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL);
+    aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI);
+    aty_ld_le32(GEN_RESET_CNTL);
+    aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI));
+    aty_ld_le32(GEN_RESET_CNTL);
+
+    aty_st_pll(MCLK_CNTL, mclk_cntl);
+    aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index);
+    aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl);
+
+    /* use old pio mode */
+    aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4);
+
+#ifdef DEBUG
+    printk("aty128fb: engine reset\n");
+#endif
+}
+
+
+static void
+aty128_init_engine(const struct aty128fb_par *par,
+		const struct fb_info_aty128 *info)
+{
+    u32 temp;
+    aty_st_le32(SCALE_3D_CNTL, 0x00000000);
+
+    aty128_reset_engine(info);
+
+    temp = par->crtc.pitch;	/* fix this up */
+    if (par->crtc.bpp == 24) {
+        temp = temp * 3;
+    }
+
+    /* setup engine offset registers */
+    wait_for_fifo(4, info);
+    aty_st_le32(DEFAULT_OFFSET, 0x00000000);
+
+    /* setup engine pitch registers */
+    aty_st_le32(DEFAULT_PITCH, temp);
+
+    /* set the default scissor register to max dimensions */
+    wait_for_fifo(1, info);
+    aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);
+
+    /* set the drawing controls registers */
+    wait_for_fifo(1, info);
+    aty_st_le32(DP_GUI_MASTER_CNTL,
+			GMC_SRC_PITCH_OFFSET_DEFAULT		|
+			GMC_DST_PITCH_OFFSET_DEFAULT		|
+			GMC_SRC_CLIP_DEFAULT			|
+			GMC_DST_CLIP_DEFAULT			|
+			GMC_BRUSH_SOLIDCOLOR			|
+			(bpp_to_depth(par->crtc.bpp) << 8)	|
+			GMC_SRC_DSTCOLOR			|
+			GMC_BYTE_ORDER_MSB_TO_LSB		|
+			GMC_DP_CONVERSION_TEMP_6500		|
+			ROP3_PATCOPY				|
+			GMC_DP_SRC_RECT				|
+			GMC_3D_FCN_EN_CLR			|
+			GMC_DST_CLR_CMP_FCN_CLEAR		|
+			GMC_AUX_CLIP_CLEAR			|
+			GMC_WRITE_MASK_SET);
+    wait_for_fifo(8, info);
+
+    /* clear the line drawing registers */
+    aty_st_le32(DST_BRES_ERR, 0);
+    aty_st_le32(DST_BRES_INC, 0);
+    aty_st_le32(DST_BRES_DEC, 0);
+
+    /* set brush color registers */
+    aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF);
+    aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000);
+
+    /* set source color registers */
+    aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF);
+    aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000);
+
+    /* default write mask */
+    aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);
+
+    /* Wait for all the writes to be completed before returning */
+    wait_for_idle(info);
+}
+
+
+    /*
+     * CRTC programming
+     */
+
+/* convert bpp values to their register representation */
+static u32
+bpp_to_depth(u32 bpp)
+{
+    if (bpp <= 8)
+	return 2;
+    else if (bpp <= 15)
+	return 3;
+    else if (bpp <= 16)
+#if 0	/* force 15bpp */
+	return 4;
+#else
+	return 3;
+#endif
+    else if (bpp <= 24)
+	return 5;
+    else if (bpp <= 32)
+	return 6;
+
+    return -EINVAL;
+}
+
+
+static void
+aty128_set_crtc(const struct aty128_crtc *crtc,
+		const struct fb_info_aty128 *info)
+{
+    aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
+    // aty_st_le32(CRTC_EXT_CNTL, crtc->ext_cntl);
+    aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
+    aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid);
+    aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total);
+    aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid);
+    aty_st_le32(CRTC_PITCH, crtc->pitch);
+    aty_st_le32(CRTC_OFFSET, crtc->offset);
+    aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl);
+}
+
+
+static int
+aty128_var_to_crtc(const struct fb_var_screeninfo *var,
+			struct aty128_crtc *crtc,
+			const struct fb_info_aty128 *info)
+{
+    u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+    u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+    u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+    u32 depth;
+    u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 };
+
+    /* input */
+    xres = var->xres;
+    yres = var->yres;
+    vxres = var->xres_virtual;
+    vyres = var->yres_virtual;
+    xoffset = var->xoffset;
+    yoffset = var->yoffset;
+    bpp = var->bits_per_pixel;
+    left = var->left_margin;
+    right = var->right_margin;
+    upper = var->upper_margin;
+    lower = var->lower_margin;
+    hslen = var->hsync_len;
+    vslen = var->vsync_len;
+    sync = var->sync;
+    vmode = var->vmode;
+
+    /* check for mode eligibility */
+
+    /* accept only non interlaced modes */
+    if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+	return -EINVAL;
+
+    /* convert (and round up) and validate */
+    xres = (xres + 7) & ~7;
+    xoffset = (xoffset + 7) & ~7;
+
+    if (vxres < xres + xoffset)
+	vxres = xres + xoffset;
+
+    if (vyres < yres + yoffset)
+	vyres = yres + yoffset;
+
+    if (bpp <= 8)
+	bpp = 8;
+    else if (bpp <= 16)
+	bpp = 16;
+    else if (bpp <= 32)
+	bpp = 32;
+
+    if (vxres * vyres * (bpp/8) > info->vram_size)
+	return -EINVAL;
+
+    h_disp = xres / 8 - 1;
+    h_total = (xres + right + hslen + left) / 8 - 1;
+
+    v_disp = yres - 1;
+    v_total = yres + upper + vslen + lower - 1;
+
+    h_sync_wid = hslen / 8;
+    if (h_sync_wid == 0)
+	h_sync_wid = 1;
+    else if (h_sync_wid > 0x3f)
+	h_sync_wid = 0x3f;
+
+    h_sync_strt = (xres + right - 8) + hsync_strt_pix[bpp/8];
+
+    v_disp = yres - 1;
+    v_sync_wid = vslen;
+    if (v_sync_wid == 0)
+	v_sync_wid = 1;
+    else if (v_sync_wid > 0x1f)
+	v_sync_wid = 0x1f;
+    
+    v_sync_strt = yres + lower - 1;
+
+    h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : (1 << 23);
+    v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : (1 << 23);
+
+    depth = bpp_to_depth(bpp);
+    c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
+
+    crtc->gen_cntl = 0x03000000 | c_sync | depth << 8;
+
+    crtc->h_total = (h_disp << 16) | (h_total & 0x0000FFFF);
+    crtc->v_total = (v_disp << 16) | (v_total & 0x0000FFFF);
+
+    crtc->h_sync_strt_wid = (h_sync_wid << 16) | (h_sync_strt) | h_sync_pol;
+    crtc->v_sync_strt_wid = (v_sync_wid << 16) | (v_sync_strt) | v_sync_pol;
+
+    crtc->pitch = xres / 8;
+
+    crtc->offset = 0;
+    crtc->offset_cntl = 0;
+
+    crtc->vxres = vxres;
+    crtc->vyres = vyres;
+    crtc->bpp = bpp;
+
+    return 0;
+}
+
+
+static int
+aty128_crtc_to_var(const struct aty128_crtc *crtc,
+			struct fb_var_screeninfo *var)
+{
+#ifdef notyet	/* xoffset and yoffset are not correctly calculated */
+    u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+    u32 pix_width;
+
+    h_total = crtc->h_total & 0x1ff;
+    h_disp = (crtc->h_total>>16) & 0xff;
+    h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
+        ((crtc->h_sync_strt_wid>>4) & 0x100);
+    h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
+    h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
+    h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
+    v_total = crtc->v_total & 0x7ff;
+    v_disp = (crtc->v_total>>16) & 0x7ff;
+    v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+    v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+    v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+    c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
+    pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+    xres = (h_disp+1)*8;
+    yres = v_disp+1;
+    left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+    right = (h_sync_strt-h_disp)*8+h_sync_dly;
+    hslen = h_sync_wid*8;
+    upper = v_total-v_sync_strt-v_sync_wid;
+    lower = v_sync_strt-v_disp;
+    vslen = v_sync_wid;
+    sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+        (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
+        (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
+
+    switch (pix_width) {
+#if 0
+    case CRTC_PIX_WIDTH_4BPP:
+        bpp = 4;
+        var->red.offset = 0;
+        var->red.length = 8;
+        var->green.offset = 0;
+        var->green.length = 8;
+        var->blue.offset = 0;
+        var->blue.length = 8;
+        var->transp.offset = 0;
+        var->transp.length = 0;
+        break;
+#endif
+    case CRTC_PIX_WIDTH_8BPP:
+        bpp = 8;
+        var->red.offset = 0;
+        var->red.length = 8;
+        var->green.offset = 0;
+        var->green.length = 8;
+        var->blue.offset = 0;
+        var->blue.length = 8;
+        var->transp.offset = 0;
+        var->transp.length = 0;
+        break;
+    case CRTC_PIX_WIDTH_15BPP:
+        bpp = 16;
+        var->red.offset = 10;
+        var->red.length = 5;
+        var->green.offset = 5;
+        var->green.length = 5;
+        var->blue.offset = 0;
+        var->blue.length = 5;
+        var->transp.offset = 0;
+        var->transp.length = 0;
+        break;
+    case CRTC_PIX_WIDTH_16BPP:
+        bpp = 16;
+        var->red.offset = 11;
+        var->red.length = 5;
+        var->green.offset = 5;
+        var->green.length = 6;
+        var->blue.offset = 0;
+        var->blue.length = 5;
+        var->transp.offset = 0;
+        var->transp.length = 0;
+        break;
+    case CRTC_PIX_WIDTH_24BPP:
+        bpp = 24;
+        var->red.offset = 16;
+        var->red.length = 8;
+        var->green.offset = 8;
+        var->green.length = 8;
+        var->blue.offset = 0;
+        var->blue.length = 8;
+        var->transp.offset = 0;
+        var->transp.length = 0;
+        break;
+    case CRTC_PIX_WIDTH_32BPP:
+        bpp = 32;
+        var->red.offset = 16;
+        var->red.length = 8;
+        var->green.offset = 8;
+        var->green.length = 8;
+        var->blue.offset = 0;
+        var->blue.length = 8;
+        var->transp.offset = 24;
+        var->transp.length = 8;
+        break;
+    default:
+        printk(KERN_ERR "Invalid pixel width\n");
+    }
+
+//Godda do math for xoffset and yoffset: does not exist in crtc
+    var->xres = xres;
+    var->yres = yres;
+    var->xres_virtual = crtc->vxres;
+    var->yres_virtual = crtc->vyres;
+    var->bits_per_pixel = bpp;
+    var->xoffset = crtc->xoffset;
+    var->yoffset = crtc->yoffset;
+    var->left_margin = left;
+    var->right_margin = right;
+    var->upper_margin = upper;
+    var->lower_margin = lower;
+    var->hsync_len = hslen;
+    var->vsync_len = vslen;
+    var->sync = sync;
+    var->vmode = FB_VMODE_NONINTERLACED;
+
+#endif /* notyet */
+    return 0;
+}
+
+static int
+aty128_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
+{
+    /* fill in pixel info */
+    switch (bpp) {
+    case 8:
+	var->red.offset = 0;
+	var->red.length = 8;
+	var->green.offset = 0;
+	var->green.length = 8;
+	var->blue.offset = 0;
+	var->blue.length = 8;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	break;
+    case 15:
+	var->bits_per_pixel = 16;
+	var->red.offset = 10;
+	var->red.length = 5;
+	var->green.offset = 5;
+	var->green.length = 5;
+	var->blue.offset = 0;
+	var->blue.length = 5;
+	var->transp.offset = 15;
+	var->transp.length = 1;
+	break;
+    case 16:
+	var->bits_per_pixel = 16;
+	var->red.offset = 11;
+	var->red.length = 5;
+	var->green.offset = 5;
+	var->green.length = 6;
+	var->blue.offset = 0;
+	var->blue.length = 5;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	break;
+    case 32:
+	var->red.offset = 16;
+	var->red.length = 8;
+	var->green.offset = 8;
+	var->green.length = 8;
+	var->blue.offset = 0;
+	var->blue.length = 8;
+	var->transp.offset = 24;
+	var->transp.length = 8;
+	break;
+    }
+
+    return 0;
+}
+
+
+static void
+aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info)
+{
+    int div3;
+    unsigned char post_conv[] =	/* register values for post dividers */
+	{ 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
+
+    /* select PPLL_DIV_3 */
+    aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
+
+    /* reset ppll */
+    aty_st_pll(PPLL_CNTL,
+		aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
+
+    div3 = aty_ld_pll(PPLL_DIV_3);
+
+    div3 &= ~PPLL_FB3_DIV_MASK;
+    div3 |= pll->feedback_divider;
+
+    div3 &= ~PPLL_POST3_DIV_MASK;
+    div3 |= post_conv[pll->post_divider] << 16;
+
+    /* write feedback and post dividers */
+    aty_st_pll(PPLL_DIV_3, div3);
+    aty_pll_writeupdate(info);
+    aty_pll_wait_readupdate(info);
+
+    aty_st_pll(HTOTAL_CNTL, 0);	/* no horiz crtc adjustment */
+
+    aty_pll_writeupdate(info);
+
+    /* clear the reset, just in case */
+    aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);
+}
+
+
+static int
+aty128_var_to_pll(u32 vclk_per, struct aty128_pll *pll,
+			const struct fb_info_aty128 *info)
+{
+    const struct aty128_constants c = info->constants;
+    unsigned char post_dividers [] = {1,2,4,8,3,6,12};
+    u32 output_freq, vclk;
+    int i;
+    u32 n, d;
+
+    vclk = 100000000 / vclk_per;	/* convert units to 10 kHz */
+
+    /* adjust pixel clock if necessary */
+    if (vclk > c.ppll_max)
+	vclk = c.ppll_max;
+    if (vclk * 12 < c.ppll_min)
+	vclk = c.ppll_min;
+
+    /* now, find an acceptable divider */
+    for (i = 0; i < sizeof(post_dividers); i++) {
+	output_freq = post_dividers[i] * vclk;
+	if (output_freq >= c.ppll_min && output_freq <= c.ppll_max)
+	    break;
+    }
+    pll->post_divider = post_dividers[i];
+
+    /* calculate feedback divider */
+    n = c.ref_divider * output_freq;
+    d = c.dotclock;
+    pll->feedback_divider = round_div(n, d);
+
+    pll->vclk = vclk;
+#ifdef DEBUG
+    printk("post %x  feedback %x vlck %x output %x\n",
+	   pll->post_divider, pll->feedback_divider, vclk, output_freq);
+#endif
+
+    return 0;
+}
+
+
+static int
+aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
+{
+    /* TODO */
+    return 0;
+}
+
+
+static void
+aty128_set_fifo(const struct aty128_ddafifo *dsp,
+			const struct fb_info_aty128 *info)
+{
+    aty_st_le32(DDA_CONFIG, dsp->dda_config);
+    aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
+}
+
+
+static int
+aty128_ddafifo(struct aty128_ddafifo *dsp,
+		const struct aty128_pll *pll,
+		u32 bpp,
+		const struct fb_info_aty128 *info)
+{
+    const struct aty128_meminfo *m = info->mem;
+    u32 xclk = info->constants.xclk;
+    u32 fifo_width = info->constants.fifo_width;
+    u32 fifo_depth = info->constants.fifo_depth;
+    s32 x, b, p, ron, roff;
+    u32 n, d;
+
+    if (bpp == 15)
+	bpp = 16;
+
+    n = xclk * fifo_width;
+    d = pll->vclk*bpp;
+    x = round_div(n, d);
+
+    ron = 4 * m->MB +
+	3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +
+	2 * m->Trp +
+	m->Twr +
+	m->CL +
+	m->Tr2w +
+	x;
+
+#ifdef DEBUG
+    printk("x %x\n", x);
+#endif
+    b = 0;
+    while (x) {
+	x >>= 1;
+	b++;
+    }
+    p = b + 1;
+
+    ron <<= (11 - p);
+
+    n <<= (11 - p);
+    x = round_div(n, d);
+    roff = x * (fifo_depth - 4);
+    if ((ron + m->Rloop) >= roff) {
+	printk("Mode out of range\n");
+	return -EINVAL;
+    }
+
+#ifdef DEBUG
+    printk("p: %x rloop: %x x: %x ron: %x roff: %x\n", p, m->Rloop, x,
+	ron, roff);
+#endif
+    dsp->dda_config = p << 16 | m->Rloop << 20 | x;
+    dsp->dda_on_off = ron << 16 | roff;
+
+    return 0;
+}
+
+
+/*
+ * This actually sets the video mode.
+ */
+static void
+aty128_set_par(struct aty128fb_par *par,
+			struct fb_info_aty128 *info)
+{ 
+    u32 config;
+    
+    info->current_par = *par;
+
+    /* clear all registers that may interfere with mode setting */
+    aty_st_le32(OVR_CLR, 0);
+    aty_st_le32(OVR_WID_LEFT_RIGHT, 0);
+    aty_st_le32(OVR_WID_TOP_BOTTOM, 0);
+    aty_st_le32(OV0_SCALE_CNTL, 0);
+    aty_st_le32(MPP_TB_CONFIG, 0);
+    aty_st_le32(MPP_GP_CONFIG, 0);
+    aty_st_le32(SUBPIC_CNTL, 0);
+    aty_st_le32(VIPH_CONTROL, 0);
+    aty_st_le32(I2C_CNTL_1, 0);
+    aty_st_le32(GEN_INT_CNTL, 0);	/* turn off interrupts */
+    aty_st_le32(CAP0_TRIG_CNTL, 0);
+    aty_st_le32(CAP1_TRIG_CNTL, 0);
+
+    aty_st_8(CRTC_EXT_CNTL + 1, 4);	/* turn video off */
+
+    aty128_set_crtc(&par->crtc, info);
+    aty128_set_pll(&par->pll, info);
+    aty128_set_fifo(&par->fifo_reg, info);
+
+    config = aty_ld_le32(CONFIG_CNTL) & ~3;
+
+#if defined(__BIG_ENDIAN)
+    if (par->crtc.bpp >= 24)
+	config |= 2;	/* make aperture do 32 byte swapping */
+    else if (par->crtc.bpp > 8)
+	config |= 1;	/* make aperture do 16 byte swapping */
+#endif
+
+    aty_st_le32(CONFIG_CNTL, config);
+
+    aty_st_8(CRTC_EXT_CNTL + 1, 0);	/* turn the video back on */
+}
+
+
+    /*
+     *  Open/Release the frame buffer device
+     */
+
+static int aty128fb_open(struct fb_info *info, int user)
+{
+    MOD_INC_USE_COUNT;
+    return(0);                              
+}
+        
+
+static int aty128fb_release(struct fb_info *info, int user)
+{
+    MOD_DEC_USE_COUNT;
+    return(0);                                                    
+}
+
+
+static int
+aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par,
+			const struct fb_info_aty128 *info)
+{
+    int err;
+
+    if ((err = aty128_var_to_crtc(var, &(par->crtc), info)))
+	return err;
+
+    if ((err = aty128_var_to_pll(var->pixclock, &(par->pll), info)))
+	return err;
+
+    if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info)))
+	return err;
+
+    if (var->accel_flags & FB_ACCELF_TEXT)
+	par->accel_flags = FB_ACCELF_TEXT;
+    else
+	par->accel_flags = 0;
+
+    return 0;
+}
+
+
+static int
+aty128_encode_var(struct fb_var_screeninfo *var,
+			const struct aty128fb_par *par,
+			const struct fb_info_aty128 *info)
+{
+    int err;
+
+    //memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+    /* XXX aty128_*_to_var() aren't fully implemented! */
+    if ((err = aty128_crtc_to_var(&par->crtc, var)))
+	return err;
+
+    if ((err = aty128_pll_to_var(&par->pll, var)))
+	return err;
+
+    if ((err = aty128_bpp_to_var(var->bits_per_pixel, var)))
+	return err;
+
+    var->height = -1;
+    var->width = -1;
+    var->accel_flags = par->accel_flags;
+
+    return 0;
+}           
+
+
+    /*
+     *  Get the User Defined Part of the Display
+     */
+
+static int
+aty128fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+    const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+
+    if (con == -1)
+	aty128_encode_var(var, &info->default_par, info); 
+    else
+	*var = fb_display[con].var;
+    return 0;
+}
+
+
+    /*
+     *  Set the User Defined Part of the Display
+     */
+
+static int
+aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+    struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+    struct aty128fb_par par;
+    struct display *display;
+    int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
+    int accel, err;
+
+    display = (con >= 0) ? &fb_display[con] : fb->disp;
+
+    if ((err = aty128_decode_var(var, &par, info)))
+	return err;
+
+    aty128_encode_var(var, &par, info);
+
+    if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+	return 0;
+
+    oldxres = display->var.xres;
+    oldyres = display->var.yres;
+    oldvxres = display->var.xres_virtual;
+    oldvyres = display->var.yres_virtual;
+    oldbpp = display->var.bits_per_pixel;
+    oldaccel = display->var.accel_flags;
+    display->var = *var;
+    if (oldxres != var->xres || oldyres != var->yres ||
+	oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+	oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
+
+	struct fb_fix_screeninfo fix;
+	aty128_encode_fix(&fix, &par, info);
+	display->screen_base = (char *) info->frame_buffer;
+	display->visual = fix.visual;
+	display->type = fix.type;
+	display->type_aux = fix.type_aux;
+	display->ypanstep = fix.ypanstep;
+	display->ywrapstep = fix.ywrapstep;
+	display->line_length = fix.line_length;
+	display->can_soft_blank = 1;
+	display->inverse = 0;
+
+	accel = var->accel_flags & FB_ACCELF_TEXT;
+	aty128_set_disp(display, info, var->bits_per_pixel, accel);
+
+#if 0	/* acceleration is not ready */
+	if (accel)
+	    display->scrollmode = 0;
+	else
+#endif
+	    display->scrollmode = SCROLL_YREDRAW;
+
+	if (info->fb_info.changevar)
+	    (*info->fb_info.changevar)(con);
+    }
+
+    if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con)
+	aty128_set_par(&par, info);
+
+    if (oldbpp != var->bits_per_pixel) {
+	if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+	    return err;
+	do_install_cmap(con, &info->fb_info);
+    } 
+
+    return 0;
+}
+
+
+static void
+aty128_set_disp(struct display *disp,
+			struct fb_info_aty128 *info, int bpp, int accel)
+{
+    switch (bpp) {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+	disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB16
+    case 16:
+	disp->dispsw = &fbcon_cfb16;
+	disp->dispsw_data = info->fbcon_cmap.cfb16;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB24
+    case 24:
+	disp->dispsw = &fbcon_cfb24;
+	disp->dispsw_data = info->fbcon_cmap.cfb24;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+	disp->dispsw = &fbcon_cfb32;
+	disp->dispsw_data = info->fbcon_cmap.cfb32;
+	break;
+#endif
+    default:
+	disp->dispsw = &fbcon_dummy;
+    }
+}
+
+
+static void
+aty128_encode_fix(struct fb_fix_screeninfo *fix,
+			struct aty128fb_par *par,
+			const struct fb_info_aty128 *info)
+{
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+    
+    strcpy(fix->id, aty128fb_name);
+    fix->smem_start = (long) info->frame_buffer_phys;
+    fix->smem_len = info->vram_size;
+
+    fix->mmio_start = (long) info->regbase_phys;
+    fix->mmio_len = 0x1fff;
+
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+    fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+					: FB_VISUAL_DIRECTCOLOR;
+
+    fix->xpanstep = 8;
+    fix->ypanstep = 1;
+
+    fix->accel = FB_ACCEL_ATI_RAGE128;
+    return;
+}
+
+
+    /*
+     *  Get the Fixed Part of the Display
+     */
+static int
+aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+    const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+    struct aty128fb_par par;
+
+    if (con == -1)
+	par = info->default_par;
+    else
+	aty128_decode_var(&fb_display[con].var, &par, info); 
+
+    aty128_encode_fix(fix, &par, info);
+    return 0;            
+}
+
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  Not supported (yet!)
+     */
+static int
+aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info)
+{
+    if (var->xoffset != 0 || var->yoffset != 0)
+	return -EINVAL;
+
+    return 0;
+}
+
+
+    /*
+     *  Get the Colormap
+     */
+
+static int
+aty128fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info)
+{
+    if (!info->display_fg ||
+	con == info->display_fg->vc_num) /* current console ? */        
+	return fb_get_cmap(cmap, kspc, aty128_getcolreg, info);
+    else if (fb_display[con].cmap.len) /* non default colormap? */
+	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+    else {  
+	int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32;
+	fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+    }
+    return 0;
+}
+
+    /*
+     *  Set the Colormap
+     */
+
+static int
+aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info)
+{
+    int err;
+    struct display *disp;  
+
+    if (con >= 0)
+	disp = &fb_display[con];
+    else
+	disp = info->disp;
+    if (!disp->cmap.len) {      /* no colormap allocated? */
+	int size = (disp->var.bits_per_pixel <= 16) ? 256 : 32;
+	if ((err = fb_alloc_cmap(&disp->cmap, size, 0)))
+	    return err;
+    }
+    if (!info->display_fg || con == info->display_fg->vc_num)
+/* current console? */
+	return fb_set_cmap(cmap, kspc, aty128_setcolreg, info);
+    else
+	fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+    return 0;                
+}
+
+
+    /*
+     *  Virtual Frame Buffer Specific ioctls
+     */
+
+static int
+aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		     u_long arg, int con, struct fb_info *info)
+{
+    return -EINVAL;
+}
+
+
+int __init
+aty128fb_setup(char *options)
+{
+    char *this_opt;
+
+    if (!options || !*options)
+	return 0;
+
+    for (this_opt = strtok(options, ","); this_opt;
+	 this_opt = strtok(NULL, ",")) {
+	if (!strncmp(this_opt, "font:", 5)) {
+	    char *p;
+	    int i;
+	    
+	    p = this_opt +5;
+	    for (i = 0; i < sizeof(fontname) - 1; i++)
+		if (!*p || *p == ' ' || *p == ',')
+		    break;
+	    memcpy(fontname, this_opt + 5, i);
+	    fontname[i] = 0;
+	}
+#if defined(CONFIG_PPC)
+	if (!strncmp(this_opt, "vmode:", 6)) {
+            unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+            if (vmode > 0 && vmode <= VMODE_MAX)
+                default_vmode = vmode;
+        } else if (!strncmp(this_opt, "cmode:", 6)) {
+            unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+            switch (cmode) {
+	    case 0:
+	    case 8:
+		default_cmode = CMODE_8;
+		break;
+	    case 15:
+	    case 16:
+		default_cmode = CMODE_16;
+		break;
+	    case 24:
+	    case 32:
+		default_cmode = CMODE_32;
+		break;
+            }
+        }
+#endif
+#ifdef CONFIG_MTRR
+	if(mtrr) {
+		ACCESS_FBINFO(mtrr.vram) =
+			mtrr_add(video_base_phys, ACCESS_FBINFO(video.len),
+				MTRR_TYPE_WRCOMB, 1);
+		ACCESS_FBINFO(mtrr.valid_vram) = 1;
+		printk(KERN_INFO "aty128fb: MTRR set to ON\n");
+	}
+#endif
+    }
+    return 0;
+}
+
+
+    /*
+     *  Initialisation
+     */
+
+static int
+aty128_init(struct fb_info_aty128 *info, const char *name)
+{
+    struct fb_var_screeninfo var;
+    u32 dac;
+    int j, k;
+    u8 chip_rev;
+
+    if (!register_test(info)) {
+	printk("Can't write to video registers\n");
+	return 0;
+    }
+
+    if (!info->vram_size)	/* may have already been probed */
+	info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+    chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
+
+    /* TODO be more verbose */
+    printk("aty128fb: Rage128 [rev 0x%x] ", chip_rev);
+
+    if (info->vram_size % (1024 * 1024) == 0)
+	printk("%dM ", info->vram_size / (1024*1024));
+    else
+	printk("%dk ", info->vram_size / 1024);
+
+    var = default_var;
+
+#ifdef CONFIG_PMAC
+
+    if (default_vmode == VMODE_NVRAM) {
+#ifdef CONFIG_NVRAM
+	default_vmode = nvram_read_byte(NV_VMODE);
+	if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+#endif /* CONFIG_NVRAM */
+	    default_vmode = VMODE_CHOOSE;
+    }
+
+    if (default_cmode == CMODE_NVRAM) {
+#ifdef CONFIG_NVRAM
+	default_cmode = nvram_read_byte(NV_CMODE);
+	if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+#endif /* CONFIG_NVRAM */
+	    default_vmode = VMODE_CHOOSE;
+    }
+
+    if (default_vmode != VMODE_CHOOSE &&
+	mac_vmode_to_var(default_vmode, default_cmode, &var))
+	var = default_var;
+
+#endif /* CONFIG_PMAC */
+
+    if (aty128_decode_var(&var, &info->default_par, info)) {
+	printk("Cannot set default mode.\n");
+	return 0;
+    }
+
+    /* fill in info */
+    strcpy(info->fb_info.modename, aty128fb_name);
+    info->fb_info.node = -1;
+    info->fb_info.fbops = &aty128fb_ops;
+    info->fb_info.disp = &info->disp;
+    strcpy(info->fb_info.fontname, fontname);
+    info->fb_info.changevar = NULL;
+    info->fb_info.switch_con = &aty128fbcon_switch;
+    info->fb_info.blank = &aty128fbcon_blank;
+    info->fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+    for (j = 0; j < 16; j++) {
+        k = color_table[j];
+        info->palette[j].red = default_red[k];
+        info->palette[j].green = default_grn[k];
+        info->palette[j].blue = default_blu[k];
+    }
+
+    dac = aty_ld_le32(DAC_CNTL) & 15;	/* preserve lower three bits */
+    dac |= DAC_8BIT_EN;			/* set 8 bit dac */
+    dac |= (0xFF << 24);		/* set DAC mask */
+    aty_st_le32(DAC_CNTL, dac);
+
+    /* turn off bus mastering, just in case */
+    aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS);
+
+    aty128fb_set_var(&var, -1, &info->fb_info);
+    aty128_init_engine(&info->default_par, info);
+
+    printk("\n");
+    if (register_framebuffer(&info->fb_info) < 0)
+	return 0;
+
+    printk("fb%d: %s frame buffer device on %s\n",
+	   GET_FB_IDX(info->fb_info.node), aty128fb_name, name);
+
+    return 1;	/* success! */
+}
+
+
+void __init
+aty128fb_init(void)
+{
+#if defined(CONFIG_FB_OF)
+/* let offb handle init */
+#elif defined (CONFIG_PCI)
+    aty128pci_probe();
+#endif
+}
+
+
+void
+aty128pci_probe(void)
+{
+    struct pci_dev *pdev;
+    struct fb_info_aty128 *info;
+    unsigned long fb_addr, reg_addr;
+    u16 tmp;
+
+    for (pdev = pci_devices; pdev; pdev = pdev->next) {
+	if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
+	    (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+	    struct resource *rp;
+
+	    /* FIXME add other known R128 device ID's */
+	    switch (pdev->device) {
+	    case 0x5245:
+	    case 0x5246:
+	    case 0x524B:
+	    case 0x524C:
+		break;
+	    default:
+		continue;
+	    }
+
+	    rp = &pdev->resource[0];
+	    fb_addr = rp->start;
+	    if (!fb_addr)
+		continue;
+	    fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	    rp = &pdev->resource[2];
+	    reg_addr = rp->start;
+	    if (!reg_addr)
+		continue;
+	    reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	    info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
+	    if (!info) {
+		printk("aty128fb: can't alloc fb_info_aty128\n");
+		return;
+	    }
+	    memset(info, 0, sizeof(struct fb_info_aty128));
+
+	    info->regbase_phys = reg_addr;
+	    info->regbase = (unsigned long) ioremap(reg_addr, 0x1FFF);
+
+	    if (!info->regbase) {
+		kfree(info);
+		return;
+	    }
+
+	    info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+	    info->frame_buffer = fb_addr;
+	    info->frame_buffer = (unsigned long)
+				    ioremap(fb_addr, info->vram_size);
+
+	    if (!info->frame_buffer) {
+		kfree(info);
+		return;
+	    }
+
+	    pci_read_config_word(pdev, PCI_COMMAND, &tmp);
+	    if (!(tmp & PCI_COMMAND_MEMORY)) {
+		tmp |= PCI_COMMAND_MEMORY;
+		pci_write_config_word(pdev, PCI_COMMAND, tmp);
+	    }
+
+#if defined(CONFIG_PPC)
+	    aty128_timings(info);
+#else
+            if (!aty128find_ROM(info)) {
+                printk("Rage128 BIOS not located.  Guessing...\n");
+                aty128_timings(info);
+            }
+            else
+                aty128_get_pllinfo(info);
+#endif
+
+	    if (!aty128_init(info, "PCI")) {
+		kfree(info);
+		return;
+	    }
+	}
+    }
+}
+
+
+static int
+aty128find_ROM(struct fb_info_aty128 *info)
+{
+    u32 segstart;
+    char *rom_base;
+    char *rom_base1;
+    char *rom;
+    int stage;
+    int i;
+    char aty_rom_sig[] = "761295520";
+    char R128_sig[] = "R128";
+    int flag = 0;
+DBG("E  aty128find_ROM");
+
+    for (segstart = 0x000c0000; segstart < 0x000f0000; segstart += 0x00001000) {
+        stage = 1;
+
+        rom_base = (char *) ioremap(segstart, 0x1000);
+        rom_base1 = (char *) (rom_base+1);
+
+        if ((*rom_base == 0x55) && (((*rom_base1) & 0xff) == 0xaa)) {
+            stage = 2;
+        }
+
+        if (stage != 2) {
+            iounmap(rom_base);
+            continue;
+        }
+        rom = rom_base;
+
+        for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) {
+            if (aty_rom_sig[0] == *rom) {
+                if (strncmp(aty_rom_sig, rom, strlen(aty_rom_sig)) == 0) {
+                    stage = 3;
+                }
+            }
+            rom++;
+        }
+        if (stage != 3) {
+            iounmap(rom_base);
+            continue;
+        }
+        rom = rom_base;
+
+        for (i = 0; (i < 512) && (stage != 4); i++) {
+            if (R128_sig[0] == *rom) {
+                if (strncmp(R128_sig, rom, strlen(R128_sig)) == 0) {
+                    stage = 4;
+                }
+            }
+            rom++;
+        }
+        if (stage != 4) {
+            iounmap(rom_base);
+            continue;
+        }
+
+        printk("Rage128 BIOS located at segment %4.4X\n", (u32)rom_base);
+        info->BIOS_SEG = (u32)rom_base;
+        flag = 1;
+
+        break;
+    }
+DBG("L  aty128find_ROM");
+    return (flag);
+}
+
+
+static void
+aty128_get_pllinfo(struct fb_info_aty128 *info)
+{   
+    u32 bios_header;
+    u32 *header_ptr;
+    u16 bios_header_offset, pll_info_offset;
+    PLL_BLOCK pll;
+DBG("E  aty128_get_pllinfo");
+
+    bios_header = info->BIOS_SEG + 0x48L;
+    header_ptr = (u32 *)bios_header;
+
+    bios_header_offset = (u16)*header_ptr;
+    bios_header = info->BIOS_SEG + (u32)bios_header_offset;
+    bios_header += 0x30;
+
+    header_ptr = (u32 *)bios_header;
+    pll_info_offset = (u16)*header_ptr;
+    header_ptr = (u32 *)(info->BIOS_SEG + (u32)pll_info_offset);
+
+    memcpy(&pll, header_ptr, 50);
+
+    info->constants.ppll_max = pll.PCLK_max_freq;
+    info->constants.ppll_min = pll.PCLK_min_freq;
+    info->constants.xclk = (u32)pll.XCLK;
+    info->constants.ref_divider = (u32)pll.PCLK_ref_divider;
+    info->constants.dotclock = (u32)pll.PCLK_ref_freq;
+
+    info->constants.fifo_width = 128;
+    info->constants.fifo_depth = 32;
+
+    switch(aty_ld_le32(MEM_CNTL) & 0x03) {
+    case 0:
+        info->mem = &sdr_128; 
+        break;
+    case 1:
+        info->mem = &sdr_sgram;
+        break;  
+    case 2: 
+        info->mem = &ddr_sgram;
+        break;  
+    default:        
+        info->mem = &sdr_sgram;
+    }       
+
+DBG("L  aty128get_pllinfo");
+    return;
+}           
+
+
+#ifdef CONFIG_FB_OF
+void
+aty128fb_of_init(struct device_node *dp)
+{
+    unsigned long addr, reg_addr, fb_addr;
+    struct fb_info_aty128 *info;
+    u8 bus, devfn;
+    u16 cmd;
+
+    switch (dp->n_addrs) {
+    case 3:
+	fb_addr = dp->addrs[0].address;
+	reg_addr = dp->addrs[2].address;
+	break;
+    default:
+	printk("aty128fb: TODO unexpected addresses\n");
+	return;
+    }
+
+    addr = (unsigned long) ioremap(reg_addr, 0x1FFF);
+    if (!addr) {
+	printk("aty128fb: can't map memory registers\n");
+	return;
+    }
+
+    info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
+    if (!info) {
+	printk("aty128fb: can't alloc fb_info_aty128\n");
+	return;
+    }
+    memset(info, 0, sizeof(struct fb_info_aty128));
+
+    info->regbase_phys = reg_addr;
+    info->regbase = addr;
+
+    /* enabled memory-space accesses using config-space command register */
+    if (pci_device_loc(dp, &bus, &devfn) == 0) {
+	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+	if (!(cmd & PCI_COMMAND_MEMORY)) {
+	    cmd |= PCI_COMMAND_MEMORY;
+	    pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+	}
+    }
+
+    info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+    info->frame_buffer_phys = fb_addr;
+    info->frame_buffer = (unsigned long) ioremap(fb_addr, info->vram_size);
+
+    /*
+     * TODO find OF values/hints.
+     *
+     * If we are booted from BootX, the MacOS ATI driver will likely have
+     * left useful tidbits in the DeviceRegistry.
+     */
+
+    if (!info->frame_buffer) {
+	printk("aty128fb: can't map frame buffer\n");
+	return;
+    }
+
+    aty128_timings(info);
+
+    if (!aty128_init(info, dp->full_name)) {
+	kfree(info);
+	return;
+    }
+}
+#endif
+
+
+/* fill in known card constants if pll_block is not available */
+static void
+aty128_timings(struct fb_info_aty128 *info)
+{
+    /* TODO make an attempt at probing */
+
+    info->constants.dotclock = 2950;
+
+    /* from documentation */
+    info->constants.ppll_min = 12500;
+    info->constants.ppll_max = 25000;	/* 23000 on some cards? */
+
+#if 1
+    /* XXX TODO. Calculate properly. Fix OF's pll ideas. */
+    info->constants.ref_divider = 0x3b;
+    aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
+    aty_pll_writeupdate(info);
+
+    aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+    aty_pll_writeupdate(info);
+#else
+    info->constants.ref_divider = aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
+
+    /* TODO. Calculate */
+    info->constants.xclk = 0x1d4d;	/* same as mclk */
+
+    info->constants.fifo_width = 128;
+    info->constants.fifo_depth = 32;
+
+    switch (aty_ld_le32(MEM_CNTL) & 0x3) {
+    case 0:
+	info->mem = &sdr_128;
+	break;
+    case 1:
+	info->mem = &sdr_sgram;
+	break;
+    case 2:
+	info->mem = &ddr_sgram;
+	break;
+    default:
+	info->mem = &sdr_sgram;
+    }
+}
+
+
+static int
+aty128fbcon_switch(int con, struct fb_info *fb)
+{
+    currcon = con;
+
+    /* Do we have to save the colormap? */
+    if (fb_display[currcon].cmap.len)
+	fb_get_cmap(&fb_display[currcon].cmap, 1, aty128_getcolreg, fb);
+
+#if 1
+    aty128fb_set_var(&fb_display[con].var, con, fb);
+#else
+{
+    struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb;
+    struct aty128fb_par par;
+
+    aty128_decode_var(&fb_display[con].var, &par, info);
+    aty128_set_par(&par, info);
+    aty128_set_disp(&fb_display[con], info,
+	fb_display[con].var.bits_per_pixel);
+
+    do_install_cmap(con, fb);
+}
+#endif
+
+    return 1;
+}
+
+
+    /*
+     *  Blank the display.
+     */
+
+static void
+aty128fbcon_blank(int blank, struct fb_info *fb)
+{
+    struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
+    u8 state = 0;
+
+    if (blank & VESA_VSYNC_SUSPEND)
+	state |= 2;
+    if (blank & VESA_HSYNC_SUSPEND)
+	state |= 1;
+    if (blank & VESA_POWERDOWN)
+	state |= 4;
+
+    aty_st_8(CRTC_EXT_CNTL+1, state);
+}
+
+
+    /*
+     *  Read a single color register and split it into
+     *  colors/transparent. Return != 0 for invalid regno.
+     */
+static int
+aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp, struct fb_info *fb)
+{
+    struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb;
+
+    if (regno > 255)
+	return 1;
+
+    *red = (info->palette[regno].red<<8) | info->palette[regno].red;
+    *green = (info->palette[regno].green<<8) | info->palette[regno].green;
+    *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue;
+    *transp = 0;
+    return 0;
+}
+
+
+    /*
+     *  Set a single color register. The values supplied are already
+     *  rounded down to the hardware's capabilities (according to the
+     *  entries in the var structure). Return != 0 for invalid regno.
+     */
+static int
+aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *fb)
+{
+    struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb;
+    u32 col;
+
+    if (regno > 255)
+	return 1;
+
+    red >>= 8;
+    green >>= 8;
+    blue >>= 8;
+    info->palette[regno].red = red;
+    info->palette[regno].green = green;
+    info->palette[regno].blue = blue;
+
+    aty_st_8(PALETTE_INDEX, regno);
+    col = red << 16 | green << 8 | blue;
+    aty_st_le32(PALETTE_DATA, col);
+
+    if (regno < 16)
+	switch (info->current_par.crtc.bpp) {
+#ifdef FBCON_HAS_CFB16
+	case 16:
+	    info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
+		regno;
+	    break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+	    info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) |
+		regno;
+	    break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+	    {
+		u32 i;
+		i = (regno << 8) | regno;
+		info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
+	    }
+	    break;
+#endif
+	}
+    return 0;
+}
+
+
+static void
+do_install_cmap(int con, struct fb_info *info)
+{
+    if (con != currcon)
+	return;
+    if (fb_display[con].cmap.len)
+	fb_set_cmap(&fb_display[con].cmap, 1, aty128_setcolreg, info);
+    else {
+	int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 16;
+	fb_set_cmap(fb_default_cmap(size), 1, aty128_setcolreg, info);
+    }
+}
+
+
+    /*
+     *  Accelerated functions
+     */
+
+static void
+aty128_rectdraw(s16 x, s16 y, u16 width, u16 height,
+		struct fb_info_aty128 *info)
+{
+    /* perform rectangle fill */
+    wait_for_fifo(2, info);
+    aty_st_le32(DST_Y_X, (y << 16) | x);
+    aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
+}
+
+
+static void
+aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
+		u_int width, u_int height,
+		struct fb_info_aty128 *info)
+{
+    u32 direction = DST_LAST_PEL;
+    u32 pitch_value;
+
+    if (!width || !height)
+        return;
+
+    pitch_value = info->current_par.crtc.vxres;
+    if (info->current_par.crtc.bpp == 24) {
+        /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+        /* horizontal coordinates and widths must be adjusted */
+        pitch_value *= 3;
+        srcx *= 3;
+        dstx *= 3;
+        width *= 3;
+    }
+    
+    if (srcy < dsty) {
+        dsty += height - 1;
+        srcy += height - 1;
+    } else
+        direction |= DST_Y_TOP_TO_BOTTOM;
+
+    if (srcx < dstx) {
+        dstx += width - 1;
+        srcx += width - 1;
+    } else
+        direction |= DST_X_LEFT_TO_RIGHT;
+
+    wait_for_fifo(4, info);
+    aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
+    aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
+    aty_st_le32(DP_CNTL, direction);
+    aty_st_le32(DP_DATATYPE, aty_ld_le32(DP_DATATYPE) | SRC_DSTCOLOR);
+    aty128_rectdraw(dstx, dsty, width, height, info);
+}
+
+static void
+fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			int height, int width)
+{
+    sx *= fontwidth(p);
+    sy *= fontheight(p);
+    dx *= fontwidth(p);
+    dy *= fontheight(p);
+    width *= fontwidth(p);
+    height *= fontheight(p);
+
+    aty128_rectcopy(sx, sy, dx, dy, width, height,
+			(struct fb_info_aty128 *)p->fb_info);
+}
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_aty128_8 = {
+    fbcon_cfb8_setup, fbcon_aty128_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc,
+    fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#if defined(MODULE) && defined(DEBUG)
+int
+init_module(void)
+{
+    aty128pci_probe();
+    return 0;
+}
+
+void
+cleanup_module(void)
+{
+/* XXX unregister! */
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.22/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.22/linux/drivers/video/atyfb.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/atyfb.c	Mon Oct 18 11:37:43 1999
@@ -2192,7 +2192,7 @@
     }
     dsp_precision -= 5;
     /* fifo_off<<6 */
-    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(1<<6);
+    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6);
 
     if (info->total_vram > 1*1024*1024) {
 	if (info->ram_type >= SDRAM) {
@@ -2219,7 +2219,7 @@
     if (xclks_per_row >= (page_size<<11))
 	fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
     else
-	fifo_on = (3*page_size)<<6;
+	fifo_on = (3*page_size+2)<<6;
 
     dsp_xclks_per_row = xclks_per_row>>dsp_precision;
     dsp_on = fifo_on>>dsp_precision;
diff -u --recursive --new-file v2.3.22/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- v2.3.22/linux/drivers/video/chipsfb.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/chipsfb.c	Mon Oct 18 11:37:43 1999
@@ -282,6 +282,14 @@
 	// useful at blank = 1 too (saves battery, extends backlight life)
 	if (blank) {
 		pmu_enable_backlight(0);
+		/* get the palette from the chip */
+		for (i = 0; i < 256; ++i) {
+			out_8(p->io_base + 0x3c7, i);
+			udelay(1);
+			p->palette[i].red = in_8(p->io_base + 0x3c9);
+			p->palette[i].green = in_8(p->io_base + 0x3c9);
+			p->palette[i].blue = in_8(p->io_base + 0x3c9);
+		}
 		for (i = 0; i < 256; ++i) {
 			out_8(p->io_base + 0x3c8, i);
 			udelay(1);
@@ -291,7 +299,13 @@
 		}
 	} else {
 		pmu_enable_backlight(1);
-		do_install_cmap(currcon, info);
+		for (i = 0; i < 256; ++i) {
+			out_8(p->io_base + 0x3c8, i);
+			udelay(1);
+			out_8(p->io_base + 0x3c9, p->palette[i].red);
+			out_8(p->io_base + 0x3c9, p->palette[i].green);
+			out_8(p->io_base + 0x3c9, p->palette[i].blue);
+		}
 	}
 }
 
@@ -711,20 +725,10 @@
 
 	for (p = all_chips; p != NULL; p = p->next) {
 		int nb = p->var.yres * p->fix.line_length;
-		int i;
 
 		switch (when) {
 		case PBOOK_SLEEP_NOW:
 			chipsfb_blank(1, (struct fb_info *)p);
-			/* get the palette from the chip, Xpmac seems
-			   to set it directly in the chip */
-			for (i = 0; i < 256; ++i) {
-				out_8(p->io_base + 0x3c8, i);
-				udelay(1);
-				p->palette[i].red = in_8(p->io_base + 0x3c9);
-				p->palette[i].green = in_8(p->io_base + 0x3c9);
-				p->palette[i].blue = in_8(p->io_base + 0x3c9);
-			}
 			p->save_framebuffer = vmalloc(nb);
 			if (p->save_framebuffer)
 				memcpy(p->save_framebuffer,
diff -u --recursive --new-file v2.3.22/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.22/linux/drivers/video/fbmem.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/video/fbmem.c	Thu Oct 21 13:38:08 1999
@@ -68,6 +68,8 @@
 extern int offb_setup(char*);
 extern int atyfb_init(void);
 extern int atyfb_setup(char*);
+extern int aty128fb_init(void);
+extern int aty128fb_setup(char*);
 extern int igafb_init(void);
 extern int igafb_setup(char*);
 extern int imsttfb_init(void);
@@ -149,6 +151,9 @@
 #endif
 #ifdef CONFIG_FB_ATY
 	{ "atyfb", atyfb_init, atyfb_setup },
+#endif
+#ifdef CONFIG_FB_ATY128
+	{ "aty128fb", aty128fb_init, aty128fb_setup },
 #endif
 #ifdef CONFIG_FB_IGA
         { "igafb", igafb_init, igafb_setup },
diff -u --recursive --new-file v2.3.22/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.3.22/linux/drivers/video/offb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/offb.c	Mon Oct 18 11:37:43 1999
@@ -293,6 +293,9 @@
 #ifdef CONFIG_FB_ATY
 extern void atyfb_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_ATY */
+#ifdef CONFIG_FB_ATY128
+extern void aty128fb_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_ATY */
 #ifdef CONFIG_FB_S3TRIO
 extern void s3triofb_init_of(struct device_node *dp);
 #endif /* CONFIG_FB_S3TRIO */
@@ -349,6 +352,21 @@
 		    dp->addrs[0].size = 0x01000000;
 		}
 	    }
+
+	    /*
+	     * The LTPro on the Lombard powerbook has no addresses
+	     * on the display nodes, they are on their parent.
+	     */
+	    if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,264LTPro")) {
+		int na;
+		unsigned int *ap = (unsigned int *)
+		    get_property(dp, "AAPL,address", &na);
+		if (ap != 0)
+		    for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
+			if (*ap <= addr && addr < *ap + 0x1000000)
+			    goto foundit;
+	    }
+
 	    /*
 	     * See if the display address is in one of the address
 	     * ranges for this display.
@@ -359,6 +377,7 @@
 		    break;
 	    }
 	    if (i < dp->n_addrs) {
+	    foundit:
 		printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
 		macos_display = dp;
 		break;
@@ -397,6 +416,12 @@
 
 static int __init offb_init_driver(struct device_node *dp)
 {
+#ifdef CONFIG_FB_ATY128
+    if (!strncmp(dp->name, "ATY,Rage128", 11)) {
+	aty128fb_of_init(dp);
+	return 1;
+    }
+#endif
 #ifdef CONFIG_FB_ATY
     if (!strncmp(dp->name, "ATY", 3)) {
 	atyfb_of_init(dp);
diff -u --recursive --new-file v2.3.22/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.22/linux/fs/binfmt_aout.c	Fri Oct 15 15:25:14 1999
+++ linux/fs/binfmt_aout.c	Sat Oct 16 09:42:22 1999
@@ -270,7 +270,6 @@
 	unsigned long fd_offset;
 	unsigned long rlim;
 	int retval;
-	static unsigned long error_time=0;
 
 	ex = *((struct exec *) bprm->buf);		/* exec-header */
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -282,29 +281,6 @@
 
 	fd_offset = N_TXTOFF(ex);
 
-#ifdef __i386__
-	if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
-		if((jiffies-error_time) >5)
-		{
-			printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
-			error_time=jiffies;
-		}
-		return -ENOEXEC;
-	}
-
-	if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
-	    bprm->dentry->d_inode->i_op &&
-	    bprm->dentry->d_inode->i_op->get_block &&
-	    (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
-		if((jiffies-error_time) >5)
-		{
-			printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
-			error_time=jiffies;
-		}
-		return -ENOEXEC;
-	}
-#endif
-
 	/* Check initial limits. This avoids letting people circumvent
 	 * size limits imposed on them by creating programs with large
 	 * arrays in the data or bss.
@@ -364,26 +340,32 @@
 		flush_icache_range((unsigned long) 0,
 				   (unsigned long) ex.a_text+ex.a_data);
 	} else {
+		static unsigned long error_time, error_time2;
 		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
-		    (N_MAGIC(ex) != NMAGIC))
+		    (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
+		{
 			printk(KERN_NOTICE "executable not page aligned\n");
+			error_time2 = jiffies;
+		}
 
 		fd = open_dentry(bprm->dentry, O_RDONLY);
 		if (fd < 0)
 			return fd;
 		file = fget(fd);
 
-		if ((fd_offset & ~PAGE_MASK) != 0) {
+		if ((fd_offset & ~PAGE_MASK) != 0 &&
+		    (jiffies-error_time) > 5*HZ)
+		{
 			printk(KERN_WARNING 
 			       "fd_offset is not page aligned. Please convert program: %s\n",
-			       file->f_dentry->d_name.name
-			       );
+			       file->f_dentry->d_name.name);
+			error_time = jiffies;
 		}
 
 		if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
 			fput(file);
 			sys_close(fd);
-			do_brk(0, ex.a_text+ex.a_data);
+			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
 			read_exec(bprm->dentry, fd_offset,
 				  (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
 			flush_icache_range((unsigned long) N_TXTADDR(ex),
@@ -493,12 +475,6 @@
 		goto out_putf;
 	}
 
-	if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
-	    (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
-		printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
-		goto out_putf;
-	}
-
 	if (N_FLAGS(ex))
 		goto out_putf;
 
@@ -508,14 +484,17 @@
 	start_addr =  ex.a_entry & 0xfffff000;
 
 	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
-		printk(KERN_WARNING 
-		       "N_TXTOFF is not page aligned. Please convert library: %s\n",
-		       file->f_dentry->d_name.name
-		       );
-		
-		do_mmap(NULL, start_addr & PAGE_MASK, ex.a_text + ex.a_data + ex.a_bss,
-			PROT_READ | PROT_WRITE | PROT_EXEC,
-			MAP_FIXED| MAP_PRIVATE, 0);
+		static unsigned long error_time;
+
+		if ((jiffies-error_time) > 5*HZ)
+		{
+			printk(KERN_WARNING 
+			       "N_TXTOFF is not page aligned. Please convert library: %s\n",
+			       file->f_dentry->d_name.name);
+			error_time = jiffies;
+		}
+
+		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
 		
 		read_exec(file->f_dentry, N_TXTOFF(ex),
 			  (char *)start_addr, ex.a_text + ex.a_data, 0);
diff -u --recursive --new-file v2.3.22/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.22/linux/fs/buffer.c	Fri Oct 15 15:25:14 1999
+++ linux/fs/buffer.c	Tue Oct 19 12:15:36 1999
@@ -26,6 +26,8 @@
 
 /* Thread it... -DaveM */
 
+/* async buffer flushing, 1999 Andrea Arcangeli <andrea@suse.de> */
+
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/malloc.h>
@@ -76,6 +78,7 @@
 static struct buffer_head *lru_list[NR_LIST];
 static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED;
 static int nr_buffers_type[NR_LIST] = {0,};
+static unsigned long size_buffers_type[NR_LIST] = {0,};
 
 static struct buffer_head * unused_list = NULL;
 static int nr_unused_buffer_heads = 0;
@@ -93,7 +96,7 @@
 static int grow_buffers(int size);
 
 /* This is used by some architectures to estimate available memory. */
-atomic_t buffermem = ATOMIC_INIT(0);
+atomic_t buffermem_pages = ATOMIC_INIT(0);
 
 /* Here is the parameter block for the bdflush process. If you add or
  * remove any of the parameters, make sure to update kernel/sysctl.c.
@@ -114,18 +117,18 @@
 				each time we call refill */
 		int nref_dirt; /* Dirty buffer threshold for activating bdflush
 				  when trying to refill buffers. */
-		int dummy1;    /* unused */
+		int interval; /* jiffies delay between kupdate flushes */
 		int age_buffer;  /* Time for normal buffer to age before we flush it */
 		int age_super;  /* Time for superblock to age before we flush it */
 		int dummy2;    /* unused */
 		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*HZ, 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_max[N_PARAM] = {100,50000, 20000, 20000,1000, 6000*HZ, 6000*HZ, 2047, 5};
+int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 6000*HZ, 2047, 5};
 
 void wakeup_bdflush(int);
 
@@ -482,6 +485,7 @@
 	(*bhp)->b_prev_free->b_next_free = bh;
 	(*bhp)->b_prev_free = bh;
 	nr_buffers_type[blist]++;
+	size_buffers_type[blist] += bh->b_size;
 }
 
 static void __remove_from_lru_list(struct buffer_head * bh, int blist)
@@ -495,6 +499,7 @@
 			lru_list[blist] = NULL;
 		bh->b_next_free = bh->b_prev_free = NULL;
 		nr_buffers_type[blist]--;
+		size_buffers_type[blist] -= bh->b_size;
 	}
 }
 
@@ -813,6 +818,27 @@
 	return bh;
 }
 
+/* -1 -> no need to flush
+    0 -> async flush
+    1 -> sync flush (wait for I/O completation) */
+static int balance_dirty_state(kdev_t dev)
+{
+	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
+
+	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+	tot = nr_lru_pages + nr_free_pages + nr_free_highpages;
+	hard_dirty_limit = tot * bdf_prm.b_un.nfract / 100;
+	soft_dirty_limit = hard_dirty_limit >> 1;
+
+	if (dirty > soft_dirty_limit)
+	{
+		if (dirty > hard_dirty_limit)
+			return 1;
+		return 0;
+	}
+	return -1;
+}
+
 /*
  * if a new dirty buffer is created we need to balance bdflush.
  *
@@ -820,23 +846,13 @@
  * pressures on different devices - thus the (currently unused)
  * 'dev' parameter.
  */
-static int too_many_dirty_buffers;
-
 void balance_dirty(kdev_t dev)
 {
-	int dirty = nr_buffers_type[BUF_DIRTY];
-	int ndirty = bdf_prm.b_un.ndirty;
+	int state = balance_dirty_state(dev);
 
-	if (dirty > ndirty) {
-		if (dirty > 2*ndirty) {
-			too_many_dirty_buffers = 1;
-			wakeup_bdflush(1);
-			return;
-		}
-		wakeup_bdflush(0);
-	}
-	too_many_dirty_buffers = 0;
-	return;
+	if (state < 0)
+		return;
+	wakeup_bdflush(state);
 }
 
 static inline void __mark_dirty(struct buffer_head *bh, int flag)
@@ -1250,7 +1266,7 @@
 	 */
 	if (!offset) {
 		if (!try_to_free_buffers(page)) {
-			atomic_add(PAGE_CACHE_SIZE, &buffermem);
+			atomic_inc(&buffermem_pages);
 			return 0;
 		}
 	}
@@ -1364,6 +1380,7 @@
 	unsigned long bbits, blocks, i, len;
 	struct buffer_head *bh, *head;
 	char * target_buf;
+	int need_balance_dirty;
 
 	target_buf = (char *)page_address(page) + offset;
 
@@ -1403,6 +1420,7 @@
 	i = 0;
 	bh = head;
 	partial = 0;
+	need_balance_dirty = 0;
 	do {
 		if (!bh)
 			BUG();
@@ -1473,8 +1491,7 @@
 		set_bit(BH_Uptodate, &bh->b_state);
 		if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
 			__mark_dirty(bh, 0);
-			if (too_many_dirty_buffers)
-				balance_dirty(bh->b_dev);
+			need_balance_dirty = 1;
 		}
 
 		if (err) {
@@ -1488,6 +1505,9 @@
 		bh = bh->b_this_page;
 	} while (bh != head);
 
+	if (need_balance_dirty)
+		balance_dirty(bh->b_dev);
+
 	/*
 	 * is this a partial write that happened to make all buffers
 	 * uptodate then we can optimize away a bogus readpage() for
@@ -1519,6 +1539,7 @@
 	struct buffer_head *bh, *head;
 	char * target_buf, *target_data;
 	unsigned long data_offset = offset;
+	int need_balance_dirty;
 
 	offset = inode->i_size - page->offset;
 	if (page->offset>inode->i_size)
@@ -1566,6 +1587,7 @@
 	i = 0;
 	bh = head;
 	partial = 0;
+	need_balance_dirty = 0;
 	do {
 		if (!bh)
 			BUG();
@@ -1644,8 +1666,7 @@
 		set_bit(BH_Uptodate, &bh->b_state);
 		if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
 			__mark_dirty(bh, 0);
-			if (too_many_dirty_buffers)
-				balance_dirty(bh->b_dev);
+			need_balance_dirty = 1;
 		}
 
 		if (err) {
@@ -1659,6 +1680,9 @@
 		bh = bh->b_this_page;
 	} while (bh != head);
 
+	if (need_balance_dirty)
+		balance_dirty(bh->b_dev);
+
 	/*
 	 * is this a partial write that happened to make all buffers
 	 * uptodate then we can optimize away a bogus readpage() for
@@ -1809,12 +1833,12 @@
 		dprintk ("iobuf %d %d %d\n", offset, length, size);
 
 		for (pageind = 0; pageind < iobuf->nr_pages; pageind++) {
-			page = iobuf->pagelist[pageind];
 			map  = iobuf->maplist[pageind];
-			if (map && PageBIGMEM(map)) {
+			if (map && PageHighMem(map)) {
 				err = -EIO;
 				goto error;
 			}
+			page = page_address(map);
 
 			while (length > 0) {
 				blocknr = b[bufind++];
@@ -2090,7 +2114,7 @@
 	page_map = mem_map + MAP_NR(page);
 	page_map->buffers = bh;
 	lru_cache_add(page_map);
-	atomic_add(PAGE_SIZE, &buffermem);
+	atomic_inc(&buffermem_pages);
 	return 1;
 
 no_buffer_head:
@@ -2168,12 +2192,53 @@
 
 busy_buffer_page:
 	/* Uhhuh, start writeback so that we don't end up with all dirty pages */
-	too_many_dirty_buffers = 1;
 	wakeup_bdflush(0);
 	ret = 0;
 	goto out;
 }
 
+/* ================== Debugging =================== */
+
+void show_buffers(void)
+{
+	struct buffer_head * bh;
+	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
+	int protected = 0;
+	int nlist;
+	static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY" };
+
+	printk("Buffer memory:   %6dkB\n",
+			atomic_read(&buffermem_pages) << (PAGE_SHIFT-10));
+
+#ifdef __SMP__ /* trylock does nothing on UP and so we could deadlock */
+	if (!spin_trylock(&lru_list_lock))
+		return;
+	for(nlist = 0; nlist < NR_LIST; nlist++) {
+		found = locked = dirty = used = lastused = protected = 0;
+		bh = lru_list[nlist];
+		if(!bh) continue;
+
+		do {
+			found++;
+			if (buffer_locked(bh))
+				locked++;
+			if (buffer_protected(bh))
+				protected++;
+			if (buffer_dirty(bh))
+				dirty++;
+			if (atomic_read(&bh->b_count))
+				used++, lastused = found;
+			bh = bh->b_next_free;
+		} while (bh != lru_list[nlist]);
+		printk("%8s: %d buffers, %d used (last=%d), "
+		       "%d locked, %d protected, %d dirty\n",
+		       buf_types[nlist], found, used, lastused,
+		       locked, protected, dirty);
+	}
+	spin_unlock(&lru_list_lock);
+#endif
+}
+
 /* ===================== Init ======================= */
 
 /*
@@ -2181,7 +2246,7 @@
  * Use gfp() for the hash table to decrease TLB misses, use
  * SLAB cache for buffer heads.
  */
-void __init buffer_init(unsigned long memory_size)
+void __init buffer_init(unsigned long mempages)
 {
 	int order, i;
 	unsigned int nr_hash;
@@ -2189,9 +2254,11 @@
 	/* The buffer cache hash table is less important these days,
 	 * trim it a bit.
 	 */
-	memory_size >>= 14;
-	memory_size *= sizeof(struct buffer_head *);
-	for (order = 0; (PAGE_SIZE << order) < memory_size; order++)
+	mempages >>= 14;
+
+	mempages *= sizeof(struct buffer_head *);
+
+	for (order = 0; (1 << order) < mempages; order++)
 		;
 
 	/* try to allocate something until we get it or we're asking
@@ -2246,21 +2313,92 @@
  * 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 DECLARE_WAIT_QUEUE_HEAD(bdflush_wait);
 static DECLARE_WAIT_QUEUE_HEAD(bdflush_done);
 struct task_struct *bdflush_tsk = 0;
 
-void wakeup_bdflush(int wait)
+void wakeup_bdflush(int block)
 {
+	DECLARE_WAITQUEUE(wait, current);
+
 	if (current == bdflush_tsk)
 		return;
-	if (wait)
-		run_task_queue(&tq_disk);
-	wake_up(&bdflush_wait);
-	if (wait)
-		sleep_on(&bdflush_done);
-}
 
+	if (!block)
+	{
+		wake_up_process(bdflush_tsk);
+		return;
+	}
+
+	/* kflushd can wakeup us before we have a chance to
+	   go to sleep so we must be smart in handling
+	   this wakeup event from kflushd to avoid deadlocking in SMP
+	   (we are not holding any lock anymore in these two paths). */
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&bdflush_done, &wait);
+
+	wake_up_process(bdflush_tsk);
+	schedule();
+
+	remove_wait_queue(&bdflush_done, &wait);
+	__set_current_state(TASK_RUNNING);
+}
+
+/* This is the _only_ function that deals with flushing async writes
+   to disk.
+   NOTENOTENOTENOTE: we _only_ need to browse the DIRTY lru list
+   as all dirty buffers lives _only_ in the DIRTY lru list.
+   As we never browse the LOCKED and CLEAN lru lists they are infact
+   completly useless. */
+static void flush_dirty_buffers(int check_flushtime)
+{
+	struct buffer_head * bh, *next;
+	int flushed = 0, i;
+
+ restart:
+	spin_lock(&lru_list_lock);
+	bh = lru_list[BUF_DIRTY];
+	if (!bh)
+		goto out_unlock;
+	for (i = nr_buffers_type[BUF_DIRTY]; i-- > 0; bh = next)
+	{
+		next = bh->b_next_free;
+
+		if (!buffer_dirty(bh))
+		{
+			__refile_buffer(bh);
+			continue;
+		}
+		if (buffer_locked(bh))
+			continue;
+
+		if (check_flushtime)
+		{
+			/* The dirty lru list is chronogical ordered so
+			   if the current bh is not yet timed out,
+			   then also all the following bhs
+			   will be too young. */
+			if (time_before(jiffies, bh->b_flushtime))
+				goto out_unlock;
+		}
+		else
+		{
+			if (++flushed > bdf_prm.b_un.ndirty)
+				goto out_unlock;
+		}
+
+		/* OK, now we are committed to write it out. */
+		atomic_inc(&bh->b_count);
+		spin_unlock(&lru_list_lock);
+		ll_rw_block(WRITE, 1, &bh);
+		atomic_dec(&bh->b_count);
+
+		if (current->need_resched)
+			schedule();
+		goto restart;
+	}
+ out_unlock:
+	spin_unlock(&lru_list_lock);
+}
 
 /* 
  * Here we attempt to write back old buffers.  We also try to flush inodes 
@@ -2272,47 +2410,13 @@
 
 static int sync_old_buffers(void)
 {
-	int nlist;
-
 	lock_kernel();
 	sync_supers(0);
 	sync_inodes(0);
 	unlock_kernel();
 
-	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) {
-		struct buffer_head *bh;
-	repeat:
-		spin_lock(&lru_list_lock);
-		bh = lru_list[nlist];
-		if(bh) {
-			struct buffer_head *next;
-			int i;
-			for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
-				next = bh->b_next_free;
-
-				/* If the buffer is not on the proper list,
-				 * then refile it.
-				 */
-				if ((nlist == BUF_DIRTY &&
-				     (!buffer_dirty(bh) && !buffer_locked(bh))) ||
-				    (nlist == BUF_LOCKED && !buffer_locked(bh))) {
-					__refile_buffer(bh);
-					continue;
-				}
-				 
-				if (buffer_locked(bh) || !buffer_dirty(bh))
-					continue;
-
-				/* OK, now we are committed to write it out. */
-				atomic_inc(&bh->b_count);
-				spin_unlock(&lru_list_lock);
-				ll_rw_block(WRITE, 1, &bh);
-				atomic_dec(&bh->b_count);
-				goto repeat;
-			}
-		}
-		spin_unlock(&lru_list_lock);
-	}
+	flush_dirty_buffers(1);
+	/* must really sync all the active I/O request to disk here */
 	run_task_queue(&tq_disk);
 	return 0;
 }
@@ -2328,6 +2432,10 @@
 		return -EPERM;
 
 	if (func == 1) {
+		/* do_exit directly and let kupdate to do its work alone. */
+		do_exit(0);
+#if 0 /* left here as it's the only example of lazy-mm-stuff used from
+	 a syscall that doesn't care about the current mm context. */
 		int error;
 		struct mm_struct *user_mm;
 
@@ -2341,6 +2449,7 @@
 		error = sync_old_buffers();
 		end_lazy_tlb(user_mm);
 		return error;
+#endif
 	}
 
 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
@@ -2383,85 +2492,103 @@
 	sprintf(current->comm, "kflushd");
 	bdflush_tsk = current;
 
-	for (;;) {
-		int nlist;
+	/* avoid getting signals */
+	spin_lock_irq(&current->sigmask_lock);
+	flush_signals(current);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
 
+	for (;;) {
 		CHECK_EMERGENCY_SYNC
 
-		for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) {
-			int nr, major, written = 0;
-			struct buffer_head *next;
-
-		repeat:
-			spin_lock(&lru_list_lock);
-			next = lru_list[nlist];
-			nr = nr_buffers_type[nlist];
-			while (nr-- > 0) {
-				struct buffer_head *bh = next;
-
-				next = next->b_next_free;
-					
-				/* If the buffer is not on the correct list,
-				 * then refile it.
-				 */
-				if ((nlist == BUF_DIRTY &&
-				     (!buffer_dirty(bh) && !buffer_locked(bh))) ||
-				    (nlist == BUF_LOCKED && !buffer_locked(bh))) {
-					__refile_buffer(bh);
-					continue;
-				}
-
-				/* If we aren't in panic mode, don't write out too much
-				 * at a time. Also, don't write out buffers we don't
-				 * really have to write out yet..
-				 */
-				if (!too_many_dirty_buffers) {
-					if (written > bdf_prm.b_un.ndirty)
-						break;
-					if (time_before(jiffies, bh->b_flushtime))
-						continue;
-				}
+		flush_dirty_buffers(0);
 
-				if (buffer_locked(bh) || !buffer_dirty(bh))
-					 continue;
-
-				major = MAJOR(bh->b_dev);
-				written++;
-
-				/*
-				 * For the loop major we can try to do asynchronous writes,
-				 * but we have to guarantee that we're making some progress..
-				 */
-				atomic_inc(&bh->b_count);
-				spin_unlock(&lru_list_lock);
-				ll_rw_block(WRITE, 1, &bh);
-				atomic_dec(&bh->b_count);
-				goto repeat;
-			}
-			spin_unlock(&lru_list_lock);
-		}
-		run_task_queue(&tq_disk);
+		/* If wakeup_bdflush will wakeup us
+		   after our bdflush_done wakeup, then
+		   we must make sure to not sleep
+		   in schedule_timeout otherwise
+		   wakeup_bdflush may wait for our
+		   bdflush_done wakeup that would never arrive
+		   (as we would be sleeping) and so it would
+		   deadlock in SMP. */
+		__set_current_state(TASK_INTERRUPTIBLE);
 		wake_up(&bdflush_done);
-		
 		/*
 		 * If there are still a lot of dirty buffers around,
 		 * skip the sleep and flush some more. Otherwise, we
-		 * sleep for a while and mark us as not being in panic
-		 * mode..
+		 * sleep for a while.
 		 */
-		if (!too_many_dirty_buffers || nr_buffers_type[BUF_DIRTY] < bdf_prm.b_un.ndirty) {
-			too_many_dirty_buffers = 0;
-			spin_lock_irq(&current->sigmask_lock);
-			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
-			interruptible_sleep_on_timeout(&bdflush_wait, 5*HZ);
+		if (balance_dirty_state(NODEV) < 0)
+			schedule_timeout(5*HZ);
+		/* Remember to mark us as running otherwise
+		   the next schedule will block. */
+		__set_current_state(TASK_RUNNING);
+	}
+}
+
+/*
+ * This is the kernel update daemon. It was used to live in userspace
+ * but since it's need to run safely we want it unkillable by mistake.
+ * You don't need to change your userspace configuration since
+ * the userspace `update` will do_exit(0) at the first sys_bdflush().
+ */
+int kupdate(void * unused) 
+{
+	struct task_struct * tsk = current;
+	int interval;
+
+	tsk->session = 1;
+	tsk->pgrp = 1;
+	strcpy(tsk->comm, "kupdate");
+
+	/* sigstop and sigcont will stop and wakeup kupdate */
+	spin_lock_irq(&tsk->sigmask_lock);
+	sigfillset(&tsk->blocked);
+	siginitsetinv(&current->blocked, sigmask(SIGCONT) | sigmask(SIGSTOP));
+	recalc_sigpending(tsk);
+	spin_unlock_irq(&tsk->sigmask_lock);
+
+	for (;;) {
+		/* update interval */
+		interval = bdf_prm.b_un.interval;
+		if (interval)
+		{
+			tsk->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(interval);
 		}
+		else
+		{
+		stop_kupdate:
+			tsk->state = TASK_STOPPED;
+			schedule(); /* wait for SIGCONT */
+		}
+		/* check for sigstop */
+		if (signal_pending(tsk))
+		{
+			int stopped = 0;
+			spin_lock_irq(&tsk->sigmask_lock);
+			if (sigismember(&tsk->signal, SIGSTOP))
+			{
+				sigdelset(&tsk->signal, SIGSTOP);
+				stopped = 1;
+			}
+			recalc_sigpending(tsk);
+			spin_unlock_irq(&tsk->sigmask_lock);
+			if (stopped)
+				goto stop_kupdate;
+		}
+#ifdef DEBUG
+		printk("kupdate() activated...\n");
+#endif
+		sync_old_buffers();
 	}
 }
 
 static int __init bdflush_init(void)
 {
 	kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	kernel_thread(kupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.22/linux/fs/dcache.c linux/fs/dcache.c
--- v2.3.22/linux/fs/dcache.c	Sat Oct  9 11:47:50 1999
+++ linux/fs/dcache.c	Tue Oct 19 10:22:19 1999
@@ -169,6 +169,11 @@
 int d_invalidate(struct dentry * dentry)
 {
 	/*
+	 * If it's already been dropped, return OK.
+	 */
+	if (list_empty(&dentry->d_hash))
+		return 0;
+	/*
 	 * Check whether to do a partial shrink_dcache
 	 * to get rid of unused child entries.
 	 */
@@ -415,7 +420,7 @@
 		unlock_kernel();
 		/* FIXME: kmem_cache_shrink here should tell us
 		   the number of pages freed, and it should
-		   work in a __GFP_DMA/__GFP_BIGMEM behaviour
+		   work in a __GFP_DMA/__GFP_HIGHMEM behaviour
 		   to free only the interesting pages in
 		   function of the needs of the current allocation. */
 		kmem_cache_shrink(dentry_cache);
diff -u --recursive --new-file v2.3.22/linux/fs/exec.c linux/fs/exec.c
--- v2.3.22/linux/fs/exec.c	Mon Oct 11 15:38:15 1999
+++ linux/fs/exec.c	Wed Oct 20 22:13:20 1999
@@ -31,6 +31,8 @@
 #include <linux/fcntl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -212,20 +214,42 @@
 		/* XXX: add architecture specific overflow check here. */ 
 
 		pos = bprm->p;
-		while (len>0) {
-			char *pag;
+		while (len > 0) {
+			char *kaddr;
+			int i, new, err;
+			struct page *page;
 			int offset, bytes_to_copy;
 
 			offset = pos % PAGE_SIZE;
-			if (!(pag = (char *) bprm->page[pos/PAGE_SIZE]) &&
-			    !(pag = (char *) bprm->page[pos/PAGE_SIZE] =
-			      (unsigned long *) get_free_page(GFP_USER))) 
-				return -ENOMEM; 
+			i = pos/PAGE_SIZE;
+			page = bprm->page[i];
+			new = 0;
+			if (!page) {
+				/*
+				 * Cannot yet use highmem page because
+				 * we cannot sleep with a kmap held.
+				 */
+				page = __get_pages(GFP_USER, 0);
+				bprm->page[i] = page;
+				if (!page)
+					return -ENOMEM;
+				new = 1;
+			}
+			kaddr = (char *)kmap(page, KM_WRITE);
 
+			if (new && offset)
+				memset(kaddr, 0, offset);
 			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len)
+			if (bytes_to_copy > len) {
 				bytes_to_copy = len;
-			if (copy_from_user(pag + offset, str, bytes_to_copy)) 
+				if (new)
+					memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
+			}
+			err = copy_from_user(kaddr + offset, str, bytes_to_copy);
+			flush_page_to_ram(page);
+			kunmap((unsigned long)kaddr, KM_WRITE);
+
+			if (err)
 				return -EFAULT; 
 
 			pos += bytes_to_copy;
@@ -276,7 +300,9 @@
 		mpnt->vm_offset = 0;
 		mpnt->vm_file = NULL;
 		mpnt->vm_private_data = (void *) 0;
+		vmlist_modify_lock(current->mm);
 		insert_vm_struct(current->mm, mpnt);
+		vmlist_modify_unlock(current->mm);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
 
@@ -467,6 +493,11 @@
 	    permission(bprm->dentry->d_inode,MAY_READ))
 		current->dumpable = 0;
 
+	/* An exec changes our domain. We are no longer part of the thread
+	   group */
+	   
+	current->self_exec_id++;
+			
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
 
@@ -640,14 +671,22 @@
 {
 	if (bprm->argc) {
 		unsigned long offset;
-		char * page;
+		char * kaddr;
+		struct page *page;
+
 		offset = bprm->p % PAGE_SIZE;
-		page = (char*)bprm->page[bprm->p/PAGE_SIZE];
-		while(bprm->p++,*(page+offset++))
-			if(offset==PAGE_SIZE){
-				offset=0;
-				page = (char*)bprm->page[bprm->p/PAGE_SIZE];
-			}
+		goto inside;
+
+		while (bprm->p++, *(kaddr+offset++)) {
+			if (offset != PAGE_SIZE)
+				continue;
+			offset = 0;
+			kunmap((unsigned long)kaddr, KM_WRITE);
+inside:
+			page = bprm->page[bprm->p/PAGE_SIZE];
+			kaddr = (char *)kmap(page, KM_WRITE);
+		}
+		kunmap((unsigned long)kaddr, KM_WRITE);
 		bprm->argc--;
 	}
 }
@@ -676,8 +715,8 @@
 		bprm->dentry = NULL;
 
 	        bprm_loader.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	        for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-                    bprm_loader.page[i] = 0;
+	        for (i = 0 ; i < MAX_ARG_PAGES ; i++)	/* clear page-table */
+                    bprm_loader.page[i] = NULL;
 
 		dentry = open_namei(dynloader[0], 0, 0);
 		retval = PTR_ERR(dentry);
@@ -793,8 +832,9 @@
 
 	/* Assumes that free_page() can take a NULL argument. */ 
 	/* I hope this is ok for all architectures */ 
-	for (i=0 ; i<MAX_ARG_PAGES ; i++)
-		free_page(bprm.page[i]);
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++)
+		if (bprm.page[i])
+			__free_page(bprm.page[i]);
 
 	return retval;
 }
diff -u --recursive --new-file v2.3.22/linux/fs/file.c linux/fs/file.c
--- v2.3.22/linux/fs/file.c	Mon Jul 26 22:41:09 1999
+++ linux/fs/file.c	Tue Oct 19 10:22:19 1999
@@ -16,7 +16,7 @@
 
 
 /*
- * Allocate an fd array, using get_free_page() if possible.
+ * Allocate an fd array, using __get_free_page() if possible.
  * Note: the array isn't cleared at allocation time.
  */
 struct file ** alloc_fd_array(int num)
@@ -129,7 +129,7 @@
 }
 
 /*
- * Allocate an fdset array, using get_free_page() if possible.
+ * Allocate an fdset array, using __get_free_page() if possible.
  * Note: the array isn't cleared at allocation time.
  */
 fd_set * alloc_fdset(int num)
diff -u --recursive --new-file v2.3.22/linux/fs/hpfs/anode.c linux/fs/hpfs/anode.c
--- v2.3.22/linux/fs/hpfs/anode.c	Sun Jun 27 10:10:41 1999
+++ linux/fs/hpfs/anode.c	Tue Oct 19 13:52:52 1999
@@ -293,10 +293,10 @@
 	if (!level) return;
 	if (s->s_hpfs_chk)
 		if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return;
+	brelse(bh);
 	hpfs_free_sectors(s, ano, 1);
 	oano = ano;
 	ano = anode->up;
-	brelse(bh);
 	if (--level) {
 		anode = hpfs_map_anode(s, ano, &bh);
 		btree1 = &anode->btree;
diff -u --recursive --new-file v2.3.22/linux/fs/hpfs/dir.c linux/fs/hpfs/dir.c
--- v2.3.22/linux/fs/hpfs/dir.c	Sun May 16 10:27:40 1999
+++ linux/fs/hpfs/dir.c	Tue Oct 19 13:52:52 1999
@@ -20,7 +20,34 @@
 	return 0;
 }
 
-int hpfs_readdir(struct file *filp, void * dirent, filldir_t filldir)
+/* This is slow, but it's not used often */
+
+loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
+{
+	loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
+	loff_t pos;
+	struct quad_buffer_head qbh;
+	struct inode *i = filp->f_dentry->d_inode;
+	struct super_block *s = filp->f_dentry->d_sb;
+	/*printk("dir lseek\n");*/
+	if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
+	hpfs_lock_inode(i);
+	pos = ((loff_t) hpfs_de_as_down_as_possible(s, i->i_hpfs_dno) << 4) + 1;
+	while (pos != new_off) {
+		if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
+		else goto fail;
+		if (pos == 12) goto fail;
+	}
+	hpfs_unlock_inode(i);
+	ok:
+	return filp->f_pos = new_off;
+	fail:
+	hpfs_unlock_inode(i);
+	/*printk("illegal lseek: %016llx\n", new_off);*/
+	return -ESPIPE;
+}
+
+int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct quad_buffer_head qbh;
@@ -54,11 +81,11 @@
 		if (e) return -EFSERROR;
 	}
 	lc = inode->i_sb->s_hpfs_lowercase;
-	if (filp->f_pos == -2) { /* diff -r requires this (note, that diff -r */
-		filp->f_pos = -3; /* also fails on msdos filesystem in 2.0) */
+	if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */
+		filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */
 		return 0;
 	}
-	if (filp->f_pos == -3) return -ENOENT;
+	if (filp->f_pos == 13) return -ENOENT;
 	
 	hpfs_lock_inode(inode);
 	
@@ -72,7 +99,7 @@
 				hpfs_unlock_inode(inode);
 				return -EFSERROR;
 			}
-		if (filp->f_pos == -2) {
+		if (filp->f_pos == 12) {
 			hpfs_unlock_inode(inode);
 			return 0;
 		}
@@ -86,9 +113,9 @@
 				hpfs_unlock_inode(inode);
 				return 0;
 			}
-			filp->f_pos = -1;
+			filp->f_pos = 11;
 		}
-		if (filp->f_pos == -1) {
+		if (filp->f_pos == 11) {
 			if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) {
 				hpfs_unlock_inode(inode);
 				return 0;
diff -u --recursive --new-file v2.3.22/linux/fs/hpfs/dnode.c linux/fs/hpfs/dnode.c
--- v2.3.22/linux/fs/hpfs/dnode.c	Sun May 16 10:27:40 1999
+++ linux/fs/hpfs/dnode.c	Tue Oct 19 13:52:52 1999
@@ -539,7 +539,7 @@
 				brelse(bh);
 			}
 			i->i_hpfs_dno = down;
-			for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) -2);
+			for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12);
 			return;
 		}
 		if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return;
@@ -876,7 +876,7 @@
 	hpfs_brelse4(&qbh0);
 	
 	bail:
-	*posp = -2;
+	*posp = 12;
 	return de;
 }
 
diff -u --recursive --new-file v2.3.22/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.3.22/linux/fs/hpfs/file.c	Sun Jun 27 10:10:41 1999
+++ linux/fs/hpfs/file.c	Tue Oct 19 13:52:52 1999
@@ -58,91 +58,96 @@
 	hpfs_write_inode(i);
 }
 
-int hpfs_getblk_block(struct inode *inode, long block, int create, int *err, int *created)
+int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
 {
-	int add;
-	int sec = 0;
-	down(&inode->i_sem);
-	if (err) *err = 0;
-	if (created) *created = 0;
-	if (!inode->i_blocks) {
-		hpfs_error(inode->i_sb, "hpfs_get_block: inode %08x has no blocks", inode->i_ino);
-		if (err) *err = -EFSERROR;
-		up(&inode->i_sem);
+	secno s;
+	if (iblock < inode->i_blocks - 1) {
+		s = hpfs_bmap(inode, iblock);
+		bh_result->b_dev = inode->i_dev;
+		bh_result->b_blocknr = s;
+		bh_result->b_state |= (1UL << BH_Mapped);
 		return 0;
 	}
-	if (block < ((add = inode->i_blocks - 1))) {
-		int bm;
-		if (!(bm = hpfs_bmap(inode, block))) {
-			hpfs_error(inode->i_sb, "hpfs_get_block: cound not bmap block %08x, inode %08x, size %08x", (int)block, inode->i_ino, (int)inode->i_size);
-			*err = -EFSERROR;
-		}
-		up(&inode->i_sem);
-		return bm;
-	}
-	if (!create) {
-		if (err) *err = -EFBIG;
-		up(&inode->i_sem);
-		return 0;
+	if (!create) return 0;
+	if (iblock > inode->i_blocks - 1) {
+		//hpfs_error(inode->i_sb, "hpfs_get_block beyond file end (requested %08x, inode size %08x", (int)iblock, (int)inode->i_blocks - 1);
+		printk("HPFS: could not write beyond file end. This is known bug.\n");
+		return -EFSERROR;
 	}
-	if (created) *created = 1;
-	while (add <= block) {
-		if ((sec = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, add)) == -1) {
-			if (err) *err = -ENOSPC;
-			hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
-			return 0;
-		} /* FIXME: clear block */
-		add++;
+	if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) {
+		hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
+		return -ENOSPC;
 	}
-	inode->i_blocks = add + 1;
-	up(&inode->i_sem);
-	return sec;
+	inode->i_blocks++;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = s;
+	bh_result->b_state |= (1UL << BH_Mapped) | (1UL << BH_New);
+	return 0;
 }
 
-/* copied from ext2fs */
-static int hpfs_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, int update)
+static int hpfs_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
 {
-	if (!bh->b_blocknr) {
-		int error, created;
-		unsigned long blocknr;
-
-		blocknr = hpfs_getblk_block(inode, block, 1, &error, &created);
-		if (!blocknr) {
-			if (!error)
-				error = -ENOSPC;
-			return error;
+	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	struct page *new_page, **hash;
+	unsigned long pgpos;
+	unsigned long page_cache = 0;
+	long status;
+
+	printk("- off: %08x\n", (int)page->offset);
+	pgpos = (inode->i_blocks - 1) * 512 & PAGE_CACHE_MASK;
+	while (pgpos < page->offset) {
+long pgp = pgpos;
+		printk("pgpos: %08x, bl: %d\n", (int)pgpos, (int)inode->i_blocks);
+		hash = page_hash(inode, pgpos);
+repeat_find:	new_page = __find_lock_page(inode, pgpos, hash);
+		if (!new_page) {
+			if (!page_cache) {
+				page_cache = page_cache_alloc();
+				if (page_cache)
+					goto repeat_find;
+				status = -ENOMEM;
+				goto out;
+			}
+			new_page = page_cache_entry(page_cache);
+			if (add_to_page_cache_unique(new_page,inode,pgpos,hash))
+				goto repeat_find;
+			page_cache = 0;
 		}
-
-		bh->b_dev = inode->i_dev;
-		bh->b_blocknr = blocknr;
-
-		if (!update)
-			return 0;
-
-		if (created) {
-			memset(bh->b_data, 0, bh->b_size);
-			set_bit(BH_Uptodate, &bh->b_state);
-			return 0;
+		printk("A\n");
+		status = block_write_cont_page(file, new_page, PAGE_SIZE, 0, NULL);
+		printk("B\n");
+		UnlockPage(new_page);
+		page_cache_release(new_page);
+		if (status < 0)
+			goto out;
+		pgpos = (inode->i_blocks - 1) * 512 & PAGE_CACHE_MASK;
+		printk("pgpos2: %08x, bl: %d\n", (int)pgpos, (int)inode->i_blocks);
+		if (pgpos == pgp) {
+			status = -1;
+			printk("ERROR\n");
+			goto out;
 		}
 	}
-
-	if (!update)
-		return 0;
-
-	lock_kernel();
-	ll_rw_block(READ, 1, &bh);
-	wait_on_buffer(bh);
-	unlock_kernel();
-
-	return buffer_uptodate(bh) ? 0 : -EIO;
+	//if ((status = block_write_cont_page(file, page, PAGE_SIZE, 0, NULL)) < 0) goto out;
+	printk("C\n");
+	status = block_write_cont_page(file, page, offset, bytes, buf);
+	printk("D\n");
+out:
+	printk("O\n");
+	if (page_cache)
+		page_cache_free(page_cache);
+	printk("E\n");
+	return status;
 }
 
+
 ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
 	ssize_t retval;
 
 	retval = generic_file_write(file, buf, count,
-				    ppos, block_write_partial_page);
+				    ppos, /*hpfs_write_partial_page*/block_write_partial_page);
 	if (retval > 0) {
 		struct inode *inode = file->f_dentry->d_inode;
 		inode->i_mtime = CURRENT_TIME;
diff -u --recursive --new-file v2.3.22/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.3.22/linux/fs/hpfs/hpfs_fn.h	Fri Jun 25 09:42:19 1999
+++ linux/fs/hpfs/hpfs_fn.h	Tue Oct 19 13:52:52 1999
@@ -226,6 +226,7 @@
 
 int hpfs_dir_read(struct file *, char *, size_t, loff_t *);
 int hpfs_dir_release(struct inode *, struct file *);
+loff_t hpfs_dir_lseek(struct file *, loff_t, int);
 int hpfs_readdir(struct file *, void *, filldir_t);
 struct dentry *hpfs_lookup(struct inode *, struct dentry *);
 
@@ -258,9 +259,8 @@
 int hpfs_file_fsync(struct file *, struct dentry *);
 secno hpfs_bmap(struct inode *, unsigned);
 void hpfs_truncate(struct inode *);
-ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
-ssize_t hpfs_file_write(struct file *, const char *, size_t, loff_t *);
-int hpfs_writepage (struct file *, struct page *);
+int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create);
+ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos);
 
 /* inode.c */
 
diff -u --recursive --new-file v2.3.22/linux/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- v2.3.22/linux/fs/hpfs/inode.c	Sun Jun 27 10:10:41 1999
+++ linux/fs/hpfs/inode.c	Tue Oct 19 13:52:52 1999
@@ -41,11 +41,9 @@
 	NULL,				/* rename */
 	NULL,				/* readlink */
 	NULL,				/* follow_link */
-	(int (*)(struct inode *, int))
-#warning Someone needs to code up hpfs_get_block properly... -DaveM
-	&hpfs_bmap,			/* get_block */
+	&hpfs_get_block,		/* get_block */
 	block_read_full_page,		/* readpage */
-	hpfs_writepage,			/* writepage */
+	block_write_full_page,		/* writepage */
 	block_flushpage,		/* flushpage */
 	hpfs_truncate,			/* truncate */
 	NULL,				/* permission */
@@ -55,7 +53,7 @@
 
 static const struct file_operations hpfs_dir_ops =
 {
-	NULL,				/* lseek - default */
+	hpfs_dir_lseek,			/* lseek */
 	hpfs_dir_read,			/* read */
 	NULL,				/* write - bad */
 	hpfs_readdir,			/* readdir */
diff -u --recursive --new-file v2.3.22/linux/fs/inode.c linux/fs/inode.c
--- v2.3.22/linux/fs/inode.c	Sat Oct  9 11:47:50 1999
+++ linux/fs/inode.c	Tue Oct 19 10:22:19 1999
@@ -89,6 +89,7 @@
 		memset(inode, 0, sizeof(*inode));
 		init_waitqueue_head(&inode->i_wait);
 		INIT_LIST_HEAD(&inode->i_hash);
+		INIT_LIST_HEAD(&inode->i_pages);
 		INIT_LIST_HEAD(&inode->i_dentry);
 		sema_init(&inode->i_sem, 1);
 		spin_lock_init(&inode->i_shared_lock);
@@ -401,7 +402,7 @@
 		prune_icache(count);
 		/* FIXME: kmem_cache_shrink here should tell us
 		   the number of pages freed, and it should
-		   work in a __GFP_DMA/__GFP_BIGMEM behaviour
+		   work in a __GFP_DMA/__GFP_HIGHMEM behaviour
 		   to free only the interesting pages in
 		   function of the needs of the current allocation. */
 		kmem_cache_shrink(inode_cachep);
@@ -429,7 +430,7 @@
  * by hand after calling find_inode now! This simplify iunique and won't
  * add any additional branch in the common code.
  */
-static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
 {
 	struct list_head *tmp;
 	struct inode * inode;
@@ -445,6 +446,8 @@
 			continue;
 		if (inode->i_ino != ino)
 			continue;
+		if (find_actor && !find_actor(inode, ino, opaque))
+			continue;
 		break;
 	}
 	return inode;
@@ -504,7 +507,7 @@
  * We no longer cache the sb_flags in i_flags - see fs.h
  *	-- rmk@arm.uk.linux.org
  */
-static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
 {
 	struct inode * inode;
 
@@ -514,7 +517,7 @@
 
 		spin_lock(&inode_lock);
 		/* We released the lock, so.. */
-		old = find_inode(sb, ino, head);
+		old = find_inode(sb, ino, head, find_actor, opaque);
 		if (!old)
 		{
 			list_add(&inode->i_list, &inode_in_use);
@@ -570,7 +573,7 @@
 retry:
 	if (counter > max_reserved) {
 		head = inode_hashtable + hash(sb,counter);
-		inode = find_inode(sb, res = counter++, head);
+		inode = find_inode(sb, res = counter++, head, NULL, NULL);
 		if (!inode) {
 			spin_unlock(&inode_lock);
 			return res;
@@ -595,13 +598,13 @@
 	return inode;
 }
 
-struct inode *iget(struct super_block *sb, unsigned long ino)
+struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
 {
 	struct list_head * head = inode_hashtable + hash(sb,ino);
 	struct inode * inode;
 
 	spin_lock(&inode_lock);
-	inode = find_inode(sb, ino, head);
+	inode = find_inode(sb, ino, head, find_actor, opaque);
 	if (inode) {
 		__iget(inode);
 		spin_unlock(&inode_lock);
@@ -614,7 +617,7 @@
 	 * get_new_inode() will do the right thing, re-trying the search
 	 * in case it had to block at any point.
 	 */
-	return get_new_inode(sb, ino, head);
+	return get_new_inode(sb, ino, head, find_actor, opaque);
 }
 
 void insert_inode_hash(struct inode *inode)
diff -u --recursive --new-file v2.3.22/linux/fs/iobuf.c linux/fs/iobuf.c
--- v2.3.22/linux/fs/iobuf.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/iobuf.c	Tue Oct 19 10:22:19 1999
@@ -50,7 +50,6 @@
 		init_waitqueue_head(&iobuf->wait_queue);
 		iobuf->end_io = simple_wakeup_kiobuf;
 		iobuf->array_len = KIO_STATIC_PAGES;
-		iobuf->pagelist  = iobuf->page_array;
 		iobuf->maplist   = iobuf->map_array;
 		*bufp++ = iobuf;
 	}
@@ -65,50 +64,35 @@
 	
 	for (i = 0; i < nr; i++) {
 		iobuf = bufp[i];
-		if (iobuf->array_len > KIO_STATIC_PAGES) {
-			kfree (iobuf->pagelist);
+		if (iobuf->array_len > KIO_STATIC_PAGES)
 			kfree (iobuf->maplist);
-		}
 		kmem_cache_free(kiobuf_cachep, bufp[i]);
 	}
 }
 
 int expand_kiobuf(struct kiobuf *iobuf, int wanted)
 {
-	unsigned long *	pagelist;
 	struct page ** maplist;
 	
 	if (iobuf->array_len >= wanted)
 		return 0;
 	
-	pagelist = (unsigned long *) 
-		kmalloc(wanted * sizeof(unsigned long), GFP_KERNEL);
-	if (!pagelist)
-		return -ENOMEM;
-	
 	maplist = (struct page **) 
 		kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
-	if (!maplist) {
-		kfree(pagelist);
+	if (!maplist)
 		return -ENOMEM;
-	}
 
 	/* Did it grow while we waited? */
 	if (iobuf->array_len >= wanted) {
-		kfree(pagelist);
 		kfree(maplist);
 		return 0;
 	}
 	
-	memcpy (pagelist, iobuf->pagelist, wanted * sizeof(unsigned long));
 	memcpy (maplist,  iobuf->maplist,   wanted * sizeof(struct page **));
 
-	if (iobuf->array_len > KIO_STATIC_PAGES) {
-		kfree (iobuf->pagelist);
+	if (iobuf->array_len > KIO_STATIC_PAGES)
 		kfree (iobuf->maplist);
-	}
 	
-	iobuf->pagelist  = pagelist;
 	iobuf->maplist   = maplist;
 	iobuf->array_len = wanted;
 	return 0;
diff -u --recursive --new-file v2.3.22/linux/fs/minix/truncate.c linux/fs/minix/truncate.c
--- v2.3.22/linux/fs/minix/truncate.c	Wed Aug 18 10:15:19 1999
+++ linux/fs/minix/truncate.c	Mon Oct 18 11:14:58 1999
@@ -33,7 +33,7 @@
  */
 
 #define DATA_BUFFER_USED(bh) \
-	(atomic_read(&bh->b_count) || buffer_locked(bh))
+	(atomic_read(&bh->b_count) > 1 || buffer_locked(bh))
 
 /*
  * The functions for minix V1 fs truncation.
diff -u --recursive --new-file v2.3.22/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.3.22/linux/fs/nfs/dir.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/nfs/dir.c	Tue Oct 19 10:22:19 1999
@@ -308,8 +308,7 @@
 	struct nfs_readdirres rd_res;
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	struct page *page, **hash;
-	unsigned long page_cache;
+	struct page *page, **hash, *page_cache;
 	long offset;
 	__u32 *cookiep;
 
@@ -341,14 +340,14 @@
 		goto unlock_out;
 	}
 
-	page = page_cache_entry(page_cache);
+	page = page_cache;
 	if (add_to_page_cache_unique(page, inode, offset, hash)) {
 		page_cache_release(page);
 		goto repeat;
 	}
 
 	rd_args.fh = NFS_FH(dentry);
-	rd_res.buffer = (char *)page_cache;
+	rd_res.buffer = (char *)page_address(page_cache);
 	rd_res.bufsiz = PAGE_CACHE_SIZE;
 	rd_res.cookie = *cookiep;
 	do {
@@ -533,13 +532,15 @@
  * If mtime is close to present time, we revalidate
  * more often.
  */
+#define NFS_REVALIDATE_NEGATIVE (1 * HZ)
 static inline int nfs_neg_need_reval(struct dentry *dentry)
 {
-	unsigned long timeout = 30 * HZ;
-	long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+	struct inode *dir = dentry->d_parent->d_inode;
+	unsigned long timeout = NFS_ATTRTIMEO(dir);
+	long diff = CURRENT_TIME - dir->i_mtime;
 
-	if (diff < 5*60)
-		timeout = 1 * HZ;
+	if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
+		timeout = NFS_REVALIDATE_NEGATIVE;
 
 	return time_after(jiffies, dentry->d_time + timeout);
 }
@@ -581,12 +582,14 @@
 		goto out_bad;
 	}
 
-	if (IS_ROOT(dentry))
-		goto out_valid;
-
 	if (!nfs_dentry_force_reval(dentry, flags))
 		goto out_valid;
 
+	if (IS_ROOT(dentry)) {
+		__nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+		goto out_valid_renew;
+	}
+
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
@@ -596,32 +599,29 @@
 		goto out_bad;
 
 	/* Inode number matches? */
-	if (fattr.fileid != inode->i_ino)
+	if (NFS_FSID(inode) != fattr.fsid ||
+	    NFS_FILEID(inode) != fattr.fileid)
 		goto out_bad;
 
 	/* Filehandle matches? */
-	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
-		if (!list_empty(&dentry->d_subdirs))
-			shrink_dcache_parent(dentry);
-		if (dentry->d_count < 2)
-			goto out_bad;
-	}
+	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
+		goto out_bad;
 
 	/* Ok, remeber that we successfully checked it.. */
-	nfs_renew_times(dentry);
 	nfs_refresh_inode(inode, &fattr);
 
+ out_valid_renew:
+	nfs_renew_times(dentry);
 out_valid:
 	return 1;
 out_bad:
+	d_drop(dentry);
+	if (!list_empty(&dentry->d_subdirs))
+		shrink_dcache_parent(dentry);
 	/* Purge readdir caches. */
 	if (dentry->d_parent->d_inode) {
-		invalidate_inode_pages(dentry->d_parent->d_inode);
-		nfs_flush_dircache(dentry->d_parent->d_inode);
-	}
-	if (inode && S_ISDIR(inode->i_mode)) {
-		invalidate_inode_pages(inode);
-		nfs_flush_dircache(inode);
+		nfs_zap_caches(dentry->d_parent->d_inode);
+		NFS_CACHEINV(dentry->d_parent->d_inode);
 	}
 	return 0;
 }
@@ -649,21 +649,6 @@
 				dentry->d_name.name, error);
 	}
 
-#ifdef NFS_PARANOIA
-	/*
-	 * Sanity check: if the dentry has been unhashed and the
-	 * inode still has users, we could have problems ...
-	 */
-	if (list_empty(&dentry->d_hash) && dentry->d_inode) {
-		struct inode *inode = dentry->d_inode;
-		int max_count = (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink);
-		if (inode->i_count > max_count) {
-printk("nfs_dentry_delete: %s/%s: ino=%ld, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-		}
-	}
-#endif
 }
 
 static kmem_cache_t *nfs_fh_cachep;
@@ -750,14 +735,6 @@
 		error = -EACCES;
 		inode = nfs_fhget(dentry, &fhandle, &fattr);
 		if (inode) {
-#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
-printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-show_dentry(&inode->i_dentry);
-}
-#endif
 	    no_entry:
 			d_add(dentry, inode);
 			nfs_renew_times(dentry);
@@ -779,14 +756,6 @@
 
 	inode = nfs_fhget(dentry, fhandle, fattr);
 	if (inode) {
-#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
-printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-show_dentry(&inode->i_dentry);
-}
-#endif
 		d_instantiate(dentry, inode);
 		nfs_renew_times(dentry);
 		error = 0;
@@ -803,16 +772,15 @@
 static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
 	int error;
-	struct nfs_sattr sattr;
+	struct iattr attr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
 		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-	sattr.mode = mode;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+	attr.ia_mode = mode;
+	attr.ia_valid = ATTR_MODE;
 
 	/*
 	 * Invalidate the dir cache before the operation to avoid a race.
@@ -820,7 +788,7 @@
 	invalidate_inode_pages(dir);
 	nfs_flush_dircache(dir);
 	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-			dentry->d_name.name, &sattr, &fhandle, &fattr);
+			dentry->d_name.name, &attr, &fhandle, &fattr);
 	if (!error)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (error)
@@ -834,23 +802,25 @@
 static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
 	int error;
-	struct nfs_sattr sattr;
+	struct iattr attr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
 		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-	sattr.mode = mode;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	if (S_ISCHR(mode) || S_ISBLK(mode))
-		sattr.size = rdev; /* get out your barf bag */
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+	attr.ia_mode = mode;
+	attr.ia_valid = ATTR_MODE;
+	/* FIXME: move this to a special nfs_proc_mknod() */
+	if (S_ISCHR(mode) || S_ISBLK(mode)) {
+		attr.ia_size = rdev; /* get out your barf bag */
+		attr.ia_valid |= ATTR_SIZE;
+	}
 
 	invalidate_inode_pages(dir);
 	nfs_flush_dircache(dir);
 	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, &sattr, &fhandle, &fattr);
+				dentry->d_name.name, &attr, &fhandle, &fattr);
 	if (!error)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (error)
@@ -864,16 +834,15 @@
 static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	int error;
-	struct nfs_sattr sattr;
+	struct iattr attr;
 	struct nfs_fattr fattr;
 	struct nfs_fh fhandle;
 
 	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
 		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-	sattr.mode = mode | S_IFDIR;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+	attr.ia_valid = ATTR_MODE;
+	attr.ia_mode = mode | S_IFDIR;
 
 	/*
 	 * Always drop the dentry, we can't always depend on
@@ -885,7 +854,7 @@
 	invalidate_inode_pages(dir);
 	nfs_flush_dircache(dir);
 	error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, &sattr, &fhandle, &fattr);
+				dentry->d_name.name, &attr, &fhandle, &fattr);
 	if (!error)
 		dir->i_nlink++;
 	return error;
@@ -898,13 +867,6 @@
 	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
 		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-#ifdef NFS_PARANOIA
-if (dentry->d_inode->i_count > 1)
-printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-dentry->d_inode->i_count, dentry->d_inode->i_nlink);
-#endif
-
 	invalidate_inode_pages(dir);
 	nfs_flush_dircache(dir);
 	error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
@@ -1082,12 +1044,6 @@
 #endif
 		goto out;
 	}
-#ifdef NFS_PARANOIA
-if (inode && inode->i_count > inode->i_nlink)
-printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_count, inode->i_nlink);
-#endif
 	/*
 	 * Unhash the dentry while we remove the file ...
 	 */
@@ -1141,7 +1097,7 @@
 static int
 nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
-	struct nfs_sattr sattr;
+	struct iattr attr;
 	int error;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
@@ -1160,9 +1116,8 @@
 	 * Fill in the sattr for the call.
  	 * Note: SunOS 4.1.2 crashes if the mode isn't initialized!
 	 */
-	sattr.mode = S_IFLNK | S_IRWXUGO;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+	attr.ia_valid = ATTR_MODE;
+	attr.ia_mode = S_IFLNK | S_IRWXUGO;
 
 	/*
 	 * Drop the dentry in advance to force a new lookup.
@@ -1173,7 +1128,7 @@
 	invalidate_inode_pages(dir);
 	nfs_flush_dircache(dir);
 	error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, symname, &sattr);
+				dentry->d_name.name, symname, &attr);
 	if (!error) {
 		nfs_renew_times(dentry->d_parent);
 	} else if (error == -EEXIST) {
@@ -1332,13 +1287,6 @@
 	 * To prevent any new references to the target during the rename,
 	 * we unhash the dentry and free the inode in advance.
 	 */
-#ifdef NFS_PARANOIA
-if (new_inode && 
-    new_inode->i_count > (S_ISDIR(new_inode->i_mode) ? 1 : new_inode->i_nlink))
-printk("nfs_rename: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_inode->i_count, new_inode->i_nlink);
-#endif
 	if (!list_empty(&new_dentry->d_hash)) {
 		d_drop(new_dentry);
 		rehash = update;
diff -u --recursive --new-file v2.3.22/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.3.22/linux/fs/nfs/inode.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/nfs/inode.c	Mon Oct 18 11:26:37 1999
@@ -37,7 +37,7 @@
 #define NFS_PARANOIA 1
 
 static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
-static void nfs_zap_caches(struct inode *);
+void nfs_zap_caches(struct inode *);
 static void nfs_invalidate_inode(struct inode *);
 
 static void nfs_read_inode(struct inode *);
@@ -78,6 +78,8 @@
 	inode->i_mode = 0;
 	inode->i_rdev = 0;
 	inode->i_op = NULL;
+	NFS_FILEID(inode) = 0;
+	NFS_FSID(inode) = 0;
 	NFS_CACHEINV(inode);
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 }
@@ -415,13 +417,15 @@
 		dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			dentry->d_count, !list_empty(&dentry->d_hash));
+		if (!list_empty(&dentry->d_subdirs))
+			shrink_dcache_parent(dentry);
 		if (!dentry->d_count) {
 			dget(dentry);
 			d_drop(dentry);
 			dput(dentry);
 			goto restart;
 		}
-		if (!list_empty(&dentry->d_hash))
+		if (list_empty(&dentry->d_hash))
 			unhashed++;
 	}
 	return unhashed;
@@ -430,7 +434,7 @@
 /*
  * Invalidate the local caches
  */
-static void
+void
 nfs_zap_caches(struct inode *inode)
 {
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
@@ -466,6 +470,8 @@
 	 * do this once. (We don't allow inodes to change types.)
 	 */
 	if (inode->i_mode == 0) {
+		NFS_FILEID(inode) = fattr->fileid;
+		NFS_FSID(inode) = fattr->fsid;
 		inode->i_mode = fattr->mode;
 		if (S_ISREG(inode->i_mode))
 			inode->i_op = &nfs_file_inode_operations;
@@ -487,6 +493,54 @@
 }
 
 /*
+ * In NFSv3 we can have 64bit inode numbers. In order to support
+ * this, and re-exported directories (also seen in NFSv2)
+ * we are forced to allow 2 different inodes to have the same
+ * i_ino.
+ */
+static int
+nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
+{
+	struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+	if (NFS_FSID(inode) != fattr->fsid)
+		return 0;
+	if (NFS_FILEID(inode) != fattr->fileid)
+		return 0;
+	return 1;
+}
+
+static int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+{
+	int unhashed;
+	int is_stale = 0;
+
+	if (inode->i_mode &&
+	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		is_stale = 1;
+
+	if (is_bad_inode(inode))
+		is_stale = 1;
+
+	/*
+	 * If the inode seems stale, free up cached dentries.
+	 */
+	unhashed = nfs_free_dentries(inode);
+
+	/* Assume we're holding an i_count
+	 *
+	 * NB: sockets sometimes have volatile file handles
+	 *     don't invalidate their inodes even if all dentries are
+	 *     unhashed.
+	 */
+	if (unhashed && inode->i_count == unhashed + 1
+	    && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
+		is_stale = 1;
+
+	return is_stale;
+}
+
+/*
  * This is our own version of iget that looks up inodes by file handle
  * instead of inode number.  We use this technique instead of using
  * the vfs read_inode function because there is no way to pass the
@@ -545,54 +599,40 @@
 static struct inode *
 __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
 {
-	struct inode *inode;
-	int max_count, stale_inode, unhashed = 0;
+	struct inode *inode = NULL;
+	unsigned long ino;
 
-retry:
-	inode = iget(sb, fattr->fileid);
-	if (!inode)
+	if (!fattr->nlink) {
+		printk("NFS: Buggy server - nlink == 0!\n");
 		goto out_no_inode;
-	/* N.B. This should be impossible ... */
-	if (inode->i_ino != fattr->fileid)
-		goto out_bad_id;
+	}
 
-	/*
-	 * Check for busy inodes, and attempt to get rid of any
-	 * unused local references. If successful, we release the
-	 * inode and try again.
-	 *
-	 * Note that the busy test uses the values in the fattr,
-	 * as the inode may have become a different object.
-	 * (We can probably handle modes changes here, too.)
-	 */
-	stale_inode = inode->i_mode &&
-		      ((fattr->mode ^ inode->i_mode) & S_IFMT);
-	stale_inode |= inode->i_count && inode->i_count == unhashed;
-	max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
-	if (stale_inode || inode->i_count > max_count + unhashed) {
-		dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
-			inode->i_ino, inode->i_count, inode->i_nlink);
-		unhashed = nfs_free_dentries(inode);
-		if (stale_inode || inode->i_count > max_count + unhashed) {
-			printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-				inode->i_ino, inode->i_count);
-			if (!list_empty(&inode->i_dentry)) {
-				struct dentry *dentry;
-				dentry = list_entry(inode->i_dentry.next,
-						 struct dentry, d_alias);
-				printk("__nfs_fhget: killing %s/%s filehandle\n",
-					dentry->d_parent->d_name.name,
-					dentry->d_name.name);
-				memset(dentry->d_fsdata, 0,
-					sizeof(struct nfs_fh));
-			}
-			remove_inode_hash(inode);
-			nfs_invalidate_inode(inode);
-			unhashed = 0;
-		}
+	ino = fattr->fileid;
+
+	while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
+
+		/*
+		 * Check for busy inodes, and attempt to get rid of any
+		 * unused local references. If successful, we release the
+		 * inode and try again.
+		 *
+		 * Note that the busy test uses the values in the fattr,
+		 * as the inode may have become a different object.
+		 * (We can probably handle modes changes here, too.)
+		 */
+		if (!nfs_inode_is_stale(inode,fattr))
+			break;
+
+		dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+		       inode->i_ino, inode->i_count);
+		nfs_zap_caches(inode);
+		remove_inode_hash(inode);
 		iput(inode);
-		goto retry;
 	}
+
+	if (!inode)
+		goto out_no_inode;
+
 	nfs_fill_inode(inode, fattr);
 	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
 		inode->i_dev, inode->i_ino, inode->i_count);
@@ -603,18 +643,14 @@
 out_no_inode:
 	printk("__nfs_fhget: iget failed\n");
 	goto out;
-out_bad_id:
-	printk("__nfs_fhget: unexpected inode from iget\n");
-	goto out;
 }
 
 int
 nfs_notify_change(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
-	int error;
-	struct nfs_sattr sattr;
 	struct nfs_fattr fattr;
+	int error;
 
 	/*
 	 * Make sure the inode is up-to-date.
@@ -627,54 +663,29 @@
 		goto out;
 	}
 
-	sattr.mode = (u32) -1;
-	if (attr->ia_valid & ATTR_MODE) 
-		sattr.mode = attr->ia_mode;
-
-	sattr.uid = (u32) -1;
-	if (attr->ia_valid & ATTR_UID)
-		sattr.uid = attr->ia_uid;
-
-	sattr.gid = (u32) -1;
-	if (attr->ia_valid & ATTR_GID)
-		sattr.gid = attr->ia_gid;
-
-	sattr.size = (u32) -1;
-	if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
-		sattr.size = attr->ia_size;
-
-	sattr.mtime.seconds = sattr.mtime.useconds = (u32) -1;
-	if (attr->ia_valid & ATTR_MTIME) {
-		sattr.mtime.seconds = attr->ia_mtime;
-		sattr.mtime.useconds = 0;
-	}
-
-	sattr.atime.seconds = sattr.atime.useconds = (u32) -1;
-	if (attr->ia_valid & ATTR_ATIME) {
-		sattr.atime.seconds = attr->ia_atime;
-		sattr.atime.useconds = 0;
-	}
+	if (!S_ISREG(inode->i_mode))
+		attr->ia_valid &= ~ATTR_SIZE;
 
 	error = nfs_wb_all(inode);
 	if (error)
 		goto out;
 
 	error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
-				&sattr, &fattr);
+				&fattr, attr);
 	if (error)
 		goto out;
 	/*
 	 * If we changed the size or mtime, update the inode
 	 * now to avoid invalidating the page cache.
 	 */
-	if (sattr.size != (u32) -1) {
-		if (sattr.size != fattr.size)
-			printk("nfs_notify_change: sattr=%d, fattr=%d??\n",
-				sattr.size, fattr.size);
-		inode->i_size  = sattr.size;
+	if (attr->ia_valid & ATTR_SIZE) {
+		if (attr->ia_size != fattr.size)
+			printk("nfs_notify_change: attr=%ld, fattr=%d??\n",
+				attr->ia_size, fattr.size);
+		inode->i_size  = attr->ia_size;
 		inode->i_mtime = fattr.mtime.seconds;
 	}
-	if (sattr.mtime.seconds != (u32) -1)
+	if (attr->ia_valid & ATTR_MTIME)
 		inode->i_mtime = fattr.mtime.seconds;
 	error = nfs_refresh_inode(inode, &fattr);
 out:
@@ -682,6 +693,34 @@
 }
 
 /*
+ * Wait for the inode to get unlocked.
+ * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
+ */
+int
+nfs_wait_on_inode(struct inode *inode, int flag)
+{
+	struct task_struct	*tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	int			intr, error = 0;
+
+	intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR;
+	add_wait_queue(&inode->i_wait, &wait);
+	for (;;) {
+		set_task_state(tsk, (intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE));
+		error = 0;
+		if (!(NFS_FLAGS(inode) & flag))
+			break;
+		error = -ERESTARTSYS;
+		if (intr && signalled())
+			break;
+		schedule();
+	}
+	set_task_state(tsk, TASK_RUNNING);
+	remove_wait_queue(&inode->i_wait, &wait);
+	return error;
+}
+
+/*
  * Externally visible revalidation function
  */
 int
@@ -711,7 +750,7 @@
  * the cached attributes have to be refreshed.
  */
 int
-_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
 {
 	struct inode	*inode = dentry->d_inode;
 	int		 status = 0;
@@ -720,6 +759,19 @@
 	dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		inode->i_ino);
+
+	if (!inode || is_bad_inode(inode))
+		return -ESTALE;
+
+	while (NFS_REVALIDATING(inode)) {
+		status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
+		if (status < 0)
+			return status;
+		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
+			return 0;
+	}
+	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
+
 	status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
 	if (status) {
 		int error;
@@ -759,6 +811,8 @@
 	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 out:
+	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
+	wake_up(&inode->i_wait);
 	return status;
 }
 
diff -u --recursive --new-file v2.3.22/linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c
--- v2.3.22/linux/fs/nfs/nfs2xdr.c	Tue Jun  8 22:11:58 1999
+++ linux/fs/nfs/nfs2xdr.c	Mon Oct 18 11:26:37 1999
@@ -118,19 +118,35 @@
 	return p;
 }
 
+
+#define SATTR(p, attr, flag, field) \
+        *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
 static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
+xdr_encode_sattr(u32 *p, struct iattr *attr)
 {
-	*p++ = htonl(sattr->mode);
-	*p++ = htonl(sattr->uid);
-	*p++ = htonl(sattr->gid);
-	*p++ = htonl(sattr->size);
-	*p++ = htonl(sattr->atime.seconds);
-	*p++ = htonl(sattr->atime.useconds);
-	*p++ = htonl(sattr->mtime.seconds);
-	*p++ = htonl(sattr->mtime.useconds);
-	return p;
+	SATTR(p, attr, ATTR_MODE, ia_mode);
+	SATTR(p, attr, ATTR_UID, ia_uid);
+	SATTR(p, attr, ATTR_GID, ia_gid);
+	SATTR(p, attr, ATTR_SIZE, ia_size);
+
+	if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
+		*p++ = htonl(attr->ia_atime);
+		*p++ = 0;
+	} else {
+		*p++ = ~(u32) 0;
+		*p++ = ~(u32) 0;
+	}
+
+	if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
+		*p++ = htonl(attr->ia_mtime);
+		*p++ = 0;
+	} else {
+		*p++ = ~(u32) 0;	
+		*p++ = ~(u32) 0;
+	}
+  	return p;
 }
+#undef SATTR
 
 /*
  * NFS encode functions
diff -u --recursive --new-file v2.3.22/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v2.3.22/linux/fs/nfs/proc.c	Tue Jun  8 22:11:58 1999
+++ linux/fs/nfs/proc.c	Mon Oct 18 11:26:37 1999
@@ -65,7 +65,7 @@
 
 int
 nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_sattr *sattr, struct nfs_fattr *fattr)
+			struct nfs_fattr *fattr, struct iattr *sattr)
 {
 	struct nfs_sattrargs	arg = { fhandle, sattr };
 	int	status;
@@ -123,7 +123,7 @@
 
 int
 nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
+			const char *name, struct iattr *sattr,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs_createargs	arg = { dir, name, sattr };
@@ -178,7 +178,7 @@
 int
 nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
 			const char *name, const char *path,
-			struct nfs_sattr *sattr)
+			struct iattr *sattr)
 {
 	struct nfs_symlinkargs	arg = { dir, name, path, sattr };
 	int			status;
@@ -191,7 +191,7 @@
 
 int
 nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
+			const char *name, struct iattr *sattr,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs_createargs	arg = { dir, name, sattr };
diff -u --recursive --new-file v2.3.22/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v2.3.22/linux/fs/nfs/symlink.c	Sat Jun 26 12:04:39 1999
+++ linux/fs/nfs/symlink.c	Tue Oct 19 10:22:19 1999
@@ -59,8 +59,7 @@
 static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode *inode)
 {
 	struct nfs_readlinkargs rl_args;
-	struct page *page, **hash;
-	unsigned long page_cache;
+	struct page *page, **hash, *page_cache;
 
 	page = NULL;
 	page_cache = page_cache_alloc();
@@ -75,7 +74,7 @@
 		goto unlock_out;
 	}
 
-	page = page_cache_entry(page_cache);
+	page = page_cache;
 	if (add_to_page_cache_unique(page, inode, 0, hash)) {
 		page_cache_release(page);
 		goto repeat;
@@ -86,7 +85,7 @@
 	 * XDR response verification will NULL terminate it.
 	 */
 	rl_args.fh = NFS_FH(dentry);
-	rl_args.buffer = (const void *)page_cache;
+	rl_args.buffer = (const void *)page_address(page_cache);
 	if (rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
 		     &rl_args, NULL, 0) < 0)
 		goto error;
diff -u --recursive --new-file v2.3.22/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.22/linux/fs/proc/array.c	Fri Oct 15 15:25:14 1999
+++ linux/fs/proc/array.c	Tue Oct 19 11:56:26 1999
@@ -38,6 +38,7 @@
  *
  * aeb@cwi.nl        :  /proc/partitions
  *
+ *
  * Alan Cox	     :  security fixes.
  *			<Alan.Cox@linux.org>
  *
@@ -45,11 +46,6 @@
  *
  * Gerhard Wichert   :  added BIGMEM support
  * Siemens AG           <Gerhard.Wichert@pdb.siemens.de>
- *
- * Chuck Lever       :  safe handling of task_struct
- *                      <cel@monkey.org>
- *
- * Andrea Arcangeli  :	SMP race/security fixes.
  */
 
 #include <linux/types.h>
@@ -71,7 +67,6 @@
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/signal.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -365,16 +360,24 @@
 	struct sysinfo i;
 	int len;
 
+/*
+ * display in kilobytes.
+ */
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+
 	si_meminfo(&i);
 	si_swapinfo(&i);
 	len = sprintf(buffer, "        total:    used:    free:  shared: buffers:  cached:\n"
-		"Mem:  %8lu %8lu %8lu %8lu %8lu %8lu\n"
+		"Mem:  %8lu %8lu %8lu %8lu %8lu %8u\n"
 		"Swap: %8lu %8lu %8lu\n",
-		i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, (unsigned long) atomic_read(&page_cache_size)*PAGE_SIZE,
-		i.totalswap, i.totalswap-i.freeswap, i.freeswap);
+		K(i.totalram), K(i.totalram-i.freeram), K(i.freeram),
+		K(i.sharedram), K(i.bufferram),
+		K(atomic_read(&page_cache_size)), K(i.totalswap),
+		K(i.totalswap-i.freeswap), K(i.freeswap));
 	/*
-	 * Tagged format, for easy grepping and expansion. The above will go away
-	 * eventually, once the tools have been updated.
+	 * Tagged format, for easy grepping and expansion.
+	 * The above will go away eventually, once the tools
+	 * have been updated.
 	 */
 	return len + sprintf(buffer+len,
 		"MemTotal:  %8lu kB\n"
@@ -382,19 +385,20 @@
 		"MemShared: %8lu kB\n"
 		"Buffers:   %8lu kB\n"
 		"Cached:    %8u kB\n"
-		"BigTotal:  %8lu kB\n"
-		"BigFree:   %8lu kB\n"
+		"HighTotal: %8lu kB\n"
+		"HighFree:  %8lu kB\n"
 		"SwapTotal: %8lu kB\n"
 		"SwapFree:  %8lu kB\n",
-		i.totalram >> 10,
-		i.freeram >> 10,
-		i.sharedram >> 10,
-		i.bufferram >> 10,
-		atomic_read(&page_cache_size) << (PAGE_SHIFT - 10),
-		i.totalbig >> 10,
-		i.freebig >> 10,
-		i.totalswap >> 10,
-		i.freeswap >> 10);
+		K(i.totalram),
+		K(i.freeram),
+		K(i.sharedram),
+		K(i.bufferram),
+		K(atomic_read(&page_cache_size)),
+		K(i.totalhigh),
+		K(i.freehigh),
+		K(i.totalswap),
+		K(i.freeswap));
+#undef K
 }
 
 static int get_version(char * buffer)
@@ -412,69 +416,68 @@
 	return sprintf(buffer, "%s\n", saved_command_line);
 }
 
-static unsigned long get_phys_addr(struct mm_struct * mm, unsigned long ptr)
+static struct page * get_phys_addr(struct mm_struct * mm, unsigned long ptr)
 {
-	pgd_t *page_dir;
-	pmd_t *page_middle;
+	pgd_t *pgd;
+	pmd_t *pmd;
 	pte_t pte;
 
 	if (ptr >= TASK_SIZE)
 		return 0;
-	page_dir = pgd_offset(mm,ptr);
-	if (pgd_none(*page_dir))
+	pgd = pgd_offset(mm,ptr);
+	if (pgd_none(*pgd))
 		return 0;
-	if (pgd_bad(*page_dir)) {
-		printk("bad page directory entry %08lx\n", pgd_val(*page_dir));
-		pgd_clear(page_dir);
+	if (pgd_bad(*pgd)) {
+		pgd_ERROR(*pgd);
+		pgd_clear(pgd);
 		return 0;
 	}
-	page_middle = pmd_offset(page_dir,ptr);
-	if (pmd_none(*page_middle))
+	pmd = pmd_offset(pgd,ptr);
+	if (pmd_none(*pmd))
 		return 0;
-	if (pmd_bad(*page_middle)) {
-		printk("bad page middle entry %08lx\n", pmd_val(*page_middle));
-		pmd_clear(page_middle);
+	if (pmd_bad(*pmd)) {
+		pmd_ERROR(*pmd);
+		pmd_clear(pmd);
 		return 0;
 	}
-	pte = *pte_offset(page_middle,ptr);
+	pte = *pte_offset(pmd,ptr);
 	if (!pte_present(pte))
 		return 0;
-	return pte_page(pte) + (ptr & ~PAGE_MASK);
+	return pte_page(pte);
 }
 
-#include <linux/bigmem.h>
-
 static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
 {
-	unsigned long addr;
+	struct page *page;
+	unsigned long kaddr;
 	int size = 0, result = 0;
 	char c;
 
 	if (start >= end)
 		return result;
 	for (;;) {
-		addr = get_phys_addr(mm, start);
-		if (!addr)
+		page = get_phys_addr(mm, start);
+		if (!page)
 			return result;
-		addr = kmap(addr, KM_READ);
+		kaddr = kmap(page, KM_READ) + (start & ~PAGE_MASK);
 		do {
-			c = *(char *) addr;
+			c = *(char *) kaddr;
 			if (!c)
 				result = size;
 			if (size < PAGE_SIZE)
 				buffer[size++] = c;
 			else {
-				kunmap(addr, KM_READ);
+				kunmap(kaddr, KM_READ);
 				return result;
 			}
-			addr++;
+			kaddr++;
 			start++;
 			if (!c && start >= end) {
-				kunmap(addr, KM_READ);
+				kunmap(kaddr, KM_READ);
 				return result;
 			}
-		} while (addr & ~PAGE_MASK);
-		kunmap(addr-1, KM_READ);
+		} while (kaddr & ~PAGE_MASK);
+		kunmap(kaddr, KM_READ);
 	}
 	return result;
 }
@@ -483,9 +486,7 @@
 {
 	struct task_struct *p;
 	struct mm_struct *mm = NULL;
-
-	/* need kernel lock to avoid the tsk->mm to go away under us */
-	lock_kernel();
+	
 	read_lock(&tasklist_lock);
 	p = find_task_by_pid(pid);
 	if (p)
@@ -493,10 +494,10 @@
 	if (mm)
 		atomic_inc(&mm->mm_users);
 	read_unlock(&tasklist_lock);
-	unlock_kernel();
 	return mm;
 }
 
+
 static int get_env(int pid, char * buffer)
 {
 	struct mm_struct *mm = get_mm(pid);
@@ -849,9 +850,6 @@
 	return buffer;
 }
 
-/*
- * These next two assume that the task's sigmask_lock is held by the caller.
- */
 static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
 				    sigset_t *catch)
 {
@@ -904,115 +902,77 @@
 			    cap_t(p->cap_effective));
 }
 
-/*
- * This is somewhat safer than it was before.  However...
- *
- * Embedded pointers in the task structure may reference data that
- * can be changed or that is no longer valid after the tasklist
- * lock is released, or that isn't even protected by the tasklist
- * lock.  Eg. tsk->tty, tsk->sig, and tsk->p_pptr can change after
- * we make our own copy of the task structure.  This doesn't matter
- * unless we are trying to use the pointed-to data as an address.
- * So there are still a few safety issues to be addressed here.
- */
+
 static int get_status(int pid, char * buffer)
 {
 	char * orig = buffer;
 	struct task_struct *tsk;
 	struct mm_struct *mm = NULL;
 
-	/*
-	 * We lock the whole kernel here because p->files and p->mm are still
-	 * protected by the global kernel lock.
-	 */
-	lock_kernel();
-
 	read_lock(&tasklist_lock);
 	tsk = find_task_by_pid(pid);
-	if (tsk) {
+	if (tsk)
 		mm = tsk->mm;
-		if (mm)
-			atomic_inc(&mm->mm_users);
-
-		buffer = task_name(tsk, buffer);
-		buffer = task_state(tsk, buffer);
-
-		spin_lock_irq(&tsk->sigmask_lock);
-		buffer = task_sig(tsk, buffer);
-		spin_unlock_irq(&tsk->sigmask_lock);
-
-		buffer = task_cap(tsk, buffer);
-	}
-	read_unlock(&tasklist_lock);
-
-	unlock_kernel();
-
-	/*
-	 * We can't hold the tasklist_lock and jiggle the mmap_sem --
-	 * that can result in a deadlock.
-	 */
-	if (mm) {
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
+	if (!tsk)
+		return 0;
+	buffer = task_name(tsk, buffer);
+	buffer = task_state(tsk, buffer);
+	if (mm)
 		buffer = task_mem(mm, buffer);
+	buffer = task_sig(tsk, buffer);
+	buffer = task_cap(tsk, buffer);
+	if (mm)
 		mmput(mm);
-	}
-
-	/*
-	 * (buffer - orig) will be zero on an error exit.
-	 */
 	return buffer - orig;
 }
 
 static int get_stat(int pid, char * buffer)
 {
 	struct task_struct *tsk;
-	struct mm_struct *mm;
+	struct mm_struct *mm = NULL;
 	unsigned long vsize, eip, esp, wchan;
 	long priority, nice;
-	pid_t ppid = 0;
+	int tty_pgrp;
 	sigset_t sigign, sigcatch;
 	char state;
-	int res = 0;
-	unsigned int tty_device;
-	int tty_pgrp;
+	int res;
 
 	read_lock(&tasklist_lock);
 	tsk = find_task_by_pid(pid);
-	if (!tsk)
-		goto out_unlock;
-	/* avoid the task list to go away under us (security) */
-	get_page(MAP_NR(tsk) + mem_map);
-	ppid = tsk->p_pptr->pid;
-	read_unlock(&tasklist_lock);
-
-	/* we need the big kernel lock to avoid tsk->mm and tsk->tty
-	   to change under us */
-	lock_kernel();
-	mm = tsk->mm;
+	if (tsk)
+		mm = tsk->mm;
 	if (mm)
 		atomic_inc(&mm->mm_users);
-	tty_device = tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0;
-	tty_pgrp = tsk->tty ? tsk->tty->pgrp : -1;
-	unlock_kernel();
-
-	spin_lock_irq(&tsk->sigmask_lock);
-	collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
-	spin_unlock_irq(&tsk->sigmask_lock);
-
-	eip = KSTK_EIP(tsk);
-	esp = KSTK_ESP(tsk);
-	wchan = get_wchan(tsk);
-
+	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
+	if (!tsk)
+		return 0;
 	state = *get_task_state(tsk);
 	vsize = eip = esp = 0;
-	if (mm)
-	{
+	if (mm) {
 		struct vm_area_struct *vma;
 		down(&mm->mmap_sem);
-		for (vma = mm->mmap; vma; vma = vma->vm_next)
+		vma = mm->mmap;
+		while (vma) {
 			vsize += vma->vm_end - vma->vm_start;
+			vma = vma->vm_next;
+		}
+		eip = KSTK_EIP(tsk);
+		esp = KSTK_ESP(tsk);
 		up(&mm->mmap_sem);
 	}
 
+	wchan = get_wchan(tsk);
+
+	collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
+
+	if (tsk->tty)
+		tty_pgrp = tsk->tty->pgrp;
+	else
+		tty_pgrp = -1;
+
 	/* scale priority and nice values from timeslices to -20..20 */
 	/* to make it look like a "normal" Unix priority/nice value  */
 	priority = tsk->counter;
@@ -1026,10 +986,10 @@
 		pid,
 		tsk->comm,
 		state,
-		ppid,
+		tsk->p_pptr->pid,
 		tsk->pgrp,
 		tsk->session,
-		tty_device,
+	        tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
 		tty_pgrp,
 		tsk->flags,
 		tsk->min_flt,
@@ -1066,16 +1026,9 @@
 		tsk->cnswap,
 		tsk->exit_signal,
 		tsk->processor);
-
 	if (mm)
 		mmput(mm);
-	free_task_struct(tsk);
 	return res;
-
-out_unlock:
-	read_unlock(&tasklist_lock);
-	unlock_kernel();
-	return 0;
 }
 		
 static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -1087,7 +1040,7 @@
 	if (pmd_none(*pmd))
 		return;
 	if (pmd_bad(*pmd)) {
-		printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		return;
 	}
@@ -1125,7 +1078,7 @@
 	if (pgd_none(*pgd))
 		return;
 	if (pgd_bad(*pgd)) {
-		printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
+		pgd_ERROR(*pgd);
 		pgd_clear(pgd);
 		return;
 	}
@@ -1223,11 +1176,11 @@
 			  size_t count, loff_t *ppos)
 {
 	struct task_struct *p;
-	struct mm_struct *mm = NULL;
 	struct vm_area_struct * map, * next;
 	char * destptr = buf, * buffer;
 	loff_t lineno;
 	ssize_t column, i;
+	int volatile_task;
 	long retval;
 
 	/*
@@ -1239,30 +1192,24 @@
 		goto out;
 
 	retval = -EINVAL;
-	lock_kernel();
 	read_lock(&tasklist_lock);
 	p = find_task_by_pid(pid);
-	if (p) {
-		mm = p->mm;
-		if (mm)
-			atomic_inc(&mm->mm_users);
-	}
-	read_unlock(&tasklist_lock);
-	unlock_kernel();
+	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
 	if (!p)
 		goto freepage_out;
 
-	/* nothing to map */
-	if (!mm || count == 0)
+	if (!p->mm || count == 0)
 		goto getlen_out;
 
+	/* Check whether the mmaps could change if we sleep */
+	volatile_task = (p != current || atomic_read(&p->mm->mm_users) > 1);
+
 	/* decode f_pos */
 	lineno = *ppos >> MAPS_LINE_SHIFT;
 	column = *ppos & (MAPS_LINE_LENGTH-1);
 
-	down(&mm->mmap_sem);
-	/* quickly go to line "lineno" */
-	for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+	/* quickly go to line lineno */
+	for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
 		continue;
 
 	for ( ; map ; map = next ) {
@@ -1333,13 +1280,17 @@
 		/* done? */
 		if (count == 0)
 			break;
+
+		/* By writing to user space, we might have slept.
+		 * Stop the loop, to avoid a race condition.
+		 */
+		if (volatile_task)
+			break;
 	}
-	up(&mm->mmap_sem);
 
 	/* encode f_pos */
 	*ppos = (lineno << MAPS_LINE_SHIFT) + column;
 
-	mmput(mm);
 getlen_out:
 	retval = destptr - buf;
 
@@ -1352,31 +1303,28 @@
 #ifdef __SMP__
 static int get_pidcpu(int pid, char * buffer)
 {
-	struct task_struct * tsk;
-	int i, len = 0;
+	struct task_struct * tsk = current ;
+	int i, len;
 
-	/*
-	 * Hold the tasklist_lock to guarantee that the task_struct
-	 * address will remain valid while we examine its contents.
-	 */
 	read_lock(&tasklist_lock);
-	tsk = find_task_by_pid(pid);
-	if (tsk)
-		get_page(MAP_NR(tsk) + mem_map);
-	read_unlock(&tasklist_lock);
-	if (tsk) {
-		len = sprintf(buffer,
-			"cpu  %lu %lu\n",
-			tsk->times.tms_utime,
-			tsk->times.tms_stime);
+	if (pid != tsk->pid)
+		tsk = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
+
+	if (tsk == NULL)
+		return 0;
+
+	len = sprintf(buffer,
+		"cpu  %lu %lu\n",
+		tsk->times.tms_utime,
+		tsk->times.tms_stime);
 		
-		for (i = 0 ; i < smp_num_cpus; i++)
-			len += sprintf(buffer + len, "cpu%d %lu %lu\n",
-				i,
-				tsk->per_cpu_utime[cpu_logical_map(i)],
-				tsk->per_cpu_stime[cpu_logical_map(i)]);
-		free_task_struct(tsk);
-	}
+	for (i = 0 ; i < smp_num_cpus; i++)
+		len += sprintf(buffer + len, "cpu%d %lu %lu\n",
+			i,
+			tsk->per_cpu_utime[cpu_logical_map(i)],
+			tsk->per_cpu_stime[cpu_logical_map(i)]);
+
 	return len;
 }
 #endif
@@ -1513,6 +1461,12 @@
 	int ok = 0;
 		
 	read_lock(&tasklist_lock);
+	
+	/*
+	 *	Grab the lock, find the task, save the uid and
+	 *	check it has an mm still (ie its not dead)
+	 */
+	
 	p = find_task_by_pid(pid);
 	if (p) {
 		euid=p->euid;
@@ -1520,7 +1474,9 @@
 		if(!cap_issubset(p->cap_permitted, current->cap_permitted))
 			ok=0;			
 	}
+		
 	read_unlock(&tasklist_lock);
+
 	if (!p)
 		return 1;
 
diff -u --recursive --new-file v2.3.22/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.3.22/linux/fs/proc/mem.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/proc/mem.c	Tue Oct 19 10:40:48 1999
@@ -10,7 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -79,9 +79,10 @@
 	pgd_t *page_dir;
 	pmd_t *page_middle;
 	pte_t pte;
-	char * page;
+	struct page * page;
 	struct task_struct * tsk;
 	unsigned long addr;
+	unsigned long maddr; /* temporary mapped address */
 	char *tmp;
 	ssize_t scount, i;
 
@@ -102,7 +103,7 @@
 		if (pgd_none(*page_dir))
 			break;
 		if (pgd_bad(*page_dir)) {
-			printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
+			pgd_ERROR(*page_dir);
 			pgd_clear(page_dir);
 			break;
 		}
@@ -110,20 +111,20 @@
 		if (pmd_none(*page_middle))
 			break;
 		if (pmd_bad(*page_middle)) {
-			printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
+			pmd_ERROR(*page_middle);
 			pmd_clear(page_middle);
 			break;
 		}
 		pte = *pte_offset(page_middle,addr);
 		if (!pte_present(pte))
 			break;
-		page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
+		page = pte_page(pte);
 		i = PAGE_SIZE-(addr & ~PAGE_MASK);
 		if (i > scount)
 			i = scount;
-		page = (char *) kmap((unsigned long) page, KM_READ);
-		copy_to_user(tmp, page, i);
-		kunmap((unsigned long) page, KM_READ);
+		maddr = kmap(page, KM_READ);
+		copy_to_user(tmp, (char *)maddr + (addr & ~PAGE_MASK), i);
+		kunmap(maddr, KM_READ);
 		addr += i;
 		tmp += i;
 		scount -= i;
@@ -141,9 +142,10 @@
 	pgd_t *page_dir;
 	pmd_t *page_middle;
 	pte_t pte;
-	char * page;
+	struct page * page;
 	struct task_struct * tsk;
 	unsigned long addr;
+	unsigned long maddr; /* temporary mapped address */
 	char *tmp;
 	long i;
 
@@ -159,7 +161,7 @@
 		if (pgd_none(*page_dir))
 			break;
 		if (pgd_bad(*page_dir)) {
-			printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
+			pgd_ERROR(*page_dir);
 			pgd_clear(page_dir);
 			break;
 		}
@@ -167,7 +169,7 @@
 		if (pmd_none(*page_middle))
 			break;
 		if (pmd_bad(*page_middle)) {
-			printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
+			pmd_ERROR(*page_middle);
 			pmd_clear(page_middle);
 			break;
 		}
@@ -176,13 +178,13 @@
 			break;
 		if (!pte_write(pte))
 			break;
-		page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
+		page = pte_page(pte);
 		i = PAGE_SIZE-(addr & ~PAGE_MASK);
 		if (i > count)
 			i = count;
-		page = (unsigned long) kmap((unsigned long) page, KM_WRITE);
-		copy_from_user(page, tmp, i);
-		kunmap((unsigned long) page, KM_WRITE);
+		maddr = kmap(page, KM_WRITE);
+		copy_from_user((char *)maddr + (addr & ~PAGE_MASK), tmp, i);
+		kunmap(maddr, KM_WRITE);
 		addr += i;
 		tmp += i;
 		count -= i;
@@ -248,14 +250,14 @@
 		if (pgd_none(*src_dir))
 			return -EINVAL;
 		if (pgd_bad(*src_dir)) {
-			printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
+			pgd_ERROR(*src_dir);
 			return -EINVAL;
 		}
 		src_middle = pmd_offset(src_dir, stmp);
 		if (pmd_none(*src_middle))
 			return -EINVAL;
 		if (pmd_bad(*src_middle)) {
-			printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
+			pmd_ERROR(*src_middle);
 			return -EINVAL;
 		}
 		src_table = pte_offset(src_middle, stmp);
@@ -301,9 +303,9 @@
 
 		set_pte(src_table, pte_mkdirty(*src_table));
 		set_pte(dest_table, *src_table);
-		mapnr = MAP_NR(pte_page(*src_table));
+		mapnr = pte_pagenr(*src_table);
 		if (mapnr < max_mapnr)
-			get_page(mem_map + MAP_NR(pte_page(*src_table)));
+			get_page(mem_map + pte_pagenr(*src_table));
 
 		stmp += PAGE_SIZE;
 		dtmp += PAGE_SIZE;
diff -u --recursive --new-file v2.3.22/linux/fs/super.c linux/fs/super.c
--- v2.3.22/linux/fs/super.c	Fri Oct 15 15:25:14 1999
+++ linux/fs/super.c	Sat Oct 16 10:56:28 1999
@@ -135,7 +135,7 @@
 	return lptr;
 }
 
-static void remove_vfsmnt(kdev_t dev)
+void remove_vfsmnt(kdev_t dev)
 {
 	struct vfsmount *lptr, *tofree;
 
@@ -508,7 +508,7 @@
 /*
  * Find a super_block with no device assigned.
  */
-static struct super_block *get_empty_super(void)
+struct super_block *get_empty_super(void)
 {
 	struct super_block *s;
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h
--- v2.3.22/linux/include/asm-arm/a.out.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/a.out.h	Wed Oct 20 16:29:08 1999
@@ -27,7 +27,8 @@
 #define M_ARM 103
 
 #ifdef __KERNEL__
-#include <asm/arch/a.out.h>
+#define STACK_TOP	((current->personality == PER_LINUX_32BIT) ? \
+			 TASK_SIZE : TASK_SIZE_26)
 #endif
 
 #ifndef LIBRARY_START_TEXT
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arcaudio.h linux/include/asm-arm/arcaudio.h
--- v2.3.22/linux/include/asm-arm/arcaudio.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arcaudio.h	Wed Dec 31 16:00:00 1969
@@ -1,51 +0,0 @@
-/* 
- * arcaudio.h
- *
- */
-
-#ifndef _LINUX_ARCAUDIO_H
-#define _LINUX_ARCAUDIO_H
-
-#define ARCAUDIO_MAXCHANNELS	8
-
-enum ch_type
-{
-  ARCAUDIO_NONE,			/* No sound (muted) */
-  ARCAUDIO_8BITSIGNED,			/* signed 8 bits per samples */
-  ARCAUDIO_8BITUNSIGNED,		/* unsigned 8 bits per samples */
-  ARCAUDIO_16BITSIGNED,			/* signed 16 bits per samples (little endian) */
-  ARCAUDIO_16BITUNSIGNED,		/* unsigned 16 bits per samples (little endian) */
-  ARCAUDIO_LOG				/* Vidc Log */
-};
-
-/* 
- * Global information
- */
-struct arcaudio
-{
-  int		sample_rate;		/* sample rate (Hz) */
-  int		num_channels;		/* number of channels */
-  int		volume;			/* overall system volume */
-};
-
-/* 
- * Per channel information
- */
-struct arcaudio_channel
-{
-  int		stereo_position;	/* Channel position */
-  int		channel_volume;		/* Channel volume */
-  enum ch_type	channel_type;		/* Type of channel */
-  int		buffer_size;		/* Size of channel buffer */
-};
-
-/* IOCTLS */
-#define ARCAUDIO_GETINFO	0x6101
-#define ARCAUDIO_SETINFO	0x6102
-#define ARCAUDIO_GETCHANNELINFO	0x6111
-#define ARCAUDIO_SETCHANNELINFO	0x6112
-#define ARCAUDIO_GETOPTS	0x61f0
-#define ARCAUDIO_SETOPTS	0x61f1
-#define  ARCAUDIO_OPTSPKR	1<<0
-
-#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/a.out.h linux/include/asm-arm/arch-arc/a.out.h
--- v2.3.22/linux/include/asm-arm/arch-arc/a.out.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-arc/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * linux/include/asm-arm/arch-arc/a.out.h
- *
- * Copyright (C) 1996-1999 Russell King
- */
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#include <asm/arch/memory.h>
-
-#define STACK_TOP	TASK_SIZE
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h
--- v2.3.22/linux/include/asm-arm/arch-arc/hardware.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-arc/hardware.h	Wed Oct 20 16:29:08 1999
@@ -49,7 +49,7 @@
 #define SCREEN1_BASE		0x01f88000
 
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 /*
  * for use with inb/outb
@@ -101,5 +101,17 @@
 #define PCIO_BASE		0x03010000
 
 #endif
+
+#ifdef HAS_EXPMASK
+#ifndef __ASSEMBLY__
+#define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
+#else
+#define __EXPMASK(offset)	offset
+#endif
+
+#define	EXPMASK_STATUS	__EXPMASK(0x00)
+#define EXPMASK_ENABLE	__EXPMASK(0x04)
+
 #endif
 
+#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/ide.h linux/include/asm-arm/arch-arc/ide.h
--- v2.3.22/linux/include/asm-arm/arch-arc/ide.h	Mon Aug  2 10:19:52 1999
+++ linux/include/asm-arm/arch-arc/ide.h	Wed Oct 20 16:29:08 1999
@@ -42,7 +42,7 @@
 #ifdef CONFIG_ARCH_A5K
 	hw_regs_t hw;
 
-        memset(hw, 0, sizeof(*hw));
+        memset(&hw, 0, sizeof(hw));
 
 	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
 	ide_register_hw(&hw, NULL);
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h
--- v2.3.22/linux/include/asm-arm/arch-arc/irq.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-arc/irq.h	Wed Oct 20 16:29:08 1999
@@ -152,4 +152,6 @@
 			break;
 		}
 	}
+
+	init_FIQ();
 }
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/memory.h linux/include/asm-arm/arch-arc/memory.h
--- v2.3.22/linux/include/asm-arm/arch-arc/memory.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-arc/memory.h	Wed Oct 20 16:29:08 1999
@@ -15,6 +15,7 @@
  * User space: 26MB
  */
 #define TASK_SIZE	(0x01a00000UL)
+#define TASK_SIZE_26	(0x01a00000UL)
 
 /*
  * Page offset: 32MB
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/param.h linux/include/asm-arm/arch-arc/param.h
--- v2.3.22/linux/include/asm-arm/arch-arc/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-arc/param.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,3 @@
+/*
+ * linux/include/asm-arm/arch-arc/param.h
+ */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/processor.h linux/include/asm-arm/arch-arc/processor.h
--- v2.3.22/linux/include/asm-arm/arch-arc/processor.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-arc/processor.h	Wed Oct 20 16:29:08 1999
@@ -11,8 +11,6 @@
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
-#include <asm/arch/memory.h>
-
 /*
  * Bus types
  */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/shmparam.h linux/include/asm-arm/arch-arc/shmparam.h
--- v2.3.22/linux/include/asm-arm/arch-arc/shmparam.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-arc/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- v2.3.22/linux/include/asm-arm/arch-arc/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/arch-arc/system.h	Wed Oct 20 16:29:08 1999
@@ -1,11 +1,8 @@
 /*
  * linux/include/asm-arm/arch-arc/system.h
  *
- * Copyright (c) 1996 Russell King and Dave Gilbert
+ * Copyright (c) 1996-1999 Russell King and Dave Gilbert
  */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
 #include <linux/config.h>
 
 #ifdef CONFIG_ARCH_ARC
@@ -23,16 +20,13 @@
 
 #endif
 
+#define arch_do_idle() do { } while (0)
+
 extern __inline__ void arch_reset(char mode)
 {
 	extern void ecard_reset(int card);
 
 	/*
-	 * Do any cleanups that the processor may require
-	 */
-	cpu_proc_fin();
-
-	/*
 	 * Reset all expansion cards.
 	 */
 	ecard_reset(-1);
@@ -43,5 +37,3 @@
 	*(unsigned long *)0 = *(unsigned long *)0x03800000;
 	((void(*)(void))0)();
 }
-
-#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/a.out.h linux/include/asm-arm/arch-ebsa110/a.out.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/a.out.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa110/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/a.out.h
- *
- * Copyright (C) 1996-1999 Russell King
- */
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#include <asm/arch/memory.h>
-
-#define STACK_TOP \
-	((current->personality == PER_LINUX_32BIT) ? \
-	 TASK_SIZE : 0x04000000)
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/hardware.h	Mon Jul 19 09:52:57 1999
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Wed Oct 20 16:29:08 1999
@@ -8,7 +8,7 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 /*
  * IO definitions
@@ -28,11 +28,11 @@
  */
 #define FLUSH_BASE_PHYS		0x40000000
 
-#else
+#else	/* __ASSEMBLY__ */
 
 #define IO_BASE			0
 
-#endif
+#endif	/* __ASSEMBLY__ */
 
 #define IO_SIZE			0x20000000
 #define IO_START		0xe0000000
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/memory.h linux/include/asm-arm/arch-ebsa110/memory.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/memory.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa110/memory.h	Wed Oct 20 16:29:08 1999
@@ -16,6 +16,7 @@
  * Task size: 3GB
  */
 #define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
 
 /*
  * Page offset: 3GB
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/param.h linux/include/asm-arm/arch-ebsa110/param.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/param.h	Sun Sep  6 10:45:30 1998
+++ linux/include/asm-arm/arch-ebsa110/param.h	Wed Oct 20 16:29:08 1999
@@ -1,8 +1,3 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/param.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1998 Philip Blundell
  */
-
-#define HZ 100
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/processor.h linux/include/asm-arm/arch-ebsa110/processor.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/processor.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa110/processor.h	Wed Oct 20 16:29:08 1999
@@ -10,8 +10,6 @@
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
-#include <asm/arch/memory.h>
-
 /*
  * Bus types
  */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/shmparam.h linux/include/asm-arm/arch-ebsa110/shmparam.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/shmparam.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/system.h	Thu Jan  7 15:51:33 1999
+++ linux/include/asm-arm/arch-ebsa110/system.h	Wed Oct 20 16:29:08 1999
@@ -1,17 +1,12 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/system.h
  *
- * Copyright (c) 1996-1998 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
  */
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-extern __inline__ void arch_reset(char mode)
-{
-	/*
-	 * loop endlessly
-	 */
-	cli();
-}
+#define arch_do_idle()		do { } while (0)
+#define arch_reset(mode)	do { } while (0)
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa110/time.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa110/time.h	Wed Oct 20 16:29:08 1999
@@ -23,13 +23,13 @@
 #define PIT1_COUNT 0xecbe
 #elif defined(MCLK_47_8)
 /*
- * This should be 0x10AE1, but that doesn't exactly fit.
+ * This should be 0x10B43, but that doesn't exactly fit.
  * We run the timer interrupt at 5ms, and then divide it by
  * two in software...  This is so that the user processes
  * see exactly the same model whichever ARM processor they're
  * running on.
  */
-#define PIT1_COUNT 0x8570
+#define PIT1_COUNT 0x85A1
 #define DIVISOR 2
 #endif
  
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/a.out.h linux/include/asm-arm/arch-ebsa285/a.out.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/a.out.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/a.out.h
- *
- * Copyright (C) 1996-1999 Russell King
- */
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#include <asm/arch/memory.h>
-
-#define STACK_TOP \
-	((current->personality == PER_LINUX_32BIT) ? \
-	 TASK_SIZE : 0x04000000)
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/hardware.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/hardware.h	Wed Oct 20 16:29:08 1999
@@ -122,8 +122,10 @@
 #define GPIO_RESET		0x001
 
 /* CPLD pins */
-#define CPLD_DSRESET		8
+#define CPLD_DS_ENABLE		8
+#define CPLD_7111_DISABLE	4
 #define CPLD_UNMUTE		2
+#define CPLD_FLASH_WR_ENABLE	1
 
 #ifndef __ASSEMBLY__
 extern void gpio_modify_op(int mask, int set);
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/io.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/arch-ebsa285/io.h	Wed Oct 20 16:29:08 1999
@@ -74,7 +74,9 @@
 	void *_ret = NULL;						\
 	if (valid_ioaddr(_addr, _size)) {				\
 		_addr = io_to_phys(_addr);				\
-		_ret = __ioremap(_addr, _size, 0) - IO_FUDGE_FACTOR;	\
+		_ret = __ioremap(_addr, _size, 0);			\
+		if (_ret)						\
+			_ret = (void *)((int) _ret - IO_FUDGE_FACTOR);	\
 	}								\
 	_ret; })
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/irq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Wed Oct 20 16:29:08 1999
@@ -10,7 +10,7 @@
  *  26-Jan-1999	PJB	Don't use IACK on CATS
  *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
-#include <linux/config.h>
+/* no need for config.h - arch/arm/kernel/irq.c does this for us */
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
@@ -135,28 +135,21 @@
 	 * Determine the ISA settings for
 	 * the machine we're running on.
 	 */
-	switch (machine_arch_type) {
-	default:
-		isa_irq = -1;
-		break;
+	isa_irq = -1;
 
-	case MACH_TYPE_EBSA285:
+	if (machine_is_ebsa285())
 		/* The following is dependent on which slot
 		 * you plug the Southbridge card into.  We
 		 * currently assume that you plug it into
 		 * the right-hand most slot.
 		 */
 		isa_irq = IRQ_PCI;
-		break;
 
-	case MACH_TYPE_CATS:
+	if (machine_is_cats())
 		isa_irq = IRQ_IN2;
-		break;
 
-	case MACH_TYPE_NETWINDER:
+	if (machine_is_netwinder())
 		isa_irq = IRQ_IN3;
-		break;
-	}
 
 	if (isa_irq != -1) {
 		/*
@@ -176,8 +169,6 @@
 		outb(0x01, PIC_MASK_HI);	/* x86			*/
 		outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
 
-//		outb(0x68, PIC_LO);		/* enable special mode	*/
-//		outb(0x68, PIC_HI);		/* enable special mode	*/
 		outb(0x0b, PIC_LO);
 		outb(0x0b, PIC_HI);
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/keyboard.h linux/include/asm-arm/arch-ebsa285/keyboard.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/keyboard.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/keyboard.h	Wed Oct 20 16:29:08 1999
@@ -69,3 +69,23 @@
 #define kbd_enable_irq()
 
 #define SYSRQ_KEY	0x54
+
+/* resource allocation */
+#define kbd_request_region()
+#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
+					     "keyboard", NULL)
+
+/* How to access the keyboard macros on this platform.  */
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+#define kbd_write_output(val) outb(val, KBD_DATA_REG)
+#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
+
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
+
+#define aux_request_irq(hand, dev_id)					\
+	request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
+
+#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id)
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/memory.h	Wed Jun 30 11:24:55 1999
+++ linux/include/asm-arm/arch-ebsa285/memory.h	Wed Oct 20 16:29:08 1999
@@ -23,6 +23,7 @@
  * Task size: 3GB
  */
 #define TASK_SIZE		(0xc0000000UL)
+#define TASK_SIZE_26		(0x04000000UL)
 
 /*
  * Page offset: 3GB
@@ -42,6 +43,7 @@
  * Task size: 1.5GB
  */
 #define TASK_SIZE		(0x60000000UL)
+#define TASK_SIZE_26		(0x04000000UL)
 
 /*
  * Page offset: 1.5GB
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/param.h linux/include/asm-arm/arch-ebsa285/param.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/param.h	Sun Sep  6 10:45:30 1998
+++ linux/include/asm-arm/arch-ebsa285/param.h	Wed Oct 20 16:29:08 1999
@@ -1,8 +1,3 @@
 /*
  * linux/include/asm-arm/arch-ebsa285/param.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1998 Philip Blundell
  */
-
-#define HZ 100
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/processor.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/processor.h	Wed Oct 20 16:29:08 1999
@@ -10,8 +10,6 @@
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
-#include <asm/arch/memory.h>
-
 /*
  * Bus types
  */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/shmparam.h linux/include/asm-arm/arch-ebsa285/shmparam.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/shmparam.h	Sun Apr 12 11:42:15 1998
+++ linux/include/asm-arm/arch-ebsa285/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/system.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/arch-ebsa285/system.h	Wed Oct 20 16:29:08 1999
@@ -1,24 +1,22 @@
 /*
  * linux/include/asm-arm/arch-ebsa285/system.h
  *
- * Copyright (c) 1996,1997,1998 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
  */
 #include <asm/dec21285.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/leds.h>
 
+#define arch_do_idle()		cpu_do_idle()
+
 extern __inline__ void arch_reset(char mode)
 {
-	cli();
-
 	if (mode == 's') {
 		__asm__ volatile (
 		"mov	lr, #0x41000000		@ prepare to jump to ROM
-		 mov	r0, #0x130
-		 mcr	p15, 0, r0, c1, c0	@ MMU off
-		 mcr	p15, 0, ip, c7, c7	@ flush caches
-		 mov	pc, lr" : : : "cc");
+		 mcr	p15, 0, %0, c1, c0, 0	@ MMU off
+		 mov	pc, lr" : : "r" (cpu_reset()) : "cc");
 	} else {
 		if (machine_is_netwinder()) {
 			/* open up the SuperIO chip
@@ -51,6 +49,3 @@
 		}
 	}
 }
-
-#define arch_start_idle()	leds_event(led_idle_start)
-#define arch_end_idle()		leds_event(led_idle_end)
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/time.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/arch-ebsa285/time.h	Wed Oct 20 16:29:08 1999
@@ -282,7 +282,7 @@
  */
 extern __inline__ void setup_timer(void)
 {
-	if (machine_arch_type == MACH_TYPE_CO285)
+	if (machine_is_co285())
 		/*
 		 * Add-in 21285s shouldn't access the RTC
 		 */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h
--- v2.3.22/linux/include/asm-arm/arch-ebsa285/uncompress.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/uncompress.h	Wed Oct 20 16:29:08 1999
@@ -1,18 +1,24 @@
 /*
  * linux/include/asm-arm/arch-ebsa285/uncompress.h
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
 
 /*
  * Note! This could cause problems on the NetWinder
  */
-#define BASE 0x42000160
+#define DC21285_BASE ((volatile unsigned int *)0x42000160)
+#define SER0_BASE    ((volatile unsigned char *)0x7c0003f8)
 
 static __inline__ void putc(char c)
 {
-	while (*((volatile unsigned int *)(BASE + 0x18)) & 8);
-	*((volatile unsigned int *)(BASE)) = c;
+	if (machine_is_netwinder()) {
+		while ((SER0_BASE[5] & 0x60) != 0x60);
+		SER0_BASE[0] = c;
+	} else {
+		while (DC21285_BASE[6] & 8);
+		DC21285_BASE[0] = c;
+	}
 }
 
 /*
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-nexuspci/a.out.h linux/include/asm-arm/arch-nexuspci/a.out.h
--- v2.3.22/linux/include/asm-arm/arch-nexuspci/a.out.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-nexuspci/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/a.out.h
- *
- * Copyright (C) 1996-1999 Russell King
- */
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#include <asm/arch/memory.h>
-
-#define STACK_TOP \
-	((current->personality == PER_LINUX_32BIT) ? \
-	 TASK_SIZE : 0x04000000)
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-nexuspci/memory.h linux/include/asm-arm/arch-nexuspci/memory.h
--- v2.3.22/linux/include/asm-arm/arch-nexuspci/memory.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-nexuspci/memory.h	Wed Oct 20 16:29:08 1999
@@ -12,6 +12,7 @@
  * Task size: 3GB
  */
 #define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
 
 /*
  * Page offset: 3GB
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-nexuspci/param.h linux/include/asm-arm/arch-nexuspci/param.h
--- v2.3.22/linux/include/asm-arm/arch-nexuspci/param.h	Sun Sep  6 10:45:30 1998
+++ linux/include/asm-arm/arch-nexuspci/param.h	Wed Oct 20 16:29:08 1999
@@ -1,8 +1,3 @@
 /*
  * linux/include/asm-arm/arch-nexuspci/param.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1998 Philip Blundell
  */
-
-#define HZ 100
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-nexuspci/processor.h linux/include/asm-arm/arch-nexuspci/processor.h
--- v2.3.22/linux/include/asm-arm/arch-nexuspci/processor.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-nexuspci/processor.h	Wed Oct 20 16:29:08 1999
@@ -11,8 +11,6 @@
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
-#include <asm/arch/memory.h>
-
 /*
  * Bus types
  */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-nexuspci/shmparam.h linux/include/asm-arm/arch-nexuspci/shmparam.h
--- v2.3.22/linux/include/asm-arm/arch-nexuspci/shmparam.h	Fri May  8 00:42:40 1998
+++ linux/include/asm-arm/arch-nexuspci/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h
--- v2.3.22/linux/include/asm-arm/arch-nexuspci/system.h	Thu Jan  7 15:51:33 1999
+++ linux/include/asm-arm/arch-nexuspci/system.h	Wed Oct 20 16:29:08 1999
@@ -1,17 +1,12 @@
 /*
  * linux/include/asm-arm/arch-nexuspci/system.h
  *
- * Copyright (c) 1996,1997,1998 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
  */
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-extern __inline__ void arch_reset(char mode)
-{
-	/*
-	 * loop endlessly - the watchdog will reset us if it's enabled.
-	 */
-	cli();
-}
+#define arch_do_idle()		do { } while (0)
+#define arch_reset(mode)	do { } while (0)
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/a.out.h linux/include/asm-arm/arch-rpc/a.out.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/a.out.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-rpc/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/a.out.h
- *
- * Copyright (C) 1996-1999 Russell King
- */
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#include <asm/arch/memory.h>
-
-#define STACK_TOP \
-	((current->personality == PER_LINUX_32BIT) ? \
-	 TASK_SIZE : 0x04000000)
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/acornfb.h linux/include/asm-arm/arch-rpc/acornfb.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/acornfb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/acornfb.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,99 @@
+/*
+ * linux/include/asm-arm/arch-rpc/acornfb.h
+ *
+ * (C) 1999 Russell King
+ *
+ * AcornFB architecture specific code
+ */
+
+#define acornfb_valid_pixrate(rate) (1)
+
+/*
+ * Try to find the best PLL parameters for the pixel clock.
+ * This algorithm seems to give best predictable results,
+ * and produces the same values as detailed in the VIDC20
+ * data sheet.
+ */
+static inline u_int
+acornfb_vidc20_find_pll(u_int pixclk)
+{
+	u_int r, best_r = 2, best_v = 2;
+	int best_d = 0x7fffffff;
+
+	for (r = 2; r <= 32; r++) {
+		u_int rr, v, p;
+		int d;
+
+		rr = 41667 * r;
+
+		v = (rr + pixclk / 2) / pixclk;
+
+		if (v > 32 || v < 2)
+			continue;
+
+		p = (rr + v / 2) / v;
+
+		d = pixclk - p;
+
+		if (d < 0)
+			d = -d;
+
+		if (d < best_d) {
+			best_d = d;
+			best_v = v - 1;
+			best_r = r - 1;
+		}
+
+		if (d == 0)
+			break;
+	}
+
+	return best_v << 8 | best_r;
+}
+
+static inline void
+acornfb_vidc20_find_rates(struct vidc_timing *vidc,
+			  struct fb_var_screeninfo *var)
+{
+	u_int div, bandwidth;
+
+	/* Select pixel-clock divisor to keep PLL in range */
+	div = var->pixclock / 9090; /*9921*/
+
+	/* Limit divisor */
+	if (div == 0)
+		div = 1;
+	if (div > 8)
+		div = 8;
+
+	/* Encode divisor to VIDC20 setting */
+	switch (div) {
+	case 1:	vidc->control |= VIDC20_CTRL_PIX_CK;  break;
+	case 2:	vidc->control |= VIDC20_CTRL_PIX_CK2; break;
+	case 3:	vidc->control |= VIDC20_CTRL_PIX_CK3; break;
+	case 4:	vidc->control |= VIDC20_CTRL_PIX_CK4; break;
+	case 5:	vidc->control |= VIDC20_CTRL_PIX_CK5; break;
+	case 6:	vidc->control |= VIDC20_CTRL_PIX_CK6; break;
+	case 7:	vidc->control |= VIDC20_CTRL_PIX_CK7; break;
+	case 8: vidc->control |= VIDC20_CTRL_PIX_CK8; break;
+	}
+
+	/* Calculate bandwidth */
+	bandwidth = var->pixclock * 8 / var->bits_per_pixel;
+
+	/* Encode bandwidth as VIDC20 setting */
+	if (bandwidth > 33334)
+		vidc->control |= VIDC20_CTRL_FIFO_16;	/* < 30.0MB/s */
+	else if (bandwidth > 26666)
+		vidc->control |= VIDC20_CTRL_FIFO_20;	/* < 37.5MB/s */
+	else if (bandwidth > 22222)
+		vidc->control |= VIDC20_CTRL_FIFO_24;	/* < 45.0MB/s */
+	else
+		vidc->control |= VIDC20_CTRL_FIFO_28;	/* > 45.0MB/s */
+
+	/* Find the PLL values */
+	vidc->pll_ctl  = acornfb_vidc20_find_pll(var->pixclock / div);
+}
+
+#define acornfb_default_control()	(VIDC20_CTRL_PIX_VCLK)
+#define acornfb_default_econtrol()	(VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3))
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/hardware.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-rpc/hardware.h	Wed Oct 20 16:29:08 1999
@@ -41,7 +41,7 @@
 #define FLUSH_BASE		0xdf000000
 
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 /*
  * for use with inb/outb
@@ -93,5 +93,17 @@
 #define PCIO_BASE		0xe0010000
 
 #endif
+
+#ifdef HAS_EXPMASK
+#ifndef __ASSEMBLY__
+#define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
+#else
+#define __EXPMASK(offset)	offset
+#endif
+
+#define	EXPMASK_STATUS	__EXPMASK(0x00)
+#define EXPMASK_ENABLE	__EXPMASK(0x04)
+
 #endif
 
+#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/irq.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-rpc/irq.h	Wed Oct 20 16:29:08 1999
@@ -174,4 +174,6 @@
 			break;
 		}
 	}
+
+	init_FIQ();
 }
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/memory.h linux/include/asm-arm/arch-rpc/memory.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/memory.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-rpc/memory.h	Wed Oct 20 16:29:08 1999
@@ -18,16 +18,17 @@
  * Task size: 3GB
  */
 #define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
 
 /*
  * Page offset: 3GB
  */
 #define PAGE_OFFSET	(0xc0000000UL)
 
-#ifndef __ASSEMBLY__
-extern unsigned long __virt_to_phys(unsigned long vpage);
-extern unsigned long __phys_to_virt(unsigned long ppage);
-#endif
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x10000000)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x10000000)
 
 /*
  * These are exactly the same on the RiscPC as the
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/mm-init.h linux/include/asm-arm/arch-rpc/mm-init.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/mm-init.h	Sun Apr 12 11:42:16 1998
+++ linux/include/asm-arm/arch-rpc/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmap.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define HAVE_MAP_VID_MEM
-
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-	static int updated = 0;
-	unsigned long address;
-	pgd_t *pgd;
-
-	if (updated)
-		return 0;
-	updated = update;
-
-	address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-	pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
-	pgd_val(pgd[0]) = address;
-	pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
-
-	if (update) {
-		unsigned long pgtable = PAGE_ALIGN(kmem), *p;
-		int i;
-
-		memzero ((void *)pgtable, 4096);
-		
-		pgd_val(pgd[-2]) = __virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-		pgd_val(pgd[-1]) = __virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-		p = (unsigned long *)pgtable;
-
-		i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
-		address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
-
-		while (i < PTRS_PER_PTE * 2) {
-			p[i++] = address;
-			address += PAGE_SIZE;
-		}
-
-		flush_page_to_ram(pgtable);
-
-		kmem = pgtable + PAGE_SIZE;
-	}
-	return kmem;
-}
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/param.h linux/include/asm-arm/arch-rpc/param.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/param.h	Sun Sep  6 10:45:30 1998
+++ linux/include/asm-arm/arch-rpc/param.h	Wed Oct 20 16:29:08 1999
@@ -1,8 +1,3 @@
 /*
  * linux/include/asm-arm/arch-rpc/param.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1998 Philip Blundell
  */
-
-#define HZ 100
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/processor.h linux/include/asm-arm/arch-rpc/processor.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/processor.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-rpc/processor.h	Wed Oct 20 16:29:08 1999
@@ -11,8 +11,6 @@
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
-#include <asm/arch/memory.h>
-
 /*
  * Bus types
  */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/shmparam.h linux/include/asm-arm/arch-rpc/shmparam.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/shmparam.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.3.22/linux/include/asm-arm/arch-rpc/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/arch-rpc/system.h	Wed Oct 20 16:29:08 1999
@@ -1,23 +1,24 @@
 /*
  * linux/include/asm-arm/arch-rpc/system.h
  *
- * Copyright (c) 1996 Russell King
+ * Copyright (c) 1996-1999 Russell King.
  */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
+#include <asm/arch/hardware.h>
 #include <asm/iomd.h>
+#include <asm/io.h>
+
+#define arch_do_idle() cpu_do_idle()
+
+extern __inline__ void arch_reset(char mode)
+{
+	extern void ecard_reset(int card);
+
+	ecard_reset(-1);
 
-#define arch_reset(mode) {						\
-	extern void ecard_reset (int card);				\
-	outb (0, IOMD_ROMCR0);						\
-	ecard_reset(-1);						\
-	cli();								\
-	__asm__ __volatile__("msr  spsr, r1;"				\
-			     "mcr  p15, 0, %0, c1, c0, 0;"		\
-			     "movs pc, #0"				\
-			 : 						\
-			 : "r" (cpu_reset()));				\
-	}
+	outb(0, IOMD_ROMCR0);
 
-#endif
+	__asm__ __volatile__(
+		"mcr  p15, 0, %0, c1, c0, 0\n\t"
+		"movs pc, #0"
+		 : : "r" (cpu_reset()));
+}
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/dma.h linux/include/asm-arm/arch-sa1100/dma.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/dma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/dma.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,9 @@
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+#define MAX_DMA_ADDRESS		0xffffffff
+
+/* No DMA (strictly, a lie :-) ) */
+#define MAX_DMA_CHANNELS	0
+
+#endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/hardware.h linux/include/asm-arm/arch-sa1100/hardware.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/hardware.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,25 @@
+/*
+ * linux/include/asm-arm/arch-brutus/hardware.h
+ *
+ * Copyright (C) 1998 Nicolas Pitre <nico@visuaide.com>
+ *
+ * This file contains the hardware definitions for SA1100 architecture
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/* Flushing areas */
+#define FLUSH_BASE_PHYS		0xe0000000	/* SA1100 zero bank */
+#define FLUSH_BASE		0xdf000000
+#define FLUSH_BASE_MINICACHE	0xde000000
+
+/*
+ * PCMCIA IO is mapped to 0xe0000000.  We are likely to use in*()/out*()
+ * IO macros for what might appear there...
+ * The SA1100 PCMCIA interface can be seen like a PC ISA bus for IO.
+ */
+#define PCIO_BASE		0xe0000000	/* PCMCIA0 IO space */
+
+#endif
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/io.h linux/include/asm-arm/arch-sa1100/io.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/io.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,46 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/io.h
+ *
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * Modifications:
+ *  06-12-1997	RMK	Created.
+ *  07-04-1999	RMK	Major cleanup
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/*
+ * This architecture does not require any delayed IO
+ */
+#undef	ARCH_IO_DELAY
+
+#define __pci_io_addr(x)	(PCIO_BASE + (unsigned int)(x))
+
+#define __inb(p)		(*(volatile unsigned char *)__pci_io_addr(p))
+#define __inl(p)		(*(volatile unsigned long *)__pci_io_addr(p))
+
+extern __inline__ unsigned int __inw(unsigned int port)
+{
+	unsigned int value;
+	__asm__ __volatile__(
+	"ldr%?h	%0, [%1, %2]	@ inw"
+	: "=&r" (value)
+	: "r" (PCIO_BASE), "r" (port));
+	return value;
+}
+
+
+#define __outb(v,p)		(*(volatile unsigned char *)__pci_io_addr(p) = (v))
+#define __outl(v,p)		(*(volatile unsigned long *)__pci_io_addr(p) = (v))
+
+extern __inline__ void __outw(unsigned int value, unsigned int port)
+{
+	__asm__ __volatile__(
+	"str%?h	%0, [%1, %2]	@ outw"
+	: : "r" (value), "r" (PCIO_BASE), "r" (port));
+}
+
+#define __ioaddr(p)	__pci_io_addr(p)
+
+#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/irq.h linux/include/asm-arm/arch-sa1100/irq.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/irq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/irq.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,183 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/irq.h
+ *
+ * Copyright (C) 1996-1999 Russell king
+ * Copyright (C) 1999 Hugo Fiennes
+ *
+ * Changelog:
+ *   22-08-1998	RMK	Restructured IRQ routines
+ *   06-01-1999	HBF	SA1100 twiddles
+ *   12-02-1999	NP	added ICCR
+ *   17-02-1999	NP	empeg henry ugly hacks now in a separate file ;)
+ *   11-08-1999	PD	SA1101 support added
+ *   25-09-1999	RMK	Merged into main ARM tree, cleaned up
+ */
+static inline unsigned int fixup_irq(unsigned int irq)
+{
+#ifdef CONFIG_SA1101
+	if (irq == SA1101_IRQ) {
+		unsigned long mask;
+		mask = INTSTATCLR0 & INTENABLE0;
+		irq  = 32;
+		if (!mask) {
+			mask = IRQSTATCLR1 & INTENABLE1;
+			irq  = 64;
+		}
+		if (mask)
+			while ((mask & 1) == 0) {
+				mask >>= 1;
+				irq += 1;
+			}
+	}
+#endif
+	return irq;
+}
+
+/* We don't need to ACK IRQs on the SA1100 unless they're <= 10,
+ * ie, an edge-detect.
+ */
+static void sa1100_mask_and_ack_irq(unsigned int irq)
+{
+	ICMR &= ~(1 << irq);
+	if (irq <= 10)
+		GEDR = 1 << irq;
+}
+
+static void sa1100_mask_irq(unsigned int irq)
+{
+	ICMR &= ~(1 << irq);
+}
+
+static void sa1100_unmask_irq(unsigned int irq)
+{
+	ICMR |= 1 << irq;
+}
+
+#ifdef CONFIG_SA1101
+
+static void sa1101_mask_and_ack_lowirq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 31);
+
+	INTENABLE0 &= ~mask;
+	GEDR = 1 << SA1101_IRQ;
+	INTSTATCLR0 = mask;
+}
+
+static void sa1101_mask_and_ack_highirq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 31);
+
+	INTENABLE1 &= ~mask;
+	GEDR = 1 << SA1101_IRQ;
+	INTSTATCLR1 = mask;
+}
+
+static void sa1101_mask_lowirq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 31);
+
+	INTENABLE0 &= ~mask;
+}
+
+static void sa1101_mask_highirq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 31);
+
+	INTENABLE1 &= ~mask;
+}
+
+/*
+ * unmasking an IRq with the wrong polarity can be
+ * fatal, but there is no need to check this in the
+ * interrupt code - it will be spotted anyway ;-)
+ */
+static void sa1101_unmask_lowirq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 31);
+
+	INTENABLE0 |= mask;
+	ICMR |= 1 << SA1101_IRQ;
+}
+
+static void sa1101_unmask_highirq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 31);
+
+	INTENABLE1 |= mask;
+	ICMR |= 1 << SA1101_IRQ;
+}
+#endif
+
+static __inline__ void irq_init_irq(void)
+{
+	int irq;
+
+	/* disable all IRQs */
+	ICMR = 0;
+
+	/* all IRQs are IRQ, not FIQ */
+	ICLR = 0;
+
+	/* clear all GPIO edge detects */
+	GEDR = -1;
+
+#ifdef CONFIG_SA1101
+	/* turn on interrupt controller */
+	SKPCR |= 4;
+
+	/* disable all IRQs */
+	INTENABLE0 = 0;
+	INTENABLE1 = 0;
+
+	/* detect on rising edge */
+	INTPOL0 = 0;
+	INTPOL1 = 0;
+
+	/* clear all IRQs */
+	INTSTATCLR0 = -1;
+	INTSTATCLR1 = -1;
+
+	/* SA1101 generates a rising edge */
+	GRER |= 1 << SA1101_IRQ;
+	GPER &= ~(1 << SA1101_IRQ);
+#endif
+
+	/*
+	 * Whatever the doc says, this has to be set for the wait-on-irq
+	 * instruction to work... on a SA1100 rev 9 at least.
+	 */
+	ICCR = 1;
+
+#ifndef CONFIG_SA1101
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= sa1100_mask_and_ack_irq;
+		irq_desc[irq].mask	= sa1100_mask_irq;
+		irq_desc[irq].unmask	= sa1100_unmask_irq;
+	}
+#else
+	for (irq = 0; irq < 31; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= sa1100_mask_and_ack_irq;
+		irq_desc[irq].mask	= sa1100_mask_irq;
+		irq_desc[irq].unmask	= sa1100_unmask_irq;
+	}
+	for (irq = 32; irq < 63; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= sa1101_mask_and_ack_lowirq;
+		irq_desc[irq].mask	= sa1101_mask_lowirq;
+		irq_desc[irq].unmask	= sa1101_unmask_lowirq;
+	}
+	for (irq = 64; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= sa1101_mask_and_ack_highirq;
+		irq_desc[irq].mask	= sa1101_mask_highirq;
+		irq_desc[irq].unmask	= sa1101_unmask_highirq;
+	}
+#endif
+}
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/irqs.h linux/include/asm-arm/arch-sa1100/irqs.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/irqs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/irqs.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,111 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/irqs.h
+ *
+ * Copyright (C) 1996 Russell King
+ * Copyright (C) 1998 Deborah Wallach (updates for SA1100/Brutus).
+ */
+
+#ifdef CONFIG_SA1101
+#define NR_IRQS                 95
+
+#define GPAIN0          32
+#define GPAIN1		33
+#define GPAIN2		34
+#define GPAIN3		35
+#define GPAIN4		36
+#define GPAIN5		37
+#define GPAIN6		38
+#define GPAIN7		39
+#define GPBIN0		40
+#define GPBIN1		41
+#define GPBIN2		42
+#define GPBIN3		43
+#define GPBIN4		44
+#define GPBIN5		45
+#define GPBIN6		46
+#define RESERVED	47
+#define KPXIN0		48
+#define KPXIN1		49
+#define KPXIN2		50
+#define KPXIN3		51
+#define KPXIN4		52
+#define KPXIN5		53
+#define KPXIN6		54
+#define KPXIN7		55
+#define KPYIN0		56
+#define KPYIN1		57
+#define KPYIN2		58
+#define KPYIN3		59
+#define KPYIN4		60
+#define KPYIN5		61
+#define KPYIN6		62
+#define KPYIN7		63
+#define KPYIN8		64
+#define KPYIN9		65
+#define KPYIN10		66
+#define KPYIN11		67
+#define KPYIN12		68
+#define KPYIN13		69
+#define KPYIN14		70
+#define KPYIN15		71
+#define MSTXINT		72
+#define MSRXINT		73
+#define TPTXINT		74
+#define TPRXINT		75
+#define INTREQTRC	76
+#define INTREQTIM	77
+#define INTREQRAV	78
+#define INTREQINT	79
+#define INTREQEMP	80
+#define INTREQDAT	81
+#define VIDEOINT	82
+#define FIFOINT		83
+#define NIRQHCIM	84
+#define IRQHCIBUFFACC	85
+#define IRQHCIRMTWKP	86
+#define NHCIMFCLIR	87
+#define USBERROR	88
+#define S0_READY_NIREQ	89
+#define S1_READY_NIREQ	90
+#define S0_CDVALID	91
+#define S1_CDVALID	92
+#define S0_BVD1_STSCHG	93
+#define S1_BVD1_STSCHG	94
+#define USB_PORT_RESUME	95
+
+#else
+#define NR_IRQS                 32
+#endif
+
+#define	IRQ_GPIO0		0
+#define	IRQ_GPIO1		1
+#define	IRQ_GPIO2		2
+#define	IRQ_GPIO3		3
+#define	IRQ_GPIO4		4
+#define	IRQ_GPIO5		5
+#define	IRQ_GPIO6		6
+#define	IRQ_GPIO7		7
+#define	IRQ_GPIO8		8
+#define	IRQ_GPIO9		9
+#define	IRQ_GPIO10		10
+#define	IRQ_GPIO11_27		11
+#define	IRQ_LCD  		12	/* LCD controller                  */
+#define IRQ_Ser0UDC		13	/* Ser. port 0 UDC                 */
+#define IRQ_Ser1SDLC		14	/* Ser. port 1 SDLC                */
+#define IRQ_Ser1UART		15	/* Ser. port 1 UART                */
+#define IRQ_Ser2ICP		16	/* Ser. port 2 ICP                 */
+#define IRQ_Ser3UART		17	/* Ser. port 3 UART                */
+#define IRQ_Ser4MCP		18	/* Ser. port 4 MCP                 */
+#define IRQ_Ser4SSP		19	/* Ser. port 4 SSP                 */
+#define IRQ_DMA0 		20	/* DMA controller channel 0        */
+#define IRQ_DMA1 		21	/* DMA controller channel 1        */
+#define IRQ_DMA2 		22	/* DMA controller channel 2        */
+#define IRQ_DMA3 		23	/* DMA controller channel 3        */
+#define IRQ_DMA4 		24	/* DMA controller channel 4        */
+#define IRQ_DMA5 		25	/* DMA controller channel 5        */
+#define IRQ_OST0 		26	/* OS Timer match 0                */
+#define IRQ_OST1 		27	/* OS Timer match 1                */
+#define IRQ_OST2 		28	/* OS Timer match 2                */
+#define IRQ_OST3 		29	/* OS Timer match 3                */
+#define IRQ_RTC1Hz		30	/* RTC 1 Hz clock                  */
+#define IRQ_RTCAlrm		31	/* RTC Alarm                       */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/keyboard.h linux/include/asm-arm/arch-sa1100/keyboard.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/keyboard.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,27 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/keyboard.h
+ *
+ * Keyboard driver definitions for SA1100 architecture
+ *
+ * This really has to be cleaned up somehow...
+ * 
+ */
+
+#define KEYBOARD_IRQ 
+
+#define NR_SCANCODES 128
+
+#define kbd_setkeycode(sc,kc)  (-EINVAL)
+#define kbd_getkeycode(sc)     (-EINVAL)
+#define kbd_pretranslate(sc,kc)       1
+#define kbd_translate(sc, kcp, raw)   kbd_drv_translate(sc, kcp, raw)
+#define kbd_init_hw()	kbd_drv_init()
+#define kbd_unexpected_up		
+
+#define kbd_leds(leds)	
+
+#define kbd_sysrq_xlate			
+#define kbd_disable_irq()
+#define kbd_enable_irq()
+
+#define SYSRQ_KEY	0x54
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/memory.h linux/include/asm-arm/arch-sa1100/memory.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/memory.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,46 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/memory.h
+ *
+ * Copyright (c) 1999 Nicolas Pitre <nico@visuaide.com>
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	 (0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	 (0xc0000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __phys_to_virt__is_a_macro
+
+/*
+ * The following gives a maximum memory size of 128MB (32MB in each bank).
+ *
+ * Does this still need to be optimised for one bank machines?
+ */
+#define __virt_to_phys(x)	(((x) & 0xe0ffffff) | ((x) & 0x06000000) << 2)
+#define __phys_to_virt(x)	(((x) & 0xe7ffffff) | ((x) & 0x30000000) >> 2)
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *		 address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *		 to an address that the kernel can use.
+ *
+ * On the SA1100, bus addresses are equivalent to physical addresses.
+ */
+#define __virt_to_bus__is_a_macro
+#define __bus_to_virt__is_a_macro
+#define __virt_to_bus(x)	 __virt_to_phys(x)
+#define __bus_to_virt(x)	 __phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/param.h linux/include/asm-arm/arch-sa1100/param.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/param.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,3 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/param.h
+ */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/processor.h linux/include/asm-arm/arch-sa1100/processor.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/processor.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/processor.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,28 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/processor.h
+ *
+ * Copyright (c) 1996 Russell King.
+ *
+ * Changelog:
+ *  10-09-1996	RMK	Created
+ *  05-01-1999  HBF     Mods for SA1100
+ *  21-09-1999  NP	SWAPPER_PG_DIR readjusted for SA1100
+ */
+
+#ifndef __ASM_ARCH_PROCESSOR_H
+#define __ASM_ARCH_PROCESSOR_H
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/serial.h linux/include/asm-arm/arch-sa1100/serial.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/serial.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/serial.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,30 @@
+/*
+ * include/asm-arm/arch-sa1100/serial.h
+ * (C) 1999 Nicolas Pitre <nico@visuaide.com>
+ *
+ * All this is intended to be used with a 16550-like UART on the SA1100's 
+ * PCMCIA bus.  It has nothing to do with the SA1100's internal serial ports.
+ * This is included by serial.c -- serial_sa1100.c makes no use of it.
+ */
+
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * 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 */
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, IRQ_GPIO3, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, IRQ_GPIO3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, IRQ_GPIO3, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, IRQ_GPIO3, STD_COM4_FLAGS },	/* ttyS3 */
+
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/serial_reg.h linux/include/asm-arm/arch-sa1100/serial_reg.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/serial_reg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/serial_reg.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,79 @@
+/*
+ * include/asm/arch/serial_reg.h
+ *
+ * Redistribution of this file is permitted under the terms of the GNU 
+ * Public License (GPL)
+ * 
+ * These are the SA1100 UART port assignments, expressed as long index 
+ * of the base address.
+ */
+
+#ifndef ASM_ARCH_SERIAL_REG_H
+#define ASM_ARCH_SERIAL_REG_H
+
+
+/*
+ * Register index.
+ */
+#define UTCR0 		0	/* 0x00 UART_LCR  Line control register */
+#define UTCR1 		1	/* 0x04 UART_DLLSB */
+#define UTCR2 		2	/* 0x08 UART_DLMSB */
+#define UTCR3 		3	/* 0x0c UART_IER */
+#define UTDR 		5	/* 0x14 UART_RX, UART_TX */
+#define UTSR0 		7	/* 0x1c */
+#define UTSR1 		8	/* 0x20 UART_LSR  Line Status register */
+
+#define UART_RX 	UTDR		/* Receive port, read only */
+#define UART_TX 	UTDR		/* transmit port, write only */
+
+#if 0
+/*
+ * Line control register flags
+ */
+#define UTCR0_PE 	1		/* Parity enable */
+#define UTCR0_EP 	2		/* Even parity */
+#define UTCR0_SB 	4		/* Stop bit */
+#define UTCR0_DB 	8		/* Data bits in transmission (0 = 7, 1 = 8) */
+
+#define UTCR0_OES	UTCR0_EP
+#define UTCR0_SBS	UTCR0_SB
+#define UTCR0_DSS	UTCR0_DB
+#define UTCR0_SCE	16		/* Sample clock enable */
+#define UTCR0_RCE	32		/* Receive clock edge select */
+#define UTCR0_TCE	64		/* Transmit clock edge select */
+
+
+/*
+ * Line status bits.
+ */
+#define UTSR1_TBY 	1		/* transmitter busy flag */
+#define UTSR1_RNE 	2		/* receiver not empty (LSR_DR) */
+#define UTSR1_TNF 	4		/* transmit fifo non full */
+#define UTSR1_PRE 	8		/* parity read error (LSR_PE) */
+#define UTSR1_FRE 	16		/* framing error (LSR_FE) */
+#define UTSR1_ROR 	32		/* receive fifo overrun (LSR_OE) */
+
+#define UTSR1_ERROR 	(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)  /* LSR_ERROR */
+
+
+#define UTSR0_TFS 	1		/* transmit fifo service request */
+#define UTSR0_RFS 	2		/* receive fifo service request */
+#define UTSR0_RID	4		/* receiver idle */
+#define UTSR0_RBB 	8		/* receiver begin of break */
+#define UTSR0_REB 	16		/* receiver end of break */
+#define UTSR0_EIF 	32		/* error in fifo */
+
+
+/*
+ * Interrupt enable register (IER)
+ */
+#define UTCR3_RXE 	1		/* Receiver enable */
+#define UTCR3_TXE 	2		/* Transmit enable */
+#define UTCR3_BRK 	4		/* Break */
+#define UTCR3_RIM 	8		/* Receive FIFO interrupt mask (IER_RDA) */
+#define UTCR3_TIM 	16		/* Transmit FIFO interrupt mask (IER_THRE) */
+#define UTCR3_LBM 	32		/* Loop Back Mode */
+
+#endif 
+
+#endif /* ASM_ARCH_SERIAL_REG_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/system.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/system.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/system.h
+ *
+ * Copyright (c) 1999 Nicolas Pitre <nico@visuaide.com>
+ */
+#ifdef CONFIG_SA1100_VICTOR
+
+#define arch_reset( x ) {					\
+	/* switch off power supply */				\
+	mdelay(2000); 						\
+	GPCR = GPIO_GPIO23;					\
+	while(1);						\
+	}
+
+#else
+
+#define arch_reset( x ) {					\
+	__asm__ volatile (					\
+"	mcr	p15, 0, %0, c1, c0	@ MMU off\n"		\
+"	mov	pc, #0\n" : : "r" (cpu_reset()));		\
+	}
+
+#endif
+
+
+/* Enter SA1100 idle mode (see data sheet sec 9.5).
+ * It seems that the wait-on-interrupt just hang the CPU forever if it's
+ * on the end of a cache line.  Workaround: we force an explicit alignment
+ * before it.
+ */
+#define arch_do_idle() \
+	do { \
+	__asm__ __volatile__( \
+"	mcr	p15, 0, %0, c15, c2, 2	@ Disable clock switching \n" \
+"	ldr	%0, [%0]		@ Must perform a non-cached access \n" \
+"	b	1f			@ Seems we must align the next \n" \
+"	.align 5			@ instruction on a cache line \n" \
+"1:	mcr	p15, 0, %0, c15, c8, 2	@ Wait for interrupts \n" \
+"	mcr	p15, 0, %0, c15, c1, 2	@ Reenable clock switching \n" \
+	: : "r" (&ICIP) : "cc" ); \
+	} while (0)
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/arch-sa1100/timex.h linux/include/asm-arm/arch-sa1100/timex.h
--- v2.3.22/linux/include/asm-arm/arch-sa1100/timex.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-sa1100/timex.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,13 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/timex.h
+ *
+ * SA1100 architecture timex specifications
+ *
+ * Copyright (C) 1998 
+ */
+
+/*
+ * SA1100 timer
+ */
+#define CLOCK_TICK_RATE		3686400
+#define CLOCK_TICK_FACTOR	80
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/assembler.h linux/include/asm-arm/assembler.h
--- v2.3.22/linux/include/asm-arm/assembler.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/assembler.h	Wed Oct 20 16:29:08 1999
@@ -7,28 +7,5 @@
  * Do not include any C declarations in this file - it is included by
  * assembler source.
  */
-
-/*
- * LOADREGS: multiple register load (ldm) with pc in register list
- *		(takes account of ARM6 not using ^)
- *
- * RETINSTR: return instruction: adds the 's' in at the end of the
- *		instruction if this is not an ARM6
- *
- * SAVEIRQS: save IRQ state (not required on ARM2/ARM3 - done
- *		implicitly
- *
- * RESTOREIRQS: restore IRQ state (not required on ARM2/ARM3 - done
- *		implicitly with ldm ... ^ or movs.
- *
- * These next two need thinking about - can't easily use stack... (see system.S)
- * DISABLEIRQS: disable IRQS in SVC mode
- *
- * ENABLEIRQS: enable IRQS in SVC mode
- *
- * USERMODE: switch to USER mode
- *
- * SVCMODE: switch to SVC mode
- */
-
+#include <asm/proc/ptrace.h>
 #include <asm/proc/assembler.h>
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/atomic.h linux/include/asm-arm/atomic.h
--- v2.3.22/linux/include/asm-arm/atomic.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/atomic.h	Wed Oct 20 16:29:08 1999
@@ -27,7 +27,7 @@
 #define ATOMIC_INIT(i)	{ (i) }
 
 #ifdef __KERNEL__
-#include <asm/system.h>
+#include <asm/proc/system.h>
 
 #define atomic_read(v)	((v)->counter)
 #define atomic_set(v,i)	(((v)->counter) = (i))
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/cache.h linux/include/asm-arm/cache.h
--- v2.3.22/linux/include/asm-arm/cache.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/cache.h	Wed Oct 20 16:29:08 1999
@@ -1,5 +1,5 @@
 /*
- * include/asm-i386/cache.h
+ * linux/include/asm-arm/cache.h
  */
 #ifndef __ASMARM_CACHE_H
 #define __ASMARM_CACHE_H
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/checksum.h linux/include/asm-arm/checksum.h
--- v2.3.22/linux/include/asm-arm/checksum.h	Fri May  8 00:42:40 1998
+++ linux/include/asm-arm/checksum.h	Thu Oct 21 12:15:36 1999
@@ -9,10 +9,6 @@
 #ifndef __ASM_ARM_CHECKSUM_H
 #define __ASM_ARM_CHECKSUM_H
 
-#ifndef __ASM_ARM_SEGMENT_H
-#include <asm/segment.h>
-#endif
-
 /*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
@@ -64,17 +60,14 @@
  *	which always checksum on 4 octet boundaries.
  *
  *	Converted and optimised for ARM by R. M. King.
- *
- *	Note: the order that the LDM registers are loaded with respect to
- *	the adc's doesn't matter.
  */
 static inline unsigned short
 ip_fast_csum(unsigned char * iph, unsigned int ihl)
 {
 	unsigned int sum, tmp1;
 
-    __asm__ __volatile__("
-	sub	%2, %2, #5
+    __asm__ __volatile__(
+	"sub	%2, %2, #5		@ ip_fast_csum 
 	ldr	%0, [%1], #4
 	ldr	%3, [%1], #4
 	adds	%0, %0, %3
@@ -94,7 +87,8 @@
 	mov	%0, %0, lsr #16
 	"
 	: "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (tmp1)
-	: "1" (iph), "2" (ihl));
+	: "1" (iph), "2" (ihl)
+	: "cc");
 	return(sum);
 }
 
@@ -104,25 +98,28 @@
 static inline unsigned int
 csum_fold(unsigned int sum)
 {
-	__asm__("
-	adds	%0, %0, %0, lsl #16
+	__asm__(
+	"adds	%0, %1, %1, lsl #16	@ csum_fold
 	addcs	%0, %0, #0x10000"
 	: "=r" (sum)
-	: "0" (sum));
+	: "r" (sum)
+	: "cc");
 	return (~sum) >> 16;
 }
 
-static inline unsigned long
+static inline unsigned int
 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
-		   unsigned short proto, unsigned int sum)
+		   unsigned int proto, unsigned int sum)
 {
-	__asm__("
-	adds	%0, %0, %1
-	adcs	%0, %0, %2
+	__asm__(
+	"adds	%0, %1, %2		@ csum_tcpudp_nofold
 	adcs	%0, %0, %3
+	adcs	%0, %0, %4
+	adcs	%0, %0, %5
 	adc	%0, %0, #0"
 	: "=&r"(sum)
-	: "r" (daddr), "r" (saddr), "r" ((ntohs(len)<<16)+proto*256), "0" (sum));
+	: "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8)
+	: "cc");
 	return sum;
 }	
 /*
@@ -131,7 +128,7 @@
  */
 static inline unsigned short int
 csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
-		  unsigned short proto, unsigned int sum)
+		  unsigned int proto, unsigned int sum)
 {
 	return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 }
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/cpu-multi26.h linux/include/asm-arm/cpu-multi26.h
--- v2.3.22/linux/include/asm-arm/cpu-multi26.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/cpu-multi26.h	Wed Oct 20 16:29:08 1999
@@ -10,40 +10,15 @@
  * relies on it.
  */
 extern struct processor {
-	/* MISC
-	 * get data abort address/flags
-	 */
-	void (*_data_abort)(unsigned long pc);
-	/*
-	 * check for any bugs
-	 */
+	/* check for any bugs */
 	void (*_check_bugs)(void);
-	/*
-	 * Set up any processor specifics
-	 */
+	/* Set up any processor specifics */
 	void (*_proc_init)(void);
-	/*
-	 * Disable any processor specifics
-	 */
+	/* Disable any processor specifics */
 	void (*_proc_fin)(void);
-	/*
-	 * Processor architecture specific
-	 */
-	/* MEMC
-	 *
-	 * remap memc tables
-	 */
-	void (*_remap_memc)(void *tsk);
-	/*
-	 * update task's idea of mmap
-	 */
-	void (*_update_map)(void *tsk);
-	/*
-	 * update task's idea after abort
-	 */
-	void (*_update_mmu_cache)(void *vma, unsigned long addr, pte_t pte);
-	/* XCHG
-	 */
+	/* set the MEMC hardware mappings */
+	void (*_set_pgd)(pgd_t *pgd);
+	/* XCHG */
 	unsigned long (*_xchg_1)(unsigned long x, volatile void *ptr);
 	unsigned long (*_xchg_2)(unsigned long x, volatile void *ptr);
 	unsigned long (*_xchg_4)(unsigned long x, volatile void *ptr);
@@ -53,16 +28,16 @@
 extern const struct processor arm250_processor_functions;
 extern const struct processor arm3_processor_functions;
 
-#define cpu_data_abort(pc)			processor._data_abort(pc)
 #define cpu_check_bugs()			processor._check_bugs()
 #define cpu_proc_init()				processor._proc_init()
 #define cpu_proc_fin()				processor._proc_fin()
-
-#define cpu_remap_memc(tsk)			processor._remap_memc(tsk)
-#define cpu_update_map(tsk)			processor._update_map(tsk)
-#define cpu_update_mmu_cache(vma,addr,pte)	processor._update_mmu_cache(vma,addr,pte)
+#define cpu_do_idle()				do { } while (0)
+#define cpu_switch_mm(pgd,tsk)			processor._set_pgd(pgd)
 #define cpu_xchg_1(x,ptr)			processor._xchg_1(x,ptr)
 #define cpu_xchg_2(x,ptr)			processor._xchg_2(x,ptr)
 #define cpu_xchg_4(x,ptr)			processor._xchg_4(x,ptr)
+
+extern void cpu_memc_update_all(pgd_t *pgd);
+extern void cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long log_addr);
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/cpu-multi32.h linux/include/asm-arm/cpu-multi32.h
--- v2.3.22/linux/include/asm-arm/cpu-multi32.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/cpu-multi32.h	Wed Oct 20 16:29:08 1999
@@ -88,6 +88,14 @@
 	 * purge cached data without (necessarily) writing it back
 	 */
 	void (*_cache_purge_area)(unsigned long start, unsigned long end);
+	/*
+	 * flush a specific TLB
+	 */
+	void (*_flush_tlb_page)(unsigned long address, int flags);
+	/*
+	 * Idle the processor
+	 */
+	int (*_do_idle)(void);
 } processor;
 
 extern const struct processor arm6_processor_functions;
@@ -98,6 +106,7 @@
 #define cpu_check_bugs()			processor._check_bugs()
 #define cpu_proc_init()				processor._proc_init()
 #define cpu_proc_fin()				processor._proc_fin()
+#define cpu_do_idle()				processor._do_idle()
 
 #define cpu_flush_cache_all()			processor._flush_cache_all()
 #define cpu_flush_cache_area(start,end,flags)	processor._flush_cache_area(start,end,flags)
@@ -106,12 +115,15 @@
 #define cpu_flush_ram_page(page)		processor._flush_ram_page(page)
 #define cpu_flush_tlb_all()			processor._flush_tlb_all()
 #define cpu_flush_tlb_area(start,end,flags)	processor._flush_tlb_area(start,end,flags)
-#define cpu_switch_mm(pgd,tsk)			processor._set_pgd(pgd)
+#define cpu_flush_tlb_page(addr,flags)		processor._flush_tlb_page(addr,flags)
+#define cpu_set_pgd(pgd)			processor._set_pgd(pgd)
 #define cpu_set_pmd(pmdp, pmd)			processor._set_pmd(pmdp, pmd)
 #define cpu_set_pte(ptep, pte)			processor._set_pte(ptep, pte)
 #define cpu_reset()				processor.reset()
 #define cpu_flush_icache_area(start,end)	processor._flush_icache_area(start,end)
 #define cpu_cache_wback_area(start,end)		processor._cache_wback_area(start,end)
 #define cpu_cache_purge_area(start,end)		processor._cache_purge_area(start,end)
+
+#define cpu_switch_mm(pgd,tsk)			cpu_set_pgd(__virt_to_phys((unsigned long)(pgd)))
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/cpu-single.h linux/include/asm-arm/cpu-single.h
--- v2.3.22/linux/include/asm-arm/cpu-single.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/cpu-single.h	Wed Oct 20 16:29:08 1999
@@ -1,7 +1,11 @@
 /*
  * Single CPU
  */
+#ifdef __STDC__
 #define __cpu_fn(name,x)	cpu_##name##x
+#else
+#define __cpu_fn(name,x)	cpu_/**/name/**/x
+#endif
 #define cpu_fn(name,x)		__cpu_fn(name,x)
 
 /*
@@ -14,6 +18,7 @@
 #define cpu_check_bugs			cpu_fn(CPU_NAME,_check_bugs)
 #define cpu_proc_init			cpu_fn(CPU_NAME,_proc_init)
 #define cpu_proc_fin			cpu_fn(CPU_NAME,_proc_fin)
+#define cpu_do_idle			cpu_fn(CPU_NAME,_do_idle)
 
 #define cpu_flush_cache_all		cpu_fn(CPU_NAME,_flush_cache_all)
 #define cpu_flush_cache_area		cpu_fn(CPU_NAME,_flush_cache_area)
@@ -22,10 +27,11 @@
 #define cpu_flush_ram_page		cpu_fn(CPU_NAME,_flush_ram_page)
 #define cpu_flush_tlb_all		cpu_fn(CPU_NAME,_flush_tlb_all)
 #define cpu_flush_tlb_area		cpu_fn(CPU_NAME,_flush_tlb_area)
-#define cpu_switch_mm			cpu_fn(CPU_NAME,_set_pgd)
+#define cpu_flush_tlb_page		cpu_fn(CPU_NAME,_flush_tlb_page)
+#define cpu_set_pgd			cpu_fn(CPU_NAME,_set_pgd)
 #define cpu_set_pmd			cpu_fn(CPU_NAME,_set_pmd)
 #define cpu_set_pte			cpu_fn(CPU_NAME,_set_pte)
-#define cpu_reset			cpu_fn(CPU_NAME,reset)
+#define cpu_reset			cpu_fn(CPU_NAME,_reset)
 #define cpu_flush_icache_area		cpu_fn(CPU_NAME,_flush_icache_area)
 #define cpu_cache_wback_area		cpu_fn(CPU_NAME,_cache_wback_area)
 #define cpu_cache_purge_area		cpu_fn(CPU_NAME,_cache_purge_area)
@@ -42,6 +48,7 @@
 extern void cpu_check_bugs(void);
 extern void cpu_proc_init(void);
 extern void cpu_proc_fin(void);
+extern int cpu_do_idle(void);
 
 extern void cpu_flush_cache_all(void);
 extern void cpu_flush_cache_area(unsigned long address, unsigned long end, int flags);
@@ -50,12 +57,15 @@
 extern void cpu_flush_ram_page(unsigned long page);
 extern void cpu_flush_tlb_all(void);
 extern void cpu_flush_tlb_area(unsigned long address, unsigned long end, int flags);
-extern void cpu_switch_mm(unsigned long pgd_phys, struct task_struct *tsk);
+extern void cpu_flush_tlb_page(unsigned long address, int flags);
+extern void cpu_set_pgd(unsigned long pgd_phys);
 extern void cpu_set_pmd(pmd_t *pmdp, pmd_t pmd);
 extern void cpu_set_pte(pte_t *ptep, pte_t pte);
 extern unsigned long cpu_reset(void);
 extern void cpu_flush_icache_area(unsigned long start, unsigned long size);
 extern void cpu_cache_wback_area(unsigned long start, unsigned long end);
 extern void cpu_cache_purge_area(unsigned long start, unsigned long end);
+
+#define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd)))
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/current.h linux/include/asm-arm/current.h
--- v2.3.22/linux/include/asm-arm/current.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/current.h	Wed Oct 20 16:29:08 1999
@@ -8,12 +8,19 @@
 	return sp;
 }
 
-//static inline struct task_struct *get_current(void) __attribute__ (( __const__ ));
+/* Old compilers seem to generate bad code if we allow `current' to be
+   non volatile.  */
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 90)
+static inline struct task_struct *get_current(void) __attribute__ (( __const__ ));
+#define __VOLATILE_CURRENT
+#else
+#define __VOLATILE_CURRENT volatile
+#endif
 
 static inline struct task_struct *get_current(void)
 {
 	struct task_struct *ts;
-	__asm__ __volatile__ (
+	__asm__ __VOLATILE_CURRENT (
 	"bic	%0, sp, #0x1f00		@ get_current
 	bic	%0, %0, #0x00ff" 
 	: "=r" (ts));
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/elf.h linux/include/asm-arm/elf.h
--- v2.3.22/linux/include/asm-arm/elf.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/elf.h	Wed Oct 20 16:29:08 1999
@@ -10,8 +10,10 @@
 #include <asm/procinfo.h>
 
 typedef unsigned long elf_greg_t;
+typedef unsigned long elf_freg_t[3];
 
 #define EM_ARM	40
+#define EF_ARM_APCS26 0x08
 
 #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
@@ -27,7 +29,11 @@
  * These are used to set parameters in the core dumps.
  */
 #define ELF_CLASS	ELFCLASS32
+#ifdef __ARMEB__
 #define ELF_DATA	ELFDATA2LSB;
+#else
+#define ELF_DATA	ELFDATA2LSB;
+#endif
 #define ELF_ARCH	EM_ARM
 
 #define USE_ELF_CORE_DUMP
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h
--- v2.3.22/linux/include/asm-arm/hardware.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/hardware.h	Wed Oct 20 16:29:08 1999
@@ -11,16 +11,4 @@
 
 #include <asm/arch/hardware.h>
 
-#ifdef HAS_EXPMASK
-#ifndef __ASSEMBLER__
-#define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
-#else
-#define __EXPMASK(offset)	offset
-#endif
-
-#define	EXPMASK_STATUS	__EXPMASK(0x00)
-#define EXPMASK_ENABLE	__EXPMASK(0x04)
-
-#endif
-
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/init.h linux/include/asm-arm/init.h
--- v2.3.22/linux/include/asm-arm/init.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/init.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-#ifndef _ASMARM_INIT_H
-#define _ASMARM_INIT_H
-
-#include <linux/config.h>
-
-/* C routines */
-
-#ifdef CONFIG_TEXT_SECTIONS
-
-#define __init __attribute__ ((__section__ (".text.init")))
-
-#else
-
-#define __init
-
-#endif
-
-#define __initdata __attribute__ ((__section__ (".data.init")))
-
-/* Assembly routines */
-#define __INIT		.section	".text.init",@alloc,@execinstr
-#define __INITDATA	.section	".data.init",@alloc,@write
-#define __FINIT	.previous
-
-#define __cacheline_aligned __attribute__ \
-			 ((__aligned__ (L1_CACHE_BYTES)))
-
-#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.3.22/linux/include/asm-arm/io.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/io.h	Wed Oct 20 16:29:08 1999
@@ -25,7 +25,7 @@
 
 #endif
 
-#include <asm/hardware.h>
+#include <asm/arch/hardware.h>
 #include <asm/arch/memory.h>
 #include <asm/arch/io.h>
 #include <asm/proc/io.h>
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/ioc.h linux/include/asm-arm/ioc.h
--- v2.3.22/linux/include/asm-arm/ioc.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/ioc.h	Wed Oct 20 16:29:08 1999
@@ -5,7 +5,7 @@
 
 #ifndef IOC_CONTROL
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 #define __IOC(offset)	(IOC_BASE + (offset >> 2))
 #else
 #define __IOC(offset)	offset
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/iomd.h linux/include/asm-arm/iomd.h
--- v2.3.22/linux/include/asm-arm/iomd.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-arm/iomd.h	Wed Oct 20 16:29:08 1999
@@ -1,6 +1,6 @@
 #include <linux/config.h>
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 #define __IOMD(offset)	(IO_IOMD_BASE + (offset >> 2))
 #else
 #define __IOMD(offset)	offset
@@ -215,7 +215,7 @@
 #define VDMA_START	IOMD_VIDSTART
 #define VDMA_END	IOMD_VIDEND
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 extern unsigned int vram_half_sam;
 #define video_set_dma(start,end,offset)				\
 do {								\
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/memc.h linux/include/asm-arm/memc.h
--- v2.3.22/linux/include/asm-arm/memc.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/memc.h	Wed Oct 20 16:29:08 1999
@@ -4,7 +4,7 @@
 #define VDMA_START	1
 #define VDMA_END	2
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 extern void memc_write(unsigned int reg, unsigned long val);
 
 #define video_set_dma(start,end,offset)				\
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/mmu_context.h linux/include/asm-arm/mmu_context.h
--- v2.3.22/linux/include/asm-arm/mmu_context.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/mmu_context.h	Wed Oct 20 16:29:08 1999
@@ -26,7 +26,7 @@
 	  struct task_struct *tsk, unsigned int cpu)
 {
 	if (prev != next) {
-		cpu_switch_mm(__virt_to_phys((unsigned long)next->pgd), tsk);
+		cpu_switch_mm(next->pgd, tsk);
 		clear_bit(cpu, &prev->cpu_vm_mask);
 	}
 	set_bit(cpu, &next->cpu_vm_mask);
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/namei.h linux/include/asm-arm/namei.h
--- v2.3.22/linux/include/asm-arm/namei.h	Mon Nov 16 10:38:09 1998
+++ linux/include/asm-arm/namei.h	Wed Oct 20 16:29:08 1999
@@ -1,18 +1,62 @@
 /* 
  * linux/include/asm-arm/namei.h
  *
+ * Routines to handle famous /usr/gnemul
+ * Derived from the Sparc version of this file
+ *
  * Included from linux/fs/namei.c
  */
 
 #ifndef __ASMARM_NAMEI_H
 #define __ASMARM_NAMEI_H
 
-/* This dummy routine maybe changed to something useful
- * for /usr/gnemul/ emulation stuff.
- * Look at asm-sparc/namei.h for details.
- */
+#define ARM_BSD_EMUL "usr/gnemul/bsd/"
+
+static inline struct dentry *
+__arm_lookup_dentry(const char *name, int lookup_flags)
+{
+	struct dentry *base;
+	char *emul;
+
+	switch (current->personality) {
+	case PER_BSD:
+		emul = ARM_BSD_EMUL; break;
+	default:
+		return NULL;
+	}
+
+	base = lookup_dentry (emul, dget (current->fs->root),
+		      (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
+			
+	if (IS_ERR (base)) return NULL;
+	
+	base = lookup_dentry (name, base, lookup_flags);
+	
+	if (IS_ERR (base)) return NULL;
+	
+	if (!base->d_inode) {
+		struct dentry *fromroot;
+		
+		fromroot = lookup_dentry (name, dget (current->fs->root), 
+					  lookup_flags);
+		
+		if (IS_ERR (fromroot)) return base;
+		
+		if (fromroot->d_inode) {
+			dput(base);
+			return fromroot;
+		}
+		
+		dput(fromroot);
+	}
+	
+	return base;
+}
 
-#define __prefix_lookup_dentry(name, lookup_flags) \
-        do {} while (0)
+#define __prefix_lookup_dentry(name, lookup_flags)			\
+	if (current->personality) {					\
+		dentry = __arm_lookup_dentry (name, lookup_flags);	\
+		if (dentry) return dentry;				\
+	}
 
 #endif /* __ASMARM_NAMEI_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/nwflash.h linux/include/asm-arm/nwflash.h
--- v2.3.22/linux/include/asm-arm/nwflash.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/nwflash.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,9 @@
+#ifndef _FLASH_H
+#define _FLASH_H
+
+#define FLASH_MINOR		 160	/* MAJOR is 10 - miscdevice */
+#define CMD_WRITE_DISABLE	 0
+#define CMD_WRITE_ENABLE	 0x28
+#define CMD_WRITE_BASE64K_ENABLE 0x47
+
+#endif /* _FLASH_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/page.h linux/include/asm-arm/page.h
--- v2.3.22/linux/include/asm-arm/page.h	Mon Jul 19 09:52:57 1999
+++ linux/include/asm-arm/page.h	Wed Oct 20 16:29:08 1999
@@ -1,10 +1,62 @@
 #ifndef _ASMARM_PAGE_H
 #define _ASMARM_PAGE_H
 
-#include <asm/arch/memory.h>
 #include <asm/proc/page.h>
 
+#define PAGE_SIZE       (1UL << PAGE_SHIFT)
+#define PAGE_MASK       (~(PAGE_SIZE-1))
+
 #ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#define STRICT_MM_TYPECHECKS
+
+#define clear_page(page)	memzero((void *)(page), PAGE_SIZE)
+extern void copy_page(unsigned long to, unsigned long from);
+
+#ifdef STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)      ((x).pte)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)      ((x).pgd)
+#define pgprot_val(x)   ((x).pgprot)
+
+#define __pte(x)        ((pte_t) { (x) } )
+#define __pmd(x)        ((pmd_t) { (x) } )
+#define __pgd(x)        ((pgd_t) { (x) } )
+#define __pgprot(x)     ((pgprot_t) { (x) } )
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)      (x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)      (x)
+#define pgprot_val(x)   (x)
+
+#define __pte(x)        (x)
+#define __pmd(x)        (x)
+#define __pgd(x)        (x)
+#define __pgprot(x)     (x)
+
+#endif
+#endif /* !__ASSEMBLY__ */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 #ifndef __ASSEMBLY__
 
@@ -17,19 +69,14 @@
 	BUG(); \
 } while (0)
 
-#endif /* __ASSEMBLY__ */
-
-#define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)	free_page(addr)
-#define clear_page(page)		memzero((void *)(page), PAGE_SIZE)
-#define copy_page(to,from)		memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+#endif /* !__ASSEMBLY__ */
 
-#endif
+#include <asm/arch/memory.h>
 
-/* unsigned long __pa(void *x) */
 #define __pa(x)			__virt_to_phys((unsigned long)(x))
-
-/* void *__va(unsigned long x) */
 #define __va(x)			((void *)(__phys_to_virt((unsigned long)(x))))
+#define MAP_NR(addr)		(((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
+
+#endif
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/param.h linux/include/asm-arm/param.h
--- v2.3.22/linux/include/asm-arm/param.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/param.h	Wed Oct 20 16:29:08 1999
@@ -1 +1,28 @@
-#include <asm/proc/param.h>
+/*
+ * linux/include/asm-arm/param.h
+ *
+ * Copyright (C) 1995-1999 Russell King
+ */
+#ifndef __ASM_PARAM_H
+#define __ASM_PARAM_H
+
+#include <asm/arch/param.h>	/* for HZ */
+#include <asm/proc/page.h>	/* for EXEC_PAGE_SIZE */
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#ifndef NGROUPS
+#define NGROUPS         32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP         (-1)
+#endif
+
+/* max length of hostname */
+#define MAXHOSTNAMELEN  64
+
+#endif
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/parport.h linux/include/asm-arm/parport.h
--- v2.3.22/linux/include/asm-arm/parport.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/parport.h	Wed Oct 20 16:29:08 1999
@@ -1,13 +1,13 @@
 /*
- * parport.h: ia32-specific parport initialisation
+ * parport.h: ARM-specific parport initialisation
  *
  * Copyright (C) 1999  Tim Waugh <tim@cyberelk.demon.co.uk>
  *
  * This file should only be included by drivers/parport/parport_pc.c.
  */
 
-#ifndef _ASM_I386_PARPORT_H
-#define _ASM_I386_PARPORT_H 1
+#ifndef __ASM_ARM_PARPORT_H
+#define __ASM_ARM_PARPORT_H
 
 #include <linux/config.h>
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.3.22/linux/include/asm-arm/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/pci.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,7 @@
+#ifndef ASMARM_PCI_H
+#define ASMARM_PCI_H
+
+#define pcibios_assign_all_busses()	0
+
+#endif
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.3.22/linux/include/asm-arm/pgtable.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/pgtable.h	Wed Oct 20 16:29:08 1999
@@ -1,18 +1,193 @@
 #ifndef _ASMARM_PGTABLE_H
 #define _ASMARM_PGTABLE_H
 
+#include <linux/config.h>
+
+#include <asm/arch/memory.h>		/* For TASK_SIZE */
 #include <asm/proc-fns.h>
+#include <asm/system.h>
+#include <asm/proc/cache.h>
+
+#define LIBRARY_TEXT_START	0x0c000000
+
+#undef TEST_VERIFY_AREA
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+extern unsigned long *empty_zero_page;
+
+#define BAD_PAGETABLE		__bad_pagetable()
+#define BAD_PAGE		__bad_page()
+#define ZERO_PAGE(vaddr)	((unsigned long) empty_zero_page)
+
+/* number of bits that fit into a memory pointer */
+#define BYTES_PER_PTR		(sizeof(unsigned long))
+#define BITS_PER_PTR		(8*BYTES_PER_PTR)
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK		(~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+#define SIZEOF_PTR_LOG2		2
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+	((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+extern void __bad_pmd(pmd_t *pmd);
+extern void __bad_pmd_kernel(pmd_t *pmd);
+
+/*
+ * Page table cache stuff
+ */
+#ifndef CONFIG_NO_PGT_CACHE
+
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
+
+#define pgd_quicklist		(quicklists.pgd_cache)
+#define pmd_quicklist		((unsigned long *)0)
+#define pte_quicklist		(quicklists.pte_cache)
+#define pgtable_cache_size	(quicklists.pgtable_cache_sz)
+
+#else	/* __SMP__ */
+#error Pgtable caches have to be per-CPU, so that no locking is needed.
+#endif	/* __SMP__ */
+
+/* used for quicklists */
+#define __pgd_next(pgd) (((unsigned long *)pgd)[1])
+#define __pte_next(pte)	(((unsigned long *)pte)[0])
+
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)__pgd_next(ret);
+		ret[1] = ret[2];
+		clean_cache_area(ret + 1, 4);
+		pgtable_cache_size--;
+	}
+	return (pgd_t *)ret;
+}
+
+/* We don't use pmd cache, so this is a dummy routine */
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	return (pmd_t *)0;
+}
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+	unsigned long *ret;
+
+	if((ret = pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)__pte_next(ret);
+		ret[0] = ret[1];
+		clean_cache_area(ret, 4);
+		pgtable_cache_size--;
+	}
+	return (pte_t *)ret;
+}
+
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	__pgd_next(pgd) = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+	__pte_next(pte) = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	pgtable_cache_size++;
+}
+
+#else	/* CONFIG_NO_PGT_CACHE */
+
+#define get_pgd_fast()		(NULL)
+#define get_pmd_fast()		(NULL)
+#define get_pte_fast()		(NULL)
+
+#define free_pgd_fast(pgd)	free_pgd_slow(pgd)
+#define free_pmd_fast(pmd)	free_pmd_slow(pmd)
+#define free_pte_fast(pte)	free_pte_slow(pte)
+
+#endif	/* CONFIG_NO_PGT_CACHE */
+
 #include <asm/proc/pgtable.h>
 
-#define module_map	vmalloc
-#define module_unmap	vfree
+extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
+{
+	struct task_struct * p;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+
+#ifndef CONFIG_NO_PGT_CACHE
+	{
+		pgd_t *pgd;
+		for (pgd = (pgd_t *)pgd_quicklist; pgd;
+		     pgd = (pgd_t *)__pgd_next(pgd))
+			pgd[address >> PGDIR_SHIFT] = entry;
+	}
+#endif
+}
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+#define update_mmu_cache(vma,address,pte)
+
+#define SWP_TYPE(entry)		(((entry) >> 2) & 0x7f)
+#define SWP_OFFSET(entry)	((entry) >> 9)
+#define SWP_ENTRY(type,offset)	(((type) << 2) | ((offset) << 9))
+
+#define module_map		vmalloc
+#define module_unmap		vfree
 
 extern int do_check_pgt_cache(int, int);
 
+/*
+ * We rely on GCC optimising this code away for
+ * architectures which it doesn't apply to.  Note
+ * that `addr' is checked against PAGE_OFFSET and
+ * end_mem by the calling code.
+ */
+#define __kern_valid_idx(a)	(((a) - PAGE_OFFSET) >> 20)
+
+extern __inline__ int __kern_valid_addr(unsigned long addr)
+{
+	extern unsigned long *valid_addr_bitmap;
+	unsigned int idx = __kern_valid_idx(addr);
+
+	return test_bit(idx, valid_addr_bitmap);
+}
+
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
-#define PageSkip(page)			(0)
-#define kern_addr_valid(addr)		(1)
+#define PageSkip(page)		(machine_is_riscpc() && test_bit(PG_skip, &(page)->flags))
+#define kern_addr_valid(addr)	(!machine_is_riscpc() || __kern_valid_addr(addr))
 
-#define io_remap_page_range remap_page_range
+#define io_remap_page_range	remap_page_range
 
 #endif /* _ASMARM_PGTABLE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/assembler.h linux/include/asm-arm/proc-armo/assembler.h
--- v2.3.22/linux/include/asm-arm/proc-armo/assembler.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/assembler.h	Wed Oct 20 16:29:08 1999
@@ -6,54 +6,30 @@
  * This file contains arm architecture specific defines
  * for the different processors
  */
+#ifndef __ASSEMBLY__
+#error "Only include this from assembly code"
+#endif
 
-/*
- * LOADREGS: multiple register load (ldm) with pc in register list
- *		(takes account of ARM6 not using ^)
- *
- * RETINSTR: return instruction: adds the 's' in at the end of the
- *		instruction if this is not an ARM6
- *
- * SAVEIRQS: save IRQ state (not required on ARM2/ARM3 - done
- *		implicitly
- *
- * RESTOREIRQS: restore IRQ state (not required on ARM2/ARM3 - done
- *		implicitly with ldm ... ^ or movs.
- *
- * These next two need thinking about - can't easily use stack... (see system.S)
- * DISABLEIRQS: disable IRQS in SVC mode
- *
- * ENABLEIRQS: enable IRQS in SVC mode
- *
- * USERMODE: switch to USER mode
- *
- * SVCMODE: switch to SVC mode
- */
-
-#define N_BIT	(1 << 31)
-#define Z_BIT	(1 << 30)
-#define C_BIT	(1 << 29)
-#define V_BIT	(1 << 28)
-
-#define PCMASK	0xfc000003
-
-#ifdef __ASSEMBLER__
-
-#define I_BIT	(1 << 27)
-#define F_BIT	(1 << 26)
-
-#define MODE_USR	0
-#define MODE_FIQ	1
-#define MODE_IRQ	2
-#define MODE_SVC	3
+#define MODE_USR	USR26_MODE
+#define MODE_FIQ	FIQ26_MODE
+#define MODE_IRQ	IRQ26_MODE
+#define MODE_SVC	SVC26_MODE
 
 #define DEFAULT_FIQ	MODE_FIQ
 
+#ifdef __STDC__
 #define LOADREGS(cond, base, reglist...)\
 	ldm##cond	base,reglist^
 
 #define RETINSTR(instr, regs...)\
 	instr##s	regs
+#else
+#define LOADREGS(cond, base, reglist...)\
+	ldm/**/cond	base,reglist^
+
+#define RETINSTR(instr, regs...)\
+	instr/**/s	regs
+#endif
 
 #define MODENOP\
 	mov	r0, r0
@@ -84,5 +60,3 @@
 #define SVCMODE(tmpreg)\
 	teqp	pc, $0x00000003;\
 	mov	r0, r0
-
-#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h
--- v2.3.22/linux/include/asm-arm/proc-armo/cache.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armo/cache.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,67 @@
+/*
+ * Cache flushing...
+ */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(mm,start,end)		do { } while (0)
+#define flush_cache_page(vma,vmaddr)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
+#define flush_icache_range(start,end)		do { } while (0)
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ */
+#define flush_tlb_all()				memc_update_all()
+#define flush_tlb_mm(mm)			do { } while (0)
+#define flush_tlb_range(mm, start, end)		do { (void)(start); (void)(end); } while (0)
+#define flush_tlb_page(vma, vmaddr)		do { } while (0)
+
+/*
+ * The following handle the weird MEMC chip
+ */
+extern __inline__ void memc_update_all(void)
+{
+	struct task_struct *p;
+
+	cpu_memc_update_all(init_mm.pgd);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		cpu_memc_update_all(p->mm->pgd);
+	}
+	processor._set_pgd(current->active_mm->pgd);
+}
+
+extern __inline__ void memc_update_mm(struct mm_struct *mm)
+{
+	cpu_memc_update_all(mm->pgd);
+
+	if (mm == current->active_mm)
+		processor._set_pgd(mm->pgd);
+}
+
+extern __inline__ void
+memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long addr)
+{
+	cpu_memc_update_entry(mm->pgd, pte_val(pte), addr);
+
+	if (mm == current->active_mm)
+		processor._set_pgd(mm->pgd);
+}
+
+extern __inline__ void
+memc_clear(struct mm_struct *mm, unsigned long phys_addr)
+{
+	cpu_memc_update_entry(mm->pgd, phys_addr, 0);
+
+	if (mm == current->active_mm)
+		processor._set_pgd(mm->pgd);
+}
+
+#define __flush_entry_to_ram(entry)
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/elf.h linux/include/asm-arm/proc-armo/elf.h
--- v2.3.22/linux/include/asm-arm/proc-armo/elf.h	Thu Dec 17 09:05:43 1998
+++ linux/include/asm-arm/proc-armo/elf.h	Wed Oct 20 16:29:08 1999
@@ -4,14 +4,11 @@
 
 #define ELF_EXEC_PAGESIZE	32768
 
-#if 0		/* not yet */
+#ifdef __KERNEL__
+
+/* We can only execute 26-bit code. */
 #define ELF_PROC_OK(x)		\
 	((x)->e_flags & EF_ARM_APCS26)
-#else
-#define ELF_PROC_OK(x)		(1)
-#endif
-
-#ifdef __KERNEL__
 
 #define SET_PERSONALITY(ex,ibcs2) \
 	current->personality = PER_LINUX
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/mm-init.h linux/include/asm-arm/proc-armo/mm-init.h
--- v2.3.22/linux/include/asm-arm/proc-armo/mm-init.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/proc-armo/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/mm-init.h
- *
- * Copyright (C) 1996 Russell King
- *
- * This contains the code to setup the memory map on an ARM2/ARM250/ARM3
- * machine. This is both processor & architecture specific, and requires
- * some more work to get it to fit into our separate processor and
- * architecture structure.
- */
-#include <asm/arch/memory.h>
-
-int page_nr;
-
-#define setup_processor_functions()
-#define PTE_SIZE	(PTRS_PER_PTE * BYTES_PER_PTR)
-
-static inline void setup_swapper_dir (int index, pte_t *ptep)
-{
-	set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep));
-}
-
-static inline unsigned long
-setup_pagetables(unsigned long start_mem, unsigned long end_mem)
-{
-	unsigned int i;
-	union { unsigned long l; pte_t *pte; } u;
-
-	page_nr = MAP_NR(end_mem);
-
-	/* map in pages for (0x0000 - 0x8000) */
-	u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1));
-	start_mem = u.l + PTE_SIZE;
-	memzero (u.pte, PTE_SIZE);
-	u.pte[0] = mk_pte(PAGE_OFFSET + 491520, PAGE_READONLY);
-	setup_swapper_dir (0, u.pte);
-
-	for (i = 1; i < PTRS_PER_PGD; i++)
-		pgd_val(swapper_pg_dir[i]) = 0;
-
-	return start_mem;
-}
-
-static inline void
-mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
-{
-	unsigned long smem;
-
-	*start_mem = smem = PAGE_ALIGN(*start_mem);
-
-	while (smem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-		smem += PAGE_SIZE;
-	}
-}
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/page.h linux/include/asm-arm/proc-armo/page.h
--- v2.3.22/linux/include/asm-arm/proc-armo/page.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/proc-armo/page.h	Wed Oct 20 16:29:08 1999
@@ -3,74 +3,18 @@
  *
  * Copyright (C) 1995, 1996 Russell King
  */
-
 #ifndef __ASM_PROC_PAGE_H
 #define __ASM_PROC_PAGE_H
 
 #include <linux/config.h>
 
 /* PAGE_SHIFT determines the page size.  This is configurable. */
-#if defined(CONFIG_PAGESIZE_8)
-#define PAGE_SHIFT	13		/* 8K */
-#elif defined(CONFIG_PAGESIZE_16)
+#if defined(CONFIG_PAGESIZE_16)
 #define PAGE_SHIFT	14		/* 16K */
 #else		/* default */
 #define PAGE_SHIFT	15		/* 32K */
 #endif
-#define PAGE_SIZE       (1UL << PAGE_SHIFT)
-#define PAGE_MASK       (~(PAGE_SIZE-1))
-
-#ifdef __KERNEL__
-
-#define STRICT_MM_TYPECHECKS
-
-#ifdef STRICT_MM_TYPECHECKS
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-#define pte_val(x)      ((x).pte)
-#define pmd_val(x)      ((x).pmd)
-#define pgd_val(x)      ((x).pgd)
-#define pgprot_val(x)   ((x).pgprot)
-
-#define __pte(x)        ((pte_t) { (x) } )
-#define __pmd(x)        ((pmd_t) { (x) } )
-#define __pgd(x)        ((pgd_t) { (x) } )
-#define __pgprot(x)     ((pgprot_t) { (x) } )
-
-#else
-/*
- * .. while these make it easier on the compiler
- */
-typedef unsigned long pte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t;
-typedef unsigned long pgprot_t;
-
-#define pte_val(x)      (x)
-#define pmd_val(x)      (x)
-#define pgd_val(x)      (x)
-#define pgprot_val(x)   (x)
-
-#define __pte(x)        (x)
-#define __pmd(x)        (x)
-#define __pgd(x)        (x)
-#define __pgprot(x)     (x)
-
-#endif
 
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/* This handles the memory map.. */
-#define MAP_NR(addr)		(((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
-
-#endif /* __KERNEL__ */
+#define EXEC_PAGESIZE   32768
 
 #endif /* __ASM_PROC_PAGE_H */
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/param.h linux/include/asm-arm/proc-armo/param.h
--- v2.3.22/linux/include/asm-arm/proc-armo/param.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/param.h	Wed Dec 31 16:00:00 1969
@@ -1,27 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/param.h
- *
- * Copyright (C) 1995, 1996 Russell King
- */
-
-#ifndef __ASM_PROC_PARAM_H
-#define __ASM_PROC_PARAM_H
-
-#ifndef HZ
-#define HZ 100
-#endif
-
-#define EXEC_PAGESIZE   32768
-
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
-#ifndef NOGROUP
-#define NOGROUP         (-1)
-#endif
-
-#define MAXHOSTNAMELEN  64      /* max length of hostname */
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.3.22/linux/include/asm-arm/proc-armo/pgtable.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-arm/proc-armo/pgtable.h	Wed Oct 20 16:29:08 1999
@@ -1,105 +1,23 @@
 /*
  * linux/include/asm-arm/proc-armo/pgtable.h
  *
- * Copyright (C) 1995, 1996 Russell King
- * Modified 18/19-Oct-1997 for two-level page table
+ * Copyright (C) 1995-1999 Russell King
+ *
+ * 18-Oct-1997	RMK	Now two-level (32x32)
  */
 #ifndef __ASM_PROC_PGTABLE_H
 #define __ASM_PROC_PGTABLE_H
 
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <asm/arch/memory.h>		/* For TASK_SIZE */
-
-#define LIBRARY_TEXT_START 0x0c000000
-
 /*
- * Cache flushing...
+ * PMD_SHIFT determines the size of the area a second-level page table can map
  */
-#define flush_cache_all()			do { } while (0)
-#define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm,start,end)		do { } while (0)
-#define flush_cache_page(vma,vmaddr)		do { } while (0)
-#define flush_page_to_ram(page)			do { } while (0)
-#define flush_icache_range(start,end)		do { } while (0)
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
- */
-#define flush_tlb()			do { } while (0)
-#define flush_tlb_all()			do { } while (0)
-#define flush_tlb_mm(mm)		do { } while (0)
-#define flush_tlb_range(mm, start, end) do { } while (0)
-#define flush_tlb_page(vma, vmaddr)	do { } while (0)
-
-/*
- * We have a mem map cache...
- */
-extern __inline__ void update_memc_all(void)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		processor.u.armv2._update_map(p);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	processor.u.armv2._remap_memc (current);
-}
-
-extern __inline__ void update_memc_task(struct task_struct *tsk)
-{
-	processor.u.armv2._update_map(tsk);
-
-	if (tsk == current)
-		processor.u.armv2._remap_memc (tsk);
-}
-
-extern __inline__ void update_memc_mm(struct mm_struct *mm)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		if (p->mm == mm)
-			processor.u.armv2._update_map(p);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	if (current->mm == mm)
-		processor.u.armv2._remap_memc (current);
-}
-
-extern __inline__ void update_memc_addr(struct mm_struct *mm, unsigned long addr, pte_t pte)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		if (p->mm == mm)
-			processor.u.armv2._update_mmu_cache(p, addr, pte);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	if (current->mm == mm)
-		processor.u.armv2._remap_memc (current);
-}
-
-#define __flush_entry_to_ram(entry)
-
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
 #define PMD_SHIFT       20
 #define PMD_SIZE        (1UL << PMD_SHIFT)
 #define PMD_MASK        (~(PMD_SIZE-1))
 
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
+/*
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
 #define PGDIR_SHIFT     20
 #define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE-1))
@@ -107,8 +25,6 @@
 /*
  * entries per page directory level: the arm3 is one-level, so
  * we don't really have any PMD or PTE directory physically.
- *
- * 18-Oct-1997 RMK Now two-level (32x32)
  */
 #define PTRS_PER_PTE    32
 #define PTRS_PER_PMD    1
@@ -119,11 +35,11 @@
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END	0x01c00000
 
-#define _PAGE_PRESENT		0x01
-#define _PAGE_READONLY		0x02
-#define _PAGE_NOT_USER		0x04
-#define _PAGE_OLD		0x08
-#define _PAGE_CLEAN		0x10
+#define _PAGE_PRESENT	0x01
+#define _PAGE_READONLY	0x02
+#define _PAGE_NOT_USER	0x04
+#define _PAGE_OLD	0x08
+#define _PAGE_CLEAN	0x10
 
 #define _PAGE_TABLE     (_PAGE_PRESENT)
 #define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_OLD | _PAGE_CLEAN)
@@ -157,47 +73,6 @@
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
-#undef TEST_VERIFY_AREA
-
-extern unsigned long *empty_zero_page;
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pte_t *__bad_pagetable(void);
-
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE(vaddr) ((unsigned long) empty_zero_page)
-
-/* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR			(sizeof(unsigned long))
-#define BITS_PER_PTR                    (8*BYTES_PER_PTR)
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK                        (~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2                 2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* to set the page-dir */
-#define SET_PAGE_DIR(tsk,pgdir)						\
-do {									\
-	tsk->tss.memmap = (unsigned long)pgdir;				\
-	processor.u.armv2._update_map(tsk);				\
-	if ((tsk) == current)						\
-		processor.u.armv2._remap_memc (current);		\
-} while (0)
-
 extern unsigned long physical_start;
 extern unsigned long physical_end;
 
@@ -229,7 +104,6 @@
 extern inline int pte_exec(pte_t pte)           { return !(pte_val(pte) & _PAGE_NOT_USER);     }
 extern inline int pte_dirty(pte_t pte)          { return !(pte_val(pte) & _PAGE_CLEAN);        }
 extern inline int pte_young(pte_t pte)          { return !(pte_val(pte) & _PAGE_OLD);          }
-#define pte_cacheable(pte) 1
 
 extern inline pte_t pte_nocache(pte_t pte)	{ return pte; }
 extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) |= _PAGE_READONLY;  return pte; }
@@ -322,128 +196,45 @@
  * if any.
  */
 
-#ifndef __SMP__
-#ifndef CONFIG_NO_PGT_CACHE
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
-
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (quicklists.pte_cache)
-#define pgd_quicklist (quicklists.pgd_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-#endif
-
-#else
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif
-
-extern pgd_t *get_pgd_slow(void);
 extern void free_table(void *table);
 
-#ifndef CONFIG_NO_PGT_CACHE
-extern __inline__ pgd_t *get_pgd_fast(void)
-{
-	unsigned long *ret;
-
-	if((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size--;
-	} else
-		ret = (unsigned long *)get_pgd_slow();
-	return (pgd_t *)ret;
-}
-
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
-}
-#endif
-
 /* keep this as an inline so we get type checking */
 extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-	free_table((void *)pgd);
-}
-
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
-#ifndef CONFIG_NO_PGT_CACHE
-extern __inline__ pte_t *get_pte_fast(void)
-{
-	unsigned long *ret;
-
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size--;
-	}
-	return (pte_t *)ret;
-}
-
-extern __inline__ void free_pte_fast(pte_t *pte)
-{
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	pgtable_cache_size++;
+	free_table(pgd);
 }
-#endif
 
 /* keep this as an inline so we get type checking */
 extern __inline__ void free_pte_slow(pte_t *pte)
 {
-	free_table((void *)pte);
-}
-
-/* We don't use pmd cache, so this is a dummy routine */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
+	free_table(pte);
 }
 
 extern __inline__ void free_pmd_slow(pmd_t *pmd)
 {
 }
 
-extern void __bad_pmd(pmd_t *pmd);
-extern void __bad_pmd_kernel(pmd_t *pmd);
-
-#ifdef CONFIG_NO_PGT_CACHE
-#define pte_free_kernel(pte)    free_pte_slow(pte)
-#define pte_free(pte)           free_pte_slow(pte)
-#define pgd_free(pgd)           free_pgd_slow(pgd)
-#define pgd_alloc()             get_pgd_slow()
+#define pgd_free(pgd)           free_pgd_fast(pgd)
 
-extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
+extern __inline__ pgd_t *pgd_alloc(void)
 {
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	extern pgd_t *get_pgd_slow(void);
+	pgd_t *pgd;
 
-	if (pmd_none (*pmd)) {
-		return get_pte_slow(pmd, address);
-	}
-	if (pmd_bad (*pmd)) {
-		__bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
+	pgd = get_pgd_fast();
+	if (!pgd)
+		pgd = get_pgd_slow();
+
+	return pgd;
 }
-#else
+
 #define pte_free_kernel(pte)    free_pte_fast(pte)
 #define pte_free(pte)           free_pte_fast(pte)
-#define pgd_free(pgd)           free_pgd_fast(pgd)
-#define pgd_alloc()             get_pgd_fast()
 
 extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
 {
+	extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 
 	if (pmd_none (*pmd)) {
@@ -460,7 +251,6 @@
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
 }
-#endif
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -479,34 +269,4 @@
 #define pmd_alloc_kernel        pmd_alloc
 #define pte_alloc_kernel        pte_alloc
 
-extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
-{
-	struct task_struct * p;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-#ifndef CONFIG_NO_PGT_CACHE
-	{
-		pgd_t *pgd;
-		for (pgd = (pgd_t *)pgd_quicklist; pgd;
-		     pgd = (pgd_t *)*(unsigned long *)pgd)
-			pgd[address >> PGDIR_SHIFT] = entry;
-	}
-#endif
-}
-
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-#define update_mmu_cache(vma,address,pte)
-
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) <<  8))
-
-#endif /* __ASM_PROC_PAGE_H */
-
+#endif /* __ASM_PROC_PGTABLE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h
--- v2.3.22/linux/include/asm-arm/proc-armo/processor.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/proc-armo/processor.h	Wed Oct 20 16:29:08 1999
@@ -15,7 +15,6 @@
 #ifndef __ASM_PROC_PROCESSOR_H
 #define __ASM_PROC_PROCESSOR_H
 
-#include <asm/assembler.h>
 #include <linux/string.h>
 
 #define KERNEL_STACK_SIZE 4096
@@ -45,20 +44,16 @@
 	unsigned long (*copy_to_user)(void *to, const void *from, unsigned long sz);
 	unsigned long (*clear_user)(void *addr, unsigned long sz);
 	unsigned long (*strncpy_from_user)(char *to, const char *from, unsigned long sz);
-	unsigned long (*strlen_user)(const char *s);
+	unsigned long (*strnlen_user)(const char *s, long n);
 } uaccess_t;
 
 extern uaccess_t uaccess_user, uaccess_kernel;
 
 #define EXTRA_THREAD_STRUCT							\
-	uaccess_t	*uaccess;		/* User access functions*/	\
-	unsigned long	memcmap[256];
+	uaccess_t	*uaccess;		/* User access functions*/
 
 #define EXTRA_THREAD_STRUCT_INIT		\
-	,&uaccess_kernel,			\
-	{ 0, }
-
-#define SWAPPER_PG_DIR ((unsigned long)swapper_pg_dir)
+	,&uaccess_kernel
 
 #define start_thread(regs,pc,sp)					\
 ({									\
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h
--- v2.3.22/linux/include/asm-arm/proc-armo/ptrace.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/proc-armo/ptrace.h	Wed Oct 20 16:29:08 1999
@@ -1,12 +1,26 @@
 /*
  * linux/include/asm-arm/proc-armo/ptrace.h
  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
-
 #ifndef __ASM_PROC_PTRACE_H
 #define __ASM_PROC_PTRACE_H
 
+#define USR26_MODE	0x00
+#define FIQ26_MODE	0x01
+#define IRQ26_MODE	0x02
+#define SVC26_MODE	0x03
+#define MODE_MASK	0x03
+#define F_BIT		(1 << 26)
+#define I_BIT		(1 << 27)
+#define CC_V_BIT	(1 << 28)
+#define CC_C_BIT	(1 << 29)
+#define CC_Z_BIT	(1 << 30)
+#define CC_N_BIT	(1 << 31)
+#define PCMASK		0xfc000003
+
+#ifndef __ASSEMBLY__
+
 /* this struct defines the way the registers are stored on the
    stack during a system call. */
 
@@ -30,19 +44,7 @@
 #define ARM_r2		uregs[2]
 #define ARM_r1		uregs[1]
 #define ARM_r0		uregs[0]
-#define ARM_ORIG_r0	uregs[16] /* -1 */
-
-#define USR26_MODE	0x00
-#define FIQ26_MODE	0x01
-#define IRQ26_MODE	0x02
-#define SVC26_MODE	0x03
-#define MODE_MASK	0x03
-#define F_BIT		(1 << 26)
-#define I_BIT		(1 << 27)
-#define CC_V_BIT	(1 << 28)
-#define CC_C_BIT	(1 << 29)
-#define CC_Z_BIT	(1 << 30)
-#define CC_N_BIT	(1 << 31)
+#define ARM_ORIG_r0	uregs[16]
 
 #ifdef __KERNEL__
 
@@ -61,12 +63,6 @@
 #define condition_codes(regs) \
 	((regs)->ARM_pc & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
 
-#define pc_pointer(v) \
-	((v) & 0x03fffffc)
-
-#define instruction_pointer(regs) \
-	(pc_pointer((regs)->ARM_pc))
-
 /* Are the current registers suitable for user mode?
  * (used to maintain security in signal handlers)
  */
@@ -85,6 +81,8 @@
 }
 
 #endif	/* __KERNEL__ */
+
+#endif	/* __ASSEMBLY__ */
 
 #endif
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/system.h linux/include/asm-arm/proc-armo/system.h
--- v2.3.22/linux/include/asm-arm/proc-armo/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/proc-armo/system.h	Wed Oct 20 16:29:08 1999
@@ -13,6 +13,8 @@
 
 extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 {
+	extern void arm_invalidptr(const char *, int);
+
 	switch (size) {
 		case 1:	return cpu_xchg_1(x, ptr);
 		case 2:	return cpu_xchg_2(x, ptr);
@@ -27,11 +29,6 @@
  * messes up if we don't
  */
 #define proc_hard_reset()	cpu_proc_fin()
-
-/*
- * This processor does not idle
- */
-#define proc_idle()
 
 /*
  * A couple of speedups for the ARM
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armo/uaccess.h linux/include/asm-arm/proc-armo/uaccess.h
--- v2.3.22/linux/include/asm-arm/proc-armo/uaccess.h	Fri May  8 00:42:40 1998
+++ linux/include/asm-arm/proc-armo/uaccess.h	Wed Oct 20 16:29:08 1999
@@ -19,16 +19,12 @@
 #define KERNEL_DS	0x03000000
 #define USER_DS   	0x02000000
 
-#define get_ds()	(KERNEL_DS)
-#define get_fs()	(current->addr_limit)
-#define segment_eq(a,b)	((a) == (b))
-
 extern uaccess_t uaccess_user, uaccess_kernel;
 
 extern __inline__ void set_fs (mm_segment_t fs)
 {
 	current->addr_limit = fs;
-	current->tss.uaccess = fs == USER_DS ? &uaccess_user : &uaccess_kernel;
+	current->thread.uaccess = fs == USER_DS ? &uaccess_user : &uaccess_kernel;
 }
 
 #define __range_ok(addr,size) ({					\
@@ -47,8 +43,6 @@
 		: "cc");						\
 	(flag == 0); })
 
-#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
-
 #define __put_user_asm_byte(x,addr,err)					\
 	__asm__ __volatile__(						\
 	"	mov	r0, %1\n"					\
@@ -58,7 +52,7 @@
 	"	mov	pc, %3\n"					\
 	"	mov	%0, r2\n"					\
 	: "=r" (err)							\
-	: "r" (x), "r" (addr), "r" (current->tss.uaccess->put_byte),	\
+	: "r" (x), "r" (addr), "r" (current->thread.uaccess->put_byte),	\
 	  "0" (err)							\
 	: "r0", "r1", "r2", "lr")
 
@@ -71,7 +65,7 @@
 	"	mov	pc, %3\n"					\
 	"	mov	%0, r2\n"					\
 	: "=r" (err)							\
-	: "r" (x), "r" (addr), "r" (current->tss.uaccess->put_half),	\
+	: "r" (x), "r" (addr), "r" (current->thread.uaccess->put_half),	\
 	  "0" (err)							\
 	: "r0", "r1", "r2", "lr")
 
@@ -84,7 +78,7 @@
 	"	mov	pc, %3\n"					\
 	"	mov	%0, r2\n"					\
 	: "=r" (err)							\
-	: "r" (x), "r" (addr), "r" (current->tss.uaccess->put_word),	\
+	: "r" (x), "r" (addr), "r" (current->thread.uaccess->put_word),	\
 	  "0" (err)							\
 	: "r0", "r1", "r2", "lr")
 
@@ -97,7 +91,7 @@
 	"	mov	%0, r1\n"					\
 	"	mov	%1, r0\n"					\
 	: "=r" (err), "=r" (x)						\
-	: "r" (addr), "r" (current->tss.uaccess->get_byte), "0" (err)	\
+	: "r" (addr), "r" (current->thread.uaccess->get_byte), "0" (err)	\
 	: "r0", "r1", "r2", "lr")
 
 #define __get_user_asm_half(x,addr,err)					\
@@ -109,7 +103,7 @@
 	"	mov	%0, r1\n"					\
 	"	mov	%1, r0\n"					\
 	: "=r" (err), "=r" (x)						\
-	: "r" (addr), "r" (current->tss.uaccess->get_half), "0" (err)	\
+	: "r" (addr), "r" (current->thread.uaccess->get_half), "0" (err)	\
 	: "r0", "r1", "r2", "lr")
 
 #define __get_user_asm_word(x,addr,err)					\
@@ -121,20 +115,20 @@
 	"	mov	%0, r1\n"					\
 	"	mov	%1, r0\n"					\
 	: "=r" (err), "=r" (x)						\
-	: "r" (addr), "r" (current->tss.uaccess->get_word), "0" (err)	\
+	: "r" (addr), "r" (current->thread.uaccess->get_word), "0" (err)	\
 	: "r0", "r1", "r2", "lr")
 
 #define __do_copy_from_user(to,from,n)					\
-	(n) = current->tss.uaccess->copy_from_user((to),(from),(n))
+	(n) = current->thread.uaccess->copy_from_user((to),(from),(n))
 
 #define __do_copy_to_user(to,from,n)					\
-	(n) = current->tss.uaccess->copy_to_user((to),(from),(n))
+	(n) = current->thread.uaccess->copy_to_user((to),(from),(n))
 
 #define __do_clear_user(addr,sz)					\
-	(sz) = current->tss.uaccess->clear_user((addr),(sz))
+	(sz) = current->thread.uaccess->clear_user((addr),(sz))
 
 #define __do_strncpy_from_user(dst,src,count,res)			\
-	(res) = current->tss.uaccess->strncpy_from_user(dst,src,count)
+	(res) = current->thread.uaccess->strncpy_from_user(dst,src,count)
 
-#define __do_strlen_user(s,res)						\
-	(res) = current->tss.uaccess->strlen_user(s)
+#define __do_strnlen_user(s,n,res)					\
+	(res) = current->thread.uaccess->strnlen_user(s,n)
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/assembler.h linux/include/asm-arm/proc-armv/assembler.h
--- v2.3.22/linux/include/asm-arm/proc-armv/assembler.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/assembler.h	Wed Oct 20 16:29:08 1999
@@ -6,79 +6,81 @@
  * This file contains arm architecture specific defines
  * for the different processors
  */
+#ifndef __ASSEMBLY__
+#error "Only include this from assembly code"
+#endif
 
-/*
- * LOADREGS: multiple register load (ldm) with pc in register list
- *		(takes account of ARM6 not using ^)
- *
- * RETINSTR: return instruction: adds the 's' in at the end of the
- *		instruction if this is not an ARM6
- *
- * SAVEIRQS: save IRQ state (not required on ARM2/ARM3 - done
- *		implicitly
- *
- * RESTOREIRQS: restore IRQ state (not required on ARM2/ARM3 - done
- *		implicitly with ldm ... ^ or movs.
- *
- * These next two need thinking about - can't easily use stack... (see system.S)
- * DISABLEIRQS: disable IRQS in SVC mode
- *
- * ENABLEIRQS: enable IRQS in SVC mode
- *
- * USERMODE: switch to USER mode
- *
- * SVCMODE: switch to SVC mode
- */
-
-#define N_BIT	(1 << 31)
-#define Z_BIT	(1 << 30)
-#define C_BIT	(1 << 29)
-#define V_BIT	(1 << 28)
-
-#define PCMASK	0
-
-#ifdef __ASSEMBLER__
-
-#define I_BIT	(1 << 7)
-#define F_BIT	(1 << 6)
-
-#define MODE_FIQ26	0x01
-#define MODE_FIQ32	0x11
+#define MODE_USR	USR_MODE
+#define MODE_FIQ	FIQ_MODE
+#define MODE_IRQ	IRQ_MODE
+#define MODE_SVC	SVC_MODE
 
-#define DEFAULT_FIQ	MODE_FIQ32
+#define DEFAULT_FIQ	MODE_FIQ
 
+/*
+ * LOADREGS - ldm with PC in register list (eg, ldmfd sp!, {pc})
+ * RETINSTR - return instruction (eg, mov pc, lr)
+ */
+#ifdef __STDC__
 #define LOADREGS(cond, base, reglist...)\
 	ldm##cond	base,reglist
 
 #define RETINSTR(instr, regs...)\
 	instr	regs
+#else
+#define LOADREGS(cond, base, reglist...)\
+	ldm/**/cond	base,reglist
 
+#define RETINSTR(instr, regs...)\
+	instr		regs
+#endif
+
+/*
+ * No nop required after mode change
+ */
 #define MODENOP
 
+/*
+ * Change to `mode'
+ */
 #define MODE(savereg,tmpreg,mode) \
 	mrs	savereg, cpsr; \
 	bic	tmpreg, savereg, $0x1f; \
 	orr	tmpreg, tmpreg, $mode; \
 	msr	cpsr, tmpreg
 
+/*
+ * Restore mode
+ */
 #define RESTOREMODE(savereg) \
 	msr	cpsr, savereg
-	
+
+/*
+ * save interrupt state (uses stack)
+ */	
 #define SAVEIRQS(tmpreg)\
 	mrs	tmpreg, cpsr; \
 	str	tmpreg, [sp, $-4]!
 
+/*
+ * restore interrupt state (uses stack)
+ */
 #define RESTOREIRQS(tmpreg)\
 	ldr	tmpreg, [sp], $4; \
 	msr	cpsr, tmpreg
 
+/*
+ * disable IRQs
+ */
 #define DISABLEIRQS(tmpreg)\
 	mrs	tmpreg , cpsr; \
 	orr	tmpreg , tmpreg , $I_BIT; \
 	msr	cpsr, tmpreg
 
+/*
+ * enable IRQs
+ */
 #define ENABLEIRQS(tmpreg)\
 	mrs	tmpreg , cpsr; \
 	bic	tmpreg , tmpreg , $I_BIT; \
 	msr	cpsr, tmpreg
-#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h
--- v2.3.22/linux/include/asm-arm/proc-armv/cache.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armv/cache.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,93 @@
+/*
+ * Cache flushing...
+ */
+#define flush_cache_all()						\
+	cpu_flush_cache_all()
+
+#define flush_cache_mm(_mm)						\
+	do {								\
+		if ((_mm) == current->mm)				\
+			cpu_flush_cache_all();				\
+	} while (0)
+
+#define flush_cache_range(_mm,_start,_end)				\
+	do {								\
+		if ((_mm) == current->mm)				\
+			cpu_flush_cache_area((_start), (_end), 1);	\
+	} while (0)
+
+#define flush_cache_page(_vma,_vmaddr)					\
+	do {								\
+		if ((_vma)->vm_mm == current->mm)			\
+			cpu_flush_cache_area((_vmaddr),			\
+				(_vmaddr) + PAGE_SIZE,			\
+				((_vma)->vm_flags & VM_EXEC));		\
+	} while (0)
+
+#define clean_cache_range(_start,_end)					\
+	do {								\
+		unsigned long _s, _sz;					\
+		_s = (unsigned long)_start;				\
+		_sz = (unsigned long)_end - _s;				\
+		cpu_clean_cache_area(_s, _sz);				\
+	} while (0)
+
+#define clean_cache_area(_start,_size)					\
+	do {								\
+		unsigned long _s;					\
+		_s = (unsigned long)_start;				\
+		cpu_clean_cache_area(_s, _size);			\
+	} while (0)
+
+#define flush_icache_range(_start,_end)					\
+	cpu_flush_icache_area((_start), (_end) - (_start))
+
+/*
+ * We don't have a MEMC chip...
+ */
+#define memc_update_all()		do { } while (0)
+#define memc_update_mm(mm)		do { } while (0)
+#define memc_update_addr(mm,pte,log)	do { } while (0)
+#define memc_clear(mm,physaddr)		do { } while (0)
+
+/*
+ * This flushes back any buffered write data.  We have to clean the entries
+ * in the cache for this page.  This does not invalidate either I or D caches.
+ */
+#define flush_page_to_ram(_page)					\
+	cpu_flush_ram_page((_page) & PAGE_MASK);
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *
+ * We drain the write buffer in here to ensure that the page tables in ram
+ * are really up to date.  It is more efficient to do this here...
+ */
+#define flush_tlb_all()								\
+	cpu_flush_tlb_all()
+
+#define flush_tlb_mm(_mm)							\
+	do {									\
+		if ((_mm) == current->mm)					\
+			cpu_flush_tlb_all();					\
+	} while (0)
+
+#define flush_tlb_range(_mm,_start,_end)					\
+	do {									\
+		if ((_mm) == current->mm)					\
+			cpu_flush_tlb_area((_start), (_end), 1);		\
+	} while (0)
+
+#define flush_tlb_page(_vma,_vmaddr)						\
+	do {									\
+		if ((_vma)->vm_mm == current->mm)				\
+			cpu_flush_tlb_page((_vmaddr),				\
+				 ((_vma)->vm_flags & VM_EXEC));			\
+	} while (0)
+
+
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/elf.h linux/include/asm-arm/proc-armv/elf.h
--- v2.3.22/linux/include/asm-arm/proc-armv/elf.h	Thu Dec 17 09:05:43 1998
+++ linux/include/asm-arm/proc-armv/elf.h	Wed Oct 20 16:29:08 1999
@@ -4,18 +4,20 @@
 
 #define ELF_EXEC_PAGESIZE	4096
 
-/* We can execute both 32-bit and 26-bit code. */
-#define ELF_PROC_OK(x)		(1)
-
 #ifdef __KERNEL__
 
-#if 0		/* not yet */
+/* 32-bit code is always OK.  Some cpus can do 26-bit, some can't.  */
+#define ELF_PROC_OK(x)				\
+	((! ((x)->e_flags & EF_ARM_APCS26))	\
+	|| (elf_hwcap & HWCAP_26BIT))
+
+/* Old NetWinder binaries were compiled in such a way that the iBCS
+   heuristic always trips on them.  Until these binaries become uncommon
+   enough not to care, don't trust the `ibcs' flag here.  In any case
+   there is no other ELF system currently supported by iBCS.
+   @@ Could print a warning message to encourage users to upgrade.  */
 #define SET_PERSONALITY(ex,ibcs2) \
-	current_personality = (ex->e_flags & EF_ARM_APCS26) ? \
+	current->personality = (ex.e_flags & EF_ARM_APCS26) ? \
 	PER_LINUX : PER_LINUX_32BIT
-#else
-#define SET_PERSONALITY(ex,ibcs2) \
-	current->personality = PER_LINUX_32BIT
-#endif
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/mm-init.h linux/include/asm-arm/proc-armv/mm-init.h
--- v2.3.22/linux/include/asm-arm/proc-armv/mm-init.h	Sat May  8 11:06:58 1999
+++ linux/include/asm-arm/proc-armv/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,177 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armv/mm-init.h
- *
- * Copyright (C) 1996 Russell King
- *
- * This contains the code to setup the memory map on an ARM v3 or v4 machine.
- * This is both processor & architecture specific, and requires some
- * more work to get it to fit into our separate processor and architecture
- * structure.
- */
-
-/*
- * On ebsa, we want the memory map set up so:
- *
- *   PHYS	  VIRT
- * 00000000	00000000	Zero page
- * 000003ff	000003ff	Zero page end
- * 00000000	c0000000	Kernel and all physical memory
- * 01ffffff	c1ffffff	End of physical (32MB)
- * e0000000	e0000000	IO start
- * ffffffff	ffffffff	IO end
- *
- * On rpc, we want:
- *
- *   PHYS	  VIRT
- * 10000000	00000000	Zero page
- * 100003ff	000003ff	Zero page end
- * 10000000	c0000000	Kernel and all physical memory
- * 1fffffff	cfffffff	End of physical (32MB)
- * 02000000	d?000000	Screen memory (first image)
- * 02000000	d8000000	Screen memory (second image)
- * 00000000	df000000	StrongARM cache invalidation area
- * 03000000	e0000000	IO start
- * 03ffffff	e0ffffff	IO end
- *
- * We set it up using the section page table entries.
- */
-#include <asm/pgtable.h>
- 
-#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR)
-
-extern unsigned long setup_io_pagetables(unsigned long start_mem);
-
-/*
- * Add a SECTION mapping between VIRT and PHYS in domain DOMAIN with protection PROT
- */
-static inline void
-alloc_init_section(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
-{
-	pgd_t *pgdp;
-	pmd_t *pmdp, pmd;
-
-	pgdp = pgd_offset_k(virt);
-	pmdp = pmd_offset(pgdp, virt);
-
-	pmd_val(pmd) = phys | PMD_TYPE_SECT | PMD_DOMAIN(domain) | prot;
-	set_pmd(pmdp, pmd);
-}
-
-/*
- * Clear any mapping
- */
-static inline void
-free_init_section(unsigned long virt)
-{
-	pgd_t *pgdp;
-	pmd_t *pmdp;
-
-	pgdp = pgd_offset_k(virt);
-	pmdp = pmd_offset(pgdp, virt);
-
-	pmd_clear(pmdp);
-}
-
-/*
- * Add a PAGE mapping between VIRT and PHYS in domain DOMAIN with protection PROT
- */
-static inline void
-alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
-{
-	pgd_t *pgdp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-
-	pgdp = pgd_offset_k(virt);
-	pmdp = pmd_offset(pgdp, virt);
-
-	if (pmd_none(*pmdp)) {
-		unsigned long memory = *mem;
-
-		memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1);
-
-		ptep = (pte_t *)memory;
-		memzero(ptep, PTE_SIZE);
-		memory += PTE_SIZE;
-
-		ptep = (pte_t *)memory;
-		memzero(ptep, PTE_SIZE);
-
-		set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
-
-		*mem = memory + PTE_SIZE;
-	}
-
-	ptep = pte_offset(pmdp, virt);
-
-	set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
-}
-
-static inline unsigned long
-setup_pagetables(unsigned long start_mem, unsigned long end_mem)
-{
-	unsigned long address = 0;
-
-	do {
-		if (address >= PAGE_OFFSET && address < end_mem)
-			/*
-			 * map in physical ram & kernel
-			 */
-			alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
-					   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
-		else
-			/*
-			 * unmap everything else
-			 */
-			free_init_section(address);
-
-		address += PGDIR_SIZE;
-	} while (address != 0);
-
-	/*
-	 * An area to invalidate the cache
-	 */
-	alloc_init_section(&start_mem, FLUSH_BASE, FLUSH_BASE_PHYS, DOMAIN_KERNEL,
-			   PMD_SECT_CACHEABLE | PMD_SECT_AP_READ);
-
-	/*
-	 * Now set up our IO mappings
-	 */
-	start_mem = setup_io_pagetables(start_mem);
-
-	/*
-	 * map in zero page
-	 */
-	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET),
-			DOMAIN_USER, L_PTE_CACHEABLE | L_PTE_YOUNG | L_PTE_PRESENT);
-
-	flush_cache_all();
-
-	return start_mem;
-}
-
-static inline
-void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
-{
-	unsigned long smem;
-
-	*start_mem = smem = PAGE_ALIGN(*start_mem);
-
-	/*
-	 * Mark all of memory from the end of kernel to end of memory
-	 */
-	while (smem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-		smem += PAGE_SIZE;
-	}
-
-	/*
-	 * Mark memory from page 1 to start of the swapper page directory
-	 */
-	smem = PAGE_OFFSET + PAGE_SIZE;
-	while (smem < (unsigned long)&swapper_pg_dir) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-		smem += PAGE_SIZE;
-	}
-}	
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/page.h linux/include/asm-arm/proc-armv/page.h
--- v2.3.22/linux/include/asm-arm/proc-armv/page.h	Thu Jan  7 15:51:33 1999
+++ linux/include/asm-arm/proc-armv/page.h	Wed Oct 20 16:29:08 1999
@@ -3,71 +3,12 @@
  *
  * Copyright (C) 1995, 1996 Russell King
  */
-
 #ifndef __ASM_PROC_PAGE_H
 #define __ASM_PROC_PAGE_H
 
-#include <asm/hardware.h>
-
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
-#define PAGE_SIZE       (1UL << PAGE_SHIFT)
-#define PAGE_MASK       (~(PAGE_SIZE-1))
-
-#ifdef __KERNEL__
-
-#define STRICT_MM_TYPECHECKS
-
-#ifdef STRICT_MM_TYPECHECKS
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-
-#define pte_val(x)      ((x).pte)
-#define pmd_val(x)      ((x).pmd)
-#define pgd_val(x)      ((x).pgd)
-#define pgprot_val(x)   ((x).pgprot)
-
-#define __pte(x)        ((pte_t) { (x) } )
-#define __pmd(x)        ((pmd_t) { (x) } )
-#define __pgd(x)        ((pgd_t) { (x) } )
-#define __pgprot(x)     ((pgprot_t) { (x) } )
-
-#else
-/*
- * .. while these make it easier on the compiler
- */
-typedef unsigned long pte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t;
-typedef unsigned long pgprot_t;
-
-#define pte_val(x)      (x)
-#define pmd_val(x)      (x)
-#define pgd_val(x)      (x)
-#define pgprot_val(x)   (x)
-
-#define __pte(x)        (x)
-#define __pmd(x)        (x)
-#define __pgd(x)        (x)
-#define __pgprot(x)     (x)
-
-#endif
-
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/* This handles the memory map.. */
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET		0xc0000000
-#endif
-
-#define MAP_NR(addr)		(((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 
-#endif /* __KERNEL__ */
+#define EXEC_PAGESIZE   4096
 
 #endif /* __ASM_PROC_PAGE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/param.h linux/include/asm-arm/proc-armv/param.h
--- v2.3.22/linux/include/asm-arm/proc-armv/param.h	Sun Sep  6 10:45:30 1998
+++ linux/include/asm-arm/proc-armv/param.h	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armv/param.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_PROC_PARAM_H
-#define __ASM_PROC_PARAM_H
-
-#include <asm/arch/param.h>		/* for HZ */
-
-#define EXEC_PAGESIZE   4096
-
-#ifndef NGROUPS
-#define NGROUPS         32
-#endif
-
-#ifndef NOGROUP
-#define NOGROUP         (-1)
-#endif
-
-#define MAXHOSTNAMELEN  64      /* max length of hostname */
-
-#endif
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.3.22/linux/include/asm-arm/proc-armv/pgtable.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/proc-armv/pgtable.h	Wed Oct 20 16:29:08 1999
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/proc-armv/pgtable.h
  *
- * Copyright (C) 1995, 1996, 1997 Russell King
+ * Copyright (C) 1995-1999 Russell King
  *
  * 12-Jan-1997	RMK	Altered flushing routines to use function pointers
  *			now possible to combine ARM6, ARM7 and StrongARM versions.
@@ -11,106 +11,7 @@
 #ifndef __ASM_PROC_PGTABLE_H
 #define __ASM_PROC_PGTABLE_H
 
-#include <asm/arch/memory.h>		/* For TASK_SIZE */
-
-#define LIBRARY_TEXT_START 0x0c000000
-
-/*
- * Cache flushing...
- */
-#define flush_cache_all()						\
-	cpu_flush_cache_all()
-
-#define flush_cache_mm(_mm)						\
-	do {								\
-		if ((_mm) == current->mm)				\
-			cpu_flush_cache_all();				\
-	} while (0)
-
-#define flush_cache_range(_mm,_start,_end)				\
-	do {								\
-		if ((_mm) == current->mm)				\
-			cpu_flush_cache_area((_start), (_end), 1);	\
-	} while (0)
-
-#define flush_cache_page(_vma,_vmaddr)					\
-	do {								\
-		if ((_vma)->vm_mm == current->mm)			\
-			cpu_flush_cache_area((_vmaddr),			\
-				(_vmaddr) + PAGE_SIZE,			\
-				((_vma)->vm_flags & VM_EXEC) ? 1 : 0);	\
-	} while (0)
-
-#define clean_cache_range(_start,_end)					\
-	do {								\
-		unsigned long _s, _sz;					\
-		_s = (unsigned long)_start;				\
-		_sz = (unsigned long)_end - _s;				\
-		cpu_clean_cache_area(_s, _sz);				\
-	} while (0)
-
-#define clean_cache_area(_start,_size)					\
-	do {								\
-		unsigned long _s;					\
-		_s = (unsigned long)_start;				\
-		cpu_clean_cache_area(_s, _size);			\
-	} while (0)
-
-#define flush_icache_range(_start,_end)					\
-	cpu_flush_icache_area((_start), (_end) - (_start))
-
-/*
- * We don't have a MEMC chip...
- */
-#define update_memc_all()		do { } while (0)
-#define update_memc_task(tsk)		do { } while (0)
-#define update_memc_mm(mm)		do { } while (0)
-#define update_memc_addr(mm,addr,pte)	do { } while (0)
-
-/*
- * This flushes back any buffered write data.  We have to clean and flush the entries
- * in the cache for this page.  Is it necessary to invalidate the I-cache?
- */
-#define flush_page_to_ram(_page)					\
-	cpu_flush_ram_page((_page) & PAGE_MASK);
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
- *
- * GCC uses conditional instructions, and expects the assembler code to do so as well.
- *
- * We drain the write buffer in here to ensure that the page tables in ram
- * are really up to date.  It is more efficient to do this here...
- */
-#define flush_tlb() flush_tlb_all()
-
-#define flush_tlb_all()								\
-	cpu_flush_tlb_all()
-
-#define flush_tlb_mm(_mm)							\
-	do {									\
-		if ((_mm) == current->mm)					\
-			cpu_flush_tlb_all();					\
-	} while (0)
-
-#define flush_tlb_range(_mm,_start,_end)					\
-	do {									\
-		if ((_mm) == current->mm)					\
-			cpu_flush_tlb_area((_start), (_end), 1);		\
-	} while (0)
-
-#define flush_tlb_page(_vma,_vmaddr)						\
-	do {									\
-		if ((_vma)->vm_mm == current->mm)				\
-			cpu_flush_tlb_area((_vmaddr), (_vmaddr) + PAGE_SIZE,	\
-				 ((_vma)->vm_flags & VM_EXEC) ? 1 : 0);		\
-	} while (0)
+#include <asm/proc/domain.h>
 
 /*
  * PMD_SHIFT determines the size of the area a second-level page table can map
@@ -135,8 +36,8 @@
 #define PTRS_PER_PGD    4096
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
  * physical memory until the kernel virtual memory starts.  That means that
  * any out-of-bounds memory accesses will hopefully be caught.
@@ -148,75 +49,6 @@
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
 
-
-/*
- * Domains
- */
-#define DOMAIN_USER	0
-#define DOMAIN_KERNEL	1
-#define DOMAIN_TABLE	1
-#define DOMAIN_IO	2
-
-
-
-#undef TEST_VERIFY_AREA
-
-/*
- * The sa110 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- */
-extern __inline__ void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t pte)
-{
-}
-
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
-extern unsigned long *empty_zero_page;
-
-#define BAD_PAGETABLE	__bad_pagetable()
-#define BAD_PAGE	__bad_page()
-#define ZERO_PAGE(vaddr)	((unsigned long) empty_zero_page)
-
-/* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR	(sizeof(unsigned long))
-#define BITS_PER_PTR	(8*BYTES_PER_PTR)
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK	(~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2	2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* to set the page-dir
- * Note that we need to flush the cache and TLBs
- * if we are affecting the current task.
- */
-#define SET_PAGE_DIR(tsk,pgdir)					\
-do {								\
-	tsk->tss.memmap = __virt_to_phys((unsigned long)pgdir);	\
-	if ((tsk) == current) {					\
-		flush_cache_all();				\
-		__asm__ __volatile__(				\
-		"mcr%?	p15, 0, %0, c2, c0, 0\n"		\
-		: : "r" (tsk->tss.memmap));			\
-		flush_tlb_all();				\
-	}							\
-} while (0)
-
-
 extern unsigned long get_page_2k(int priority);
 extern void free_page_2k(unsigned long page);
 
@@ -226,21 +58,6 @@
  * if any.
  */
 
-#ifndef __SMP__
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
-
-#define pgd_quicklist (quicklists.pgd_cache)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (quicklists.pte_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-#else
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif
-
 /****************
 * PMD functions *
 ****************/
@@ -275,23 +92,10 @@
 	return ((pmd_val(pmd) + 1) & 2);
 }
 
-/* We don't use pmd cache, so this is a dummy routine */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
-}
-
 extern __inline__ void free_pmd_slow(pmd_t *pmd)
 {
 }
 
-extern void __bad_pmd(pmd_t *pmd);
-extern void __bad_pmd_kernel(pmd_t *pmd);
-
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
@@ -378,29 +182,8 @@
 	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
 }
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
 extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
 
-extern __inline__ pte_t *get_pte_fast(void)
-{
-	unsigned long *ret;
-
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		clean_cache_area(ret, 4);
-		pgtable_cache_size--;
-	}
-	return (pte_t *)ret;
-}
-
-extern __inline__ void free_pte_fast(pte_t *pte)
-{
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	pgtable_cache_size++;
-}
-
 extern __inline__ void free_pte_slow(pte_t *pte)
 {
 	free_page_2k((unsigned long)(pte - PTRS_PER_PTE));
@@ -539,6 +322,8 @@
 
 extern __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
+	extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 
 	if (pmd_none(*pmd)) {
@@ -569,38 +354,12 @@
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-/* used for quicklists */
-#define __pgd_next(pgd) (((unsigned long *)pgd)[1])
-
 /* to find an entry in a page-table-directory */
 extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + (address >> PGDIR_SHIFT);
 }
 
-extern pgd_t *get_pgd_slow(void);
-
-extern __inline__ pgd_t *get_pgd_fast(void)
-{
-	unsigned long *ret;
-
-	if((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)__pgd_next(ret);
-		ret[1] = ret[2];
-		clean_cache_area(ret + 1, 4);
-		pgtable_cache_size--;
-	} else
-		ret = (unsigned long *)get_pgd_slow();
-	return (pgd_t *)ret;
-}
-
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-	__pgd_next(pgd) = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
-}
-
 extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
 	do {
@@ -630,28 +389,17 @@
 }
 
 #define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
 
-extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
+extern __inline__ pgd_t *pgd_alloc(void)
 {
-	struct task_struct * p;
+	extern pgd_t *get_pgd_slow(void);
 	pgd_t *pgd;
 
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)__pgd_next(pgd))
-		pgd[address >> PGDIR_SHIFT] = entry;
-}
+	pgd = get_pgd_fast();
+	if (!pgd)
+		pgd = get_pgd_slow();
 
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 9)
-#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
+	return pgd;
+}
 
-#endif /* __ASM_PROC_PAGE_H */
+#endif /* __ASM_PROC_PGTABLE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h
--- v2.3.22/linux/include/asm-arm/proc-armv/processor.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/proc-armv/processor.h	Wed Oct 20 16:29:08 1999
@@ -41,8 +41,6 @@
 	  domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |			\
 	  domain_val(DOMAIN_IO, DOMAIN_CLIENT)
 
-#define SWAPPER_PG_DIR	(((unsigned long)swapper_pg_dir) - PAGE_OFFSET)
-
 #define start_thread(regs,pc,sp)					\
 ({									\
 	unsigned long *stack = (unsigned long *)sp;			\
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/ptrace.h linux/include/asm-arm/proc-armv/ptrace.h
--- v2.3.22/linux/include/asm-arm/proc-armv/ptrace.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/proc-armv/ptrace.h	Wed Oct 20 16:29:08 1999
@@ -1,12 +1,33 @@
 /*
  * linux/include/asm-arm/proc-armv/ptrace.h
  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
-
 #ifndef __ASM_PROC_PTRACE_H
 #define __ASM_PROC_PTRACE_H
 
+#define USR26_MODE	0x00
+#define FIQ26_MODE	0x01
+#define IRQ26_MODE	0x02
+#define SVC26_MODE	0x03
+#define USR_MODE	0x10
+#define FIQ_MODE	0x11
+#define IRQ_MODE	0x12
+#define SVC_MODE	0x13
+#define ABT_MODE	0x17
+#define UND_MODE	0x1b
+#define SYSTEM_MODE	0x1f
+#define MODE_MASK	0x1f
+#define F_BIT		0x40
+#define I_BIT		0x80
+#define CC_V_BIT	(1 << 28)
+#define CC_C_BIT	(1 << 29)
+#define CC_Z_BIT	(1 << 30)
+#define CC_N_BIT	(1 << 31)
+#define PCMASK		0
+
+#ifndef __ASSEMBLY__
+
 /* this struct defines the way the registers are stored on the
    stack during a system call. */
 
@@ -31,37 +52,12 @@
 #define ARM_r2		uregs[2]
 #define ARM_r1		uregs[1]
 #define ARM_r0		uregs[0]
-#define ARM_ORIG_r0	uregs[17] /* -1 */
-
-#define USR26_MODE	0x00
-#define FIQ26_MODE	0x01
-#define IRQ26_MODE	0x02
-#define SVC26_MODE	0x03
-#define USR_MODE	0x10
-#define FIQ_MODE	0x11
-#define IRQ_MODE	0x12
-#define SVC_MODE	0x13
-#define ABT_MODE	0x17
-#define UND_MODE	0x1b
-#define SYSTEM_MODE	0x1f
-#define MODE_MASK	0x1f
-#define F_BIT		0x40
-#define I_BIT		0x80
-#define CC_V_BIT	(1 << 28)
-#define CC_C_BIT	(1 << 29)
-#define CC_Z_BIT	(1 << 30)
-#define CC_N_BIT	(1 << 31)
+#define ARM_ORIG_r0	uregs[17]
 
 #ifdef __KERNEL__
 
-#if 0 /* GCC/egcs should be able to optimise this, IMHO */
-#define user_mode(regs)	\
-	((((regs)->ARM_cpsr & MODE_MASK) == USR_MODE) || \
-	 (((regs)->ARM_cpsr & MODE_MASK) == USR26_MODE))
-#else
 #define user_mode(regs)	\
 	(((regs)->ARM_cpsr & 0xf) == 0)
-#endif
 
 #define processor_mode(regs) \
 	((regs)->ARM_cpsr & MODE_MASK)
@@ -75,9 +71,6 @@
 #define condition_codes(regs) \
 	((regs)->ARM_cpsr & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
 	
-#define instruction_pointer(regs)	((regs)->ARM_pc)
-#define pc_pointer(v)			(v)
-
 /* Are the current registers suitable for user mode?
  * (used to maintain security in signal handlers)
  */
@@ -96,6 +89,8 @@
 }
 
 #endif	/* __KERNEL__ */
+
+#endif	/* __ASSEMBLY__ */
 
 #endif
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h
--- v2.3.22/linux/include/asm-arm/proc-armv/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/proc-armv/system.h	Wed Oct 20 16:29:08 1999
@@ -11,6 +11,8 @@
 
 extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 {
+	extern void arm_invalidptr(const char *, int);
+
 	switch (size) {
 		case 1:	__asm__ __volatile__ ("swpb %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory");
 			break;
@@ -31,16 +33,6 @@
 
 extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
 extern unsigned long cr_alignment;	/* defined in entry-armv.S */
-
-/*
- * We can wait for an interrupt...
- */
-#define proc_idle()						\
-	do {							\
-	__asm__ __volatile__(					\
-"	mcr	p15, 0, %0, c15, c8, 2	@ proc_idle"		\
-	  : : "r" (0));						\
-	} while (0)
 
 /*
  * A couple of speedups for the ARM
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h
--- v2.3.22/linux/include/asm-arm/proc-armv/uaccess.h	Mon Aug  2 10:19:52 1999
+++ linux/include/asm-arm/proc-armv/uaccess.h	Wed Oct 20 16:29:08 1999
@@ -2,7 +2,7 @@
  * linux/include/asm-arm/proc-armv/uaccess.h
  */
 
-#include <asm/hardware.h>
+#include <asm/arch/memory.h>
 #include <asm/proc/domain.h>
 
 /*
@@ -11,11 +11,6 @@
 #define KERNEL_DS	0x00000000
 #define USER_DS		PAGE_OFFSET
 
-#define get_ds()	(KERNEL_DS)
-#define get_fs()	(current->addr_limit)
-
-#define segment_eq(a,b)	((a) == (b))
-
 extern __inline__ void set_fs (mm_segment_t fs)
 {
 	current->addr_limit = fs;
@@ -40,8 +35,6 @@
 		: "cc"); \
 	(flag == 0); })
 
-#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
-
 #define __put_user_asm_byte(x,addr,err)				\
 	__asm__ __volatile__(					\
 	"1:	strbt	%1,[%2],#0\n"				\
@@ -172,6 +165,6 @@
 #define __do_strncpy_from_user(dst,src,count,res)		\
 	(res) = __arch_strncpy_from_user(dst,src,count)
 
-extern unsigned long __arch_strlen_user(const char *s);
-#define __do_strlen_user(s,res)					\
-	(res) = __arch_strlen_user(s)
+extern unsigned long __arch_strnlen_user(const char *s, long n);
+#define __do_strnlen_user(s,n,res)					\
+	(res) = __arch_strnlen_user(s,n)
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.3.22/linux/include/asm-arm/proc-fns.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/proc-fns.h	Wed Oct 20 16:29:08 1999
@@ -58,4 +58,14 @@
 
 #endif /* __KERNEL__ */
 
+#if 0
+ * The following is to fool mkdep into generating the correct
+ * dependencies.  Without this, it cant figure out that this
+ * file does indeed depend on the cpu-*.h files.
+#include <asm/cpu-single.h>
+#include <asm/cpu-multi26.h>
+#include <asm/cpu-multi32.h>
+ *
+#endif
+
 #endif /* __ASM_PROCFNS_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.3.22/linux/include/asm-arm/processor.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/processor.h	Wed Oct 20 16:29:08 1999
@@ -32,11 +32,10 @@
 
 #ifdef __KERNEL__
 
-#include <asm/assembler.h> 
-
 #define NR_DEBUGS	5
 
-#include <asm/proc/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/arch/memory.h>
 #include <asm/arch/processor.h>
 #include <asm/proc/processor.h>
 
@@ -80,7 +79,7 @@
  */
 extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	return t->save ? t->save->pc & ~PCMASK : 0;
+	return t->save ? pc_pointer(t->save->pc) : 0;
 }
 
 extern __inline__ unsigned long get_css_fp(struct thread_struct *t)
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/procinfo.h linux/include/asm-arm/procinfo.h
--- v2.3.22/linux/include/asm-arm/procinfo.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/procinfo.h	Wed Oct 20 16:29:08 1999
@@ -6,7 +6,7 @@
 #ifndef __ASM_PROCINFO_H
 #define __ASM_PROCINFO_H
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 #include <asm/proc-fns.h>
 
@@ -18,11 +18,15 @@
 /*
  * Note!  struct processor is always defined if we're
  * using MULTI_CPU, otherwise this entry is unused,
- * but still exists.
+ * but still exists.  NOTE! This structure is used
+ * by assembler code!  Check:
+ *  arch/arm/mm/proc-*.S and arch/arm/kernel/head-armv.S
  */
 struct proc_info_list {
 	unsigned int	 cpu_val;
 	unsigned int	 cpu_mask;
+	unsigned long	 __cpu_mmu_flags;	/* used by head-armv.S */
+	unsigned long	 __cpu_flush;		/* used by head-armv.S */
 	const char	 *arch_name;
 	const char	 *elf_name;
 	unsigned int	 elf_hwcap;
@@ -34,7 +38,7 @@
 #endif
 };
 
-#endif
+#endif	/* __ASSEMBLY__ */
 
 #define HWCAP_SWP	1
 #define HWCAP_HALF	2
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/ptrace.h linux/include/asm-arm/ptrace.h
--- v2.3.22/linux/include/asm-arm/ptrace.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/ptrace.h	Wed Oct 20 16:29:08 1999
@@ -3,9 +3,18 @@
 
 #include <asm/proc/ptrace.h>
 
+#ifndef __ASSEMBLY__
+#define pc_pointer(v) \
+	((v) & ~PCMASK)
+
+#define instruction_pointer(regs) \
+	(pc_pointer((regs)->ARM_pc))
+
 #ifdef __KERNEL__
 extern void show_regs(struct pt_regs *);
 #endif
+
+#endif /* __ASSEMBLY__ */
 
 #endif
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.3.22/linux/include/asm-arm/semaphore.h	Fri Sep 10 23:57:36 1999
+++ linux/include/asm-arm/semaphore.h	Wed Oct 20 16:29:08 1999
@@ -5,9 +5,10 @@
 #define __ASM_ARM_SEMAPHORE_H
 
 #include <linux/linkage.h>
-#include <asm/atomic.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+
+#include <asm/atomic.h>
 
 struct semaphore {
 	atomic_t count;
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/setup.h linux/include/asm-arm/setup.h
--- v2.3.22/linux/include/asm-arm/setup.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/setup.h	Wed Oct 20 16:29:08 1999
@@ -1,13 +1,24 @@
 /*
  * include/asm/setup.h
  *
- * Structure passed to kernel to tell it about the hardware it's running on
+ * Structure passed to kernel to tell it about the
+ * hardware it's running on.  See linux/Documentation/arm/Setup
+ * for more info.
  *
- * Copyright (C) 1997,1998 Russell King
+ * Copyright (C) 1997-1999 Russell King
  */
 #ifndef __ASMARM_SETUP_H
 #define __ASMARM_SETUP_H
 
+/*
+ * Usage:
+ *  - do not go blindly adding fields, add them at the end
+ *  - when adding fields, don't rely on the address until
+ *    a patch from me has been released
+ *  - unused fields should be zero (for future expansion)
+ */
+#define COMMAND_LINE_SIZE 1024
+
 struct param_struct {
     union {
 	struct {
@@ -33,6 +44,9 @@
 	    unsigned long initrd_start;		/* 64 */
 	    unsigned long initrd_size;		/* 68 */
 	    unsigned long rd_start;		/* 72 */
+	    unsigned long system_rev;		/* 76 */
+	    unsigned long system_serial_low;	/* 80 */
+	    unsigned long system_serial_high;	/* 84 */
 	} s;
 	char unused[256];
     } u1;
@@ -43,7 +57,7 @@
 	    char n[1024 - sizeof(unsigned long)];
 	} s;
     } u2;
-    char commandline[256];
+    char commandline[COMMAND_LINE_SIZE];
 };
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/shmparam.h linux/include/asm-arm/shmparam.h
--- v2.3.22/linux/include/asm-arm/shmparam.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/shmparam.h	Wed Oct 20 16:29:08 1999
@@ -1,12 +1,6 @@
 #ifndef _ASMARM_SHMPARAM_H
 #define _ASMARM_SHMPARAM_H
 
-/*
- * Include the machine specific shm parameters before the processor
- * dependent parameters so that the machine parameters can override
- * the processor parameters
- */
-#include <asm/arch/shmparam.h>
 #include <asm/proc/shmparam.h>
 
 /*
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/string.h linux/include/asm-arm/string.h
--- v2.3.22/linux/include/asm-arm/string.h	Mon Jul 19 09:52:57 1999
+++ linux/include/asm-arm/string.h	Wed Oct 20 16:29:08 1999
@@ -2,7 +2,8 @@
 #define __ASM_ARM_STRING_H
 
 /*
- * inline versions, hmm...
+ * We don't do inline string functions, since the
+ * optimised inline asm versions are not small.
  */
 
 #define __HAVE_ARCH_STRRCHR
@@ -13,13 +14,25 @@
 
 #define __HAVE_ARCH_MEMCPY
 #define __HAVE_ARCH_MEMMOVE
-#define __HAVE_ARCH_MEMSET
 #define __HAVE_ARCH_MEMCHR
-
 #define __HAVE_ARCH_MEMZERO
-extern void memzero(void *ptr, int n);
+#define __HAVE_ARCH_MEMSET
+
+extern void __memzero(void *ptr, __kernel_size_t n);
+extern void __memset(void *ptr, int v, __kernel_size_t n);
+
+#define memset(p,v,n)							\
+	({								\
+		if ((n) != 0) {						\
+			if (__builtin_constant_p((v)) && (v) == 0)	\
+				__memzero((p),(n));			\
+			else						\
+				__memset((p),(v),(n));			\
+		}							\
+		(p);							\
+	})
 
-extern void memsetl (unsigned long *, unsigned long, int n);
+#define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); })
 
 #endif
  
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.3.22/linux/include/asm-arm/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/system.h	Wed Oct 20 16:29:08 1999
@@ -18,9 +18,15 @@
 #define __netwinder_text
 #endif
 
+/* information about the system we're running on */
+extern unsigned int system_rev;
+extern unsigned int system_serial_low;
+extern unsigned int system_serial_high;
+
 /* The type of machine we're running on */
 extern unsigned int __machine_arch_type;
 
+/* see arch/arm/kernel/setup.c for a description of these */
 #define MACH_TYPE_EBSA110	0
 #define MACH_TYPE_RISCPC	1
 #define MACH_TYPE_NEXUSPCI	3
@@ -32,7 +38,10 @@
 #define MACH_TYPE_CLPS7110	9
 #define MACH_TYPE_ARCHIMEDES	10
 #define MACH_TYPE_A5K		11
-#define MACH_TYPE_SA1100	12	/* not allocated!!! */
+#define MACH_TYPE_ETOILE	12
+#define MACH_TYPE_LACIE_NAS	13
+#define MACH_TYPE_CLPS7500	14
+#define MACH_TYPE_SHARK		15
 
 /*
  * Sort out a definition for machine_arch_type
@@ -127,14 +136,12 @@
 #define tas(ptr) (xchg((ptr),1))
 
 extern void arm_malalignedptr(const char *, void *, volatile void *);
-extern void arm_invalidptr(const char *, int);
 extern asmlinkage void __backtrace(void);
 
 /*
  * Include processor dependent parts
  */
 #include <asm/proc/system.h>
-#include <asm/arch/system.h>
 
 #define mb() __asm__ __volatile__ ("" : : : "memory")
 #define rmb() mb()
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/therm.h linux/include/asm-arm/therm.h
--- v2.3.22/linux/include/asm-arm/therm.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/therm.h	Wed Oct 20 16:29:08 1999
@@ -0,0 +1,28 @@
+/*
+ * linux/include/asm-arm/therm.h: Definitions for Dallas Semiconductor
+ *  DS1620 thermometer driver (as used in the Rebel.com NetWinder)
+ */
+#ifndef __ASM_THERM_H
+#define __ASM_THERM_H
+
+/* ioctl numbers for /dev/therm */
+#define CMD_SET_THERMOSTATE	0x53
+#define CMD_GET_THERMOSTATE	0x54
+#define CMD_GET_STATUS		0x56
+#define CMD_GET_TEMPERATURE	0x57
+#define CMD_SET_THERMOSTATE2	0x58
+#define CMD_GET_THERMOSTATE2	0x59
+#define CMD_GET_TEMPERATURE2	0x5a
+#define CMD_GET_FAN		0x5b
+#define CMD_SET_FAN		0x5c
+
+#define FAN_OFF			0
+#define FAN_ON			1
+#define FAN_ALWAYS_ON		2
+
+struct therm {
+	int hi;
+	int lo;
+};
+
+#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h
--- v2.3.22/linux/include/asm-arm/uaccess.h	Mon Aug 24 12:29:35 1998
+++ linux/include/asm-arm/uaccess.h	Wed Oct 20 16:29:08 1999
@@ -5,6 +5,7 @@
  * User space memory access functions
  */
 #include <linux/sched.h>
+#include <asm/errno.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
@@ -30,11 +31,17 @@
 /* Returns 0 if exception not found and fixup otherwise.  */
 extern unsigned long search_exception_table(unsigned long);
 
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current->addr_limit)
+#define segment_eq(a,b)	((a) == (b))
+
 #include <asm/proc/uaccess.h>
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+#define access_ok(type,addr,size)	(__range_ok(addr,size) == 0)
+
+extern __inline__ int verify_area(int type, const void * addr, unsigned long size)
 {
-	return access_ok(type,addr,size) ? 0 : -EFAULT;
+	return access_ok(type, addr, size) ? 0 : -EFAULT;
 }
 
 /*
@@ -121,12 +128,14 @@
 	return res;
 }
 
-extern __inline__ long strlen_user (const char *s)
+#define strlen_user(s)	strnlen_user(s, ~0UL >> 1)
+
+extern __inline__ long strnlen_user(const char *s, long n)
 {
 	unsigned long res = 0;
 
 	if (__addr_ok(s))
-		__do_strlen_user (s, res);
+		__do_strnlen_user(s, n, res);
 
 	return res;
 }
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/unaligned.h linux/include/asm-arm/unaligned.h
--- v2.3.22/linux/include/asm-arm/unaligned.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/unaligned.h	Wed Oct 20 16:29:08 1999
@@ -1,59 +1,46 @@
-#ifndef __ARM_UNALIGNED_H
-#define __ARM_UNALIGNED_H
+#ifndef __ASM_ARM_UNALIGNED_H
+#define __ASM_ARM_UNALIGNED_H
 
 #define get_unaligned(ptr) \
-	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
+	((__typeof__(*(ptr)))__get_unaligned_size((ptr), sizeof(*(ptr))))
 
 #define put_unaligned(val, ptr) \
-	__put_unaligned((unsigned long)(val), (ptr), sizeof(*(ptr)))
+	__put_unaligned_size((unsigned long)(val), (ptr), sizeof(*(ptr)))
 
-extern void bad_unaligned_access_length (void);
-	
-extern inline unsigned long __get_unaligned(const void *ptr, size_t size)
+/*
+ * We use a similar method to the uaccess.h badness detection.
+ *
+ * These are actually never defined anywhere, and therefore
+ * catch errors at compile/link time.  Don't be tempted to
+ * provide a declaration for them; doing so will mask the
+ * errors.
+ */
+extern unsigned long __get_unaligned_bad(void);
+extern void __put_unaligned_bad(void);
+
+extern __inline__ unsigned long __get_unaligned_size(const void *ptr, size_t size)
 {
-    unsigned long val;
-    switch (size) {
-	case 1:
-	    val = *(const unsigned char *)ptr;
-	    break;
-
-	case 2:
-	    val = ((const unsigned char *)ptr)[0] | (((const unsigned char *)ptr)[1] << 8);
-	    break;
-
-	case 4:
-	    val = ((const unsigned char *)ptr)[0]        | (((const unsigned char *)ptr)[1] << 8) |
-		 (((const unsigned char *)ptr)[2]) << 16 | (((const unsigned char *)ptr)[3] << 24);
-	    break;
-
-	default:
-	    bad_unaligned_access_length ();
-    }
-    return val;
+	const unsigned char *p = (const unsigned char *)ptr;
+	unsigned long val = 0;
+
+	switch (size) {
+	case 4:		val  = p[2] << 16 | p[3] << 24;
+	case 2:		val |= p[1] << 8;
+	case 1:		val |= p[0];				break;
+	default:	val = __get_unaligned_bad();		break;
+	}
+	return val;
 }
 
-extern inline void __put_unaligned(unsigned long val, void *ptr, size_t size)
+extern __inline__ void __put_unaligned_size(unsigned long val, void *ptr, size_t size)
 {
-    switch (size) {
-	case 1:
-	    *(unsigned char *)ptr = val;
-	    break;
-
-	case 2:
-	    ((unsigned char *)ptr)[0] = val;
-	    ((unsigned char *)ptr)[1] = val >> 8;
-	    break;
-
-	case 4:
-	    ((unsigned char *)ptr)[0] = val;
-	    ((unsigned char *)ptr)[1] = val >> 8;
-	    ((unsigned char *)ptr)[2] = val >> 16;
-	    ((unsigned char *)ptr)[3] = val >> 24;
-	    break;
-
-	default:
-	    bad_unaligned_access_length ();
-    }
+	switch (size) {
+	case 4:		((unsigned char *)ptr)[3] = val >> 24;
+			((unsigned char *)ptr)[2] = val >> 16;
+	case 2:		((unsigned char *)ptr)[1] = val >> 8;
+	case 1:		((unsigned char *)ptr)[0] = val;	break;
+	default:	__put_unaligned_bad();			break;
+	}
 }
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.3.22/linux/include/asm-arm/unistd.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/unistd.h	Wed Oct 20 16:29:08 1999
@@ -362,6 +362,7 @@
 
 static inline long close(int fd)
 {
+	extern long sys_close(unsigned int);
 	return sys_close(fd);
 }
 
@@ -397,6 +398,3 @@
 
 #endif
 #endif /* __ASM_ARM_UNISTD_H */
-
-
-
diff -u --recursive --new-file v2.3.22/linux/include/asm-arm/user.h linux/include/asm-arm/user.h
--- v2.3.22/linux/include/asm-arm/user.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/user.h	Wed Oct 20 16:29:08 1999
@@ -42,6 +42,8 @@
 	} fpregs[8];
 	unsigned int fpsr:32;
 	unsigned int fpcr:32;
+	unsigned char ftype[8];
+	unsigned int init_flag;
 };
 
 /* When the kernel dumps core, it starts by dumping the user struct -
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/bigmem.h linux/include/asm-i386/bigmem.h
--- v2.3.22/linux/include/asm-i386/bigmem.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-i386/bigmem.h	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*
- * bigmem.h:	virtual kernel memory mappings for big memory
- *
- * Used in CONFIG_BIGMEM systems for memory pages which	are not
- * addressable by direct kernel virtual adresses.
- *
- * Copyright (C) 1999 Gerhard Wichert, Siemens AG
- *		      Gerhard.Wichert@pdb.siemens.de
- */
-
-#ifndef _ASM_BIGMEM_H
-#define _ASM_BIGMEM_H
-
-#include <linux/init.h>
-
-#define BIGMEM_DEBUG /* undef for production */
-
-/* declarations for bigmem.c */
-extern unsigned long bigmem_start, bigmem_end;
-extern int nr_free_bigpages;
-
-extern pte_t *kmap_pte;
-extern pgprot_t kmap_prot;
-
-extern void kmap_init(void) __init;
-
-/* kmap helper functions necessary to access the bigmem pages in kernel */
-#include <asm/pgtable.h>
-#include <asm/kmap_types.h>
-
-extern inline unsigned long kmap(unsigned long kaddr, enum km_type type)
-{
-	if (__pa(kaddr) < bigmem_start)
-		return kaddr;
-	{
-		enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id();
-		unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN+idx);
-
-#ifdef BIGMEM_DEBUG
-		if (!pte_none(*(kmap_pte-idx)))
-		{
-			__label__ here;
-		here:
-			printk(KERN_ERR "not null pte on CPU %d from %p\n",
-			       smp_processor_id(), &&here);
-		}
-#endif
-		set_pte(kmap_pte-idx, mk_pte(kaddr & PAGE_MASK, kmap_prot));
-		__flush_tlb_one(vaddr);
-
-		return vaddr | (kaddr & ~PAGE_MASK);
-	}
-}
-
-extern inline void kunmap(unsigned long vaddr, enum km_type type)
-{
-#ifdef BIGMEM_DEBUG
-	enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id();
-	if ((vaddr & PAGE_MASK) == __fix_to_virt(FIX_KMAP_BEGIN+idx))
-	{
-		/* force other mappings to Oops if they'll try to access
-		   this pte without first remap it */
-		pte_clear(kmap_pte-idx);
-		__flush_tlb_one(vaddr);
-	}
-#endif
-}
-
-#endif /* _ASM_BIGMEM_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.3.22/linux/include/asm-i386/bugs.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-i386/bugs.h	Fri Oct 22 12:46:18 1999
@@ -236,6 +236,7 @@
  * have the F0 0F bug, which lets nonpriviledged users lock up the system:
  */
 
+#ifndef CONFIG_M686
 extern void trap_init_f00f_bug(void);
 
 static void __init check_pentium_f00f(void)
@@ -250,6 +251,7 @@
 		trap_init_f00f_bug();
 	}
 }
+#endif
 
 /*
  * Perform the Cyrix 5/2 test. A Cyrix won't change
@@ -424,7 +426,9 @@
 	check_hlt();
 	check_popad();
 	check_amd_k6();
+#ifndef CONFIG_M686
 	check_pentium_f00f();
+#endif
 	check_cyrix_coma();
 	system_utsname.machine[1] = '0' + boot_cpu_data.x86;
 }
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/fixmap.h linux/include/asm-i386/fixmap.h
--- v2.3.22/linux/include/asm-i386/fixmap.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-i386/fixmap.h	Fri Oct 22 12:46:20 1999
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <asm/apic.h>
 #include <asm/page.h>
-#ifdef CONFIG_BIGMEM
+#ifdef CONFIG_HIGHMEM
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
 #endif
@@ -34,7 +34,7 @@
  *
  * these 'compile-time allocated' memory buffers are
  * fixed-size 4k pages. (or larger if used with an increment
- * bigger than 1) use fixmap_set(idx,phys) to associate
+ * highger than 1) use fixmap_set(idx,phys) to associate
  * physical memory with fixmap indices.
  *
  * TLB entries of such buffers will not be flushed across
@@ -61,7 +61,7 @@
 	FIX_LI_PCIA,	/* Lithium PCI Bridge A */
 	FIX_LI_PCIB,	/* Lithium PCI Bridge B */
 #endif
-#ifdef CONFIG_BIGMEM
+#ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/highmem.h linux/include/asm-i386/highmem.h
--- v2.3.22/linux/include/asm-i386/highmem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/highmem.h	Fri Oct 22 12:46:21 1999
@@ -0,0 +1,85 @@
+/*
+ * highmem.h: virtual kernel memory mappings for high memory
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual adresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *		      Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with 
+ * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+#ifndef _ASM_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#include <linux/init.h>
+
+/* undef for production */
+#define HIGHMEM_DEBUG 1
+
+/* declarations for highmem.c */
+extern unsigned long highstart_pfn, highend_pfn;
+
+extern pte_t *kmap_pte;
+extern pgprot_t kmap_prot;
+
+extern void kmap_init(void) __init;
+
+/* kmap helper functions necessary to access the highmem pages in kernel */
+#include <asm/pgtable.h>
+#include <asm/kmap_types.h>
+
+extern inline unsigned long kmap(struct page *page, enum km_type type)
+{
+	if (page < highmem_start_page)
+		return page_address(page);
+	{
+		enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id();
+		unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN+idx);
+
+#if HIGHMEM_DEBUG
+		if (!pte_none(*(kmap_pte-idx)))
+		{
+			__label__ here;
+		here:
+			printk(KERN_ERR "not null pte on CPU %d from %p\n",
+			       smp_processor_id(), &&here);
+		}
+#endif
+		set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
+		__flush_tlb_one(vaddr);
+
+		return vaddr;
+	}
+}
+
+extern inline void kunmap(unsigned long vaddr, enum km_type type)
+{
+#if HIGHMEM_DEBUG
+	enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id();
+	if ((vaddr & PAGE_MASK) == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+	{
+		/* force other mappings to Oops if they'll try to access
+		   this pte without first remap it */
+		pte_clear(kmap_pte-idx);
+		__flush_tlb_one(vaddr);
+	}
+#endif
+}
+
+extern inline void kmap_check(void)
+{
+#if HIGHMEM_DEBUG
+	int idx_base = KM_TYPE_NR*smp_processor_id(), i;
+	for (i = idx_base; i < idx_base+KM_TYPE_NR; i++)
+		if (!pte_none(*(kmap_pte-i)))
+			BUG();
+#endif
+}
+#endif /* _ASM_HIGHMEM_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- v2.3.22/linux/include/asm-i386/io.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-i386/io.h	Fri Oct 22 12:46:34 1999
@@ -103,28 +103,32 @@
 #include <linux/vmalloc.h>
 #include <asm/page.h>
 
-#define __io_virt(x)		((void *)(PAGE_OFFSET | (unsigned long)(x)))
-#define __io_phys(x)		((unsigned long)(x) & ~PAGE_OFFSET)
+/*
+ * Temporary debugging check to catch old code using
+ * unmapped ISA addresses. Will be removed in 2.4.
+ */
+#if 1
+  extern void *__io_virt_debug(unsigned long x, const char *file, int line);
+  extern unsigned long __io_phys_debug(unsigned long x, const char *file, int line);
+  #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__)
+//#define __io_phys(x) __io_phys_debug((unsigned long)(x), __FILE__, __LINE__)
+#else
+  #define __io_virt(x) ((void *)(x))
+//#define __io_phys(x) __pa(x)
+#endif
+
 /*
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
  */
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
-#ifdef CONFIG_BIGMEM
 	return __pa(address);
-#else
-	return __io_phys(address);
-#endif
 }
 
 extern inline void * phys_to_virt(unsigned long address)
 {
-#ifdef CONFIG_BIGMEM
 	return __va(address);
-#else
-	return __io_virt(address);
-#endif
 }
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
@@ -176,6 +180,23 @@
 #define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
 #define memcpy_fromio(a,b,c)	memcpy((a),__io_virt(b),(c))
 #define memcpy_toio(a,b,c)	memcpy(__io_virt(a),(b),(c))
+
+/*
+ * ISA space is 'always mapped' on a typical x86 system, no need to
+ * explicitly ioremap() it. The fact that the ISA IO space is mapped
+ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
+ * are physical addresses. The following constant pointer can be
+ * used as the IO-area pointer (it can be iounmapped as well, so the
+ * analogy with PCI is quite large):
+ */
+#define __ISA_IO_base ((char *)(PAGE_OFFSET))
+
+#define isa_readb(a) readb(__ISA_IO_base + (a))
+#define isa_readw(a) readb(__ISA_IO_base + (a))
+#define isa_readl(a) readb(__ISA_IO_base + (a))
+#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a))
+#define isa_writew(w,a) writeb(w,__ISA_IO_base + (a))
+#define isa_writel(l,a) writeb(l,__ISA_IO_base + (a))
 
 /*
  * Again, i386 does not require mem IO specific function.
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v2.3.22/linux/include/asm-i386/page.h	Mon Oct 11 15:38:15 1999
+++ linux/include/asm-i386/page.h	Tue Oct 19 10:22:20 1999
@@ -9,8 +9,6 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-#define STRICT_MM_TYPECHECKS
-
 #include <linux/config.h>
 
 #ifdef CONFIG_X86_USE_3DNOW
@@ -32,13 +30,19 @@
 
 #endif
 
-#ifdef STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
  */
+#if CONFIG_X86_PAE
+typedef struct { unsigned long long pte; } pte_t;
+typedef struct { unsigned long long pmd; } pmd_t;
+typedef struct { unsigned long long pgd; } pgd_t;
+#else
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
+#endif
+
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)	((x).pte)
@@ -51,26 +55,6 @@
 #define __pgd(x)	((pgd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
 
-#else
-/*
- * .. while these make it easier on the compiler
- */
-typedef unsigned long pte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t;
-typedef unsigned long pgprot_t;
-
-#define pte_val(x)	(x)
-#define pmd_val(x)	(x)
-#define pgd_val(x)	(x)
-#define pgprot_val(x)	(x)
-
-#define __pte(x)	(x)
-#define __pmd(x)	(x)
-#define __pgd(x)	(x)
-#define __pgprot(x)	(x)
-
-#endif
 #endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
@@ -83,29 +67,26 @@
  *
  * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
  * a virtual address space of one gigabyte, which limits the
- * amount of physical memory you can use to about 950MB. If
- * you want to use more physical memory, change this define.
- *
- * For example, if you have 2GB worth of physical memory, you
- * could change this define to 0x80000000, which gives the
- * kernel 2GB of virtual memory (enough to most of your physical memory
- * as the kernel needs a bit extra for various io-memory mappings)
- *
- * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
- *
- *	arch/i386/vmlinux.lds
+ * amount of physical memory you can use to about 950MB. 
  *
- * which has the same constant encoded..
+ * If you want more physical memory than this then see the CONFIG_BIGMEM
+ * option in the kernel configuration.
  */
 
-#include <asm/page_offset.h>
-
-#define __PAGE_OFFSET		(PAGE_OFFSET_RAW)
+#define __PAGE_OFFSET		(0xC0000000)
 
 #ifndef __ASSEMBLY__
 
+extern int console_loglevel;
+
+/*
+ * Tell the user there is some problem. Beep too, so we can
+ * see^H^H^Hhear bugs in early bootup as well!
+ */
 #define BUG() do { \
+	__asm__ __volatile__ ("movb $0x3,%al; outb %al,$0x61"); \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	console_loglevel = 0; \
 	__asm__ __volatile__(".byte 0x0f,0x0b"); \
 } while (0)
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/page_offset.h linux/include/asm-i386/page_offset.h
--- v2.3.22/linux/include/asm-i386/page_offset.h	Wed Aug 18 16:43:28 1999
+++ linux/include/asm-i386/page_offset.h	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-#include <linux/config.h>
-#ifdef CONFIG_1GB
-#define PAGE_OFFSET_RAW 0xC0000000
-#elif defined(CONFIG_2GB)
-#define PAGE_OFFSET_RAW 0x80000000
-#elif defined(CONFIG_3GB)
-#define PAGE_OFFSET_RAW 0x40000000
-#endif
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/pgtable-2level.h linux/include/asm-i386/pgtable-2level.h
--- v2.3.22/linux/include/asm-i386/pgtable-2level.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/pgtable-2level.h	Tue Oct 19 10:22:20 1999
@@ -0,0 +1,62 @@
+#ifndef _I386_PGTABLE_2LEVEL_H
+#define _I386_PGTABLE_2LEVEL_H
+
+/*
+ * traditional i386 two-level paging structure:
+ */
+
+#define PGDIR_SHIFT	22
+#define PTRS_PER_PGD	1024
+
+/*
+ * the i386 is two-level, so we don't really have any
+ * PMD directory physically.
+ */
+#define PMD_SHIFT	22
+#define PTRS_PER_PMD	1
+
+#define PTRS_PER_PTE	1024
+
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+extern inline int pgd_none(pgd_t pgd)		{ return 0; }
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+#define pgd_clear(xp)	do { pgd_val(*(xp)) = 0; } while (0)
+
+#define pgd_page(pgd) \
+((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd) { }
+extern __inline__ void free_pmd_slow(pmd_t *pmd) { }
+
+extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+	if (!pgd)
+		BUG();
+	return (pmd_t *) pgd;
+}
+
+#define SWP_ENTRY(type,offset) __pte((((type) << 1) | ((offset) << 8)))
+
+#endif /* _I386_PGTABLE_2LEVEL_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/pgtable-3level.h linux/include/asm-i386/pgtable-3level.h
--- v2.3.22/linux/include/asm-i386/pgtable-3level.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/pgtable-3level.h	Tue Oct 19 10:22:20 1999
@@ -0,0 +1,131 @@
+#ifndef _I386_PGTABLE_3LEVEL_H
+#define _I386_PGTABLE_3LEVEL_H
+
+/*
+ * Intel Physical Address Extension (PAE) Mode - three-level page
+ * tables on PPro+ CPUs.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+/*
+ * PGDIR_SHIFT determines what a top-level page table entry can map
+ */
+#define PGDIR_SHIFT	30
+#define PTRS_PER_PGD	4
+
+/*
+ * PMD_SHIFT determines the size of the area a middle-level
+ * page table can map
+ */
+#define PMD_SHIFT	21
+#define PTRS_PER_PMD	512
+
+/*
+ * entries per page directory level
+ */
+#define PTRS_PER_PTE	512
+
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+	printk("%s:%d: bad pmd %016Lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %016Lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * Subtle, in PAE mode we cannot have zeroes in the top level
+ * page directory, the CPU enforces this.
+ */
+#define pgd_none(x)	(pgd_val(x) == 1ULL)
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return !pgd_none(pgd); }
+/*
+ * Pentium-II errata A13: in PAE mode we explicitly have to flush
+ * the TLB via cr3 if the top-level pgd is changed... This was one tough
+ * thing to find out - guess i should first read all the documentation
+ * next time around ;)
+ */
+extern inline void __pgd_clear (pgd_t * pgd)
+{
+	pgd_val(*pgd) = 1; // no zero allowed!
+}
+
+extern inline void pgd_clear (pgd_t * pgd)
+{
+	__pgd_clear(pgd);
+	__flush_tlb();
+}
+
+#define pgd_page(pgd) \
+((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, address) ((pmd_t *) pgd_page(*(dir)) + \
+			__pmd_offset(address))
+
+extern __inline__ pmd_t *get_pmd_slow(void)
+{
+	pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
+
+	if (ret)
+		memset(ret, 0, PAGE_SIZE);
+	return ret;
+}
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+	unsigned long *ret;
+
+	if ((ret = pmd_quicklist) != NULL) {
+		pmd_quicklist = (unsigned long *)(*ret);
+		ret[0] = 0;
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pmd_slow();
+	return (pmd_t *)ret;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+	*(unsigned long *)pmd = (unsigned long) pmd_quicklist;
+	pmd_quicklist = (unsigned long *) pmd;
+	pgtable_cache_size++;
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+	free_page((unsigned long)pmd);
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+	if (!pgd)
+		BUG();
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = get_pmd_fast();
+
+		if (!page)
+			page = get_pmd_slow();
+		if (page) {
+			if (pgd_none(*pgd)) {
+				pgd_val(*pgd) = 1 + __pa(page);
+				__flush_tlb();
+				return page + address;
+			} else
+				free_pmd_fast(page);
+		} else
+			return NULL;
+	}
+	return (pmd_t *)pgd_page(*pgd) + address;
+}
+
+/*
+ * Subtle. offset can overflow 32 bits and that's a feature - we can do
+ * up to 16 TB swap on PAE. (Not that anyone should need that much
+ * swapspace, but who knows?)
+ */
+#define SWP_ENTRY(type,offset) __pte((((type) << 1) | ((offset) << 8ULL)))
+
+#endif /* _I386_PGTABLE_3LEVEL_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.3.22/linux/include/asm-i386/pgtable.h	Thu Aug 26 13:05:41 1999
+++ linux/include/asm-i386/pgtable.h	Fri Oct 22 12:46:20 1999
@@ -44,7 +44,7 @@
 do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0)
 
 #ifndef CONFIG_X86_INVLPG
-#define __flush_tlb_one(addr) flush_tlb()
+#define __flush_tlb_one(addr) __flush_tlb()
 #else
 #define __flush_tlb_one(addr) \
 __asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
@@ -100,44 +100,50 @@
 	flush_tlb_mm(mm);
 }
 
-
 #endif
 #endif /* !__ASSEMBLY__ */
 
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist (current_cpu_data.pmd_quick)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
 
-/* Certain architectures need to do special things when PTEs
+/*
+ * The Linux x86 paging architecture is 'compile-time dual-mode', it
+ * implements both the traditional 2-level x86 page tables and the
+ * newer 3-level PAE-mode page tables.
+ */
+#ifndef __ASSEMBLY__
+#if CONFIG_X86_PAE
+# include <asm/pgtable-3level.h>
+#else
+# include <asm/pgtable-2level.h>
+#endif
+#endif
+
+/*
+ * Certain architectures need to do special things when PTEs
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
 
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define PMD_SHIFT	22
+#define __beep() asm("movb $0x3,%al; outb %al,$0x61")
+
 #define PMD_SIZE	(1UL << PMD_SHIFT)
 #define PMD_MASK	(~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT	22
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
-/*
- * entries per page directory level: the i386 is two-level, so
- * we don't really have any PMD directory physically.
- */
-#define PTRS_PER_PTE	1024
-#define PTRS_PER_PMD	1
-#define PTRS_PER_PGD	1024
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
-/*
- * pgd entries used up by user/kernel:
- */
-
 #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
 #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-#define __USER_PGD_PTRS ((__PAGE_OFFSET >> PGDIR_SHIFT) & 0x3ff)
-#define __KERNEL_PGD_PTRS (PTRS_PER_PGD-__USER_PGD_PTRS)
+
+#define TWOLEVEL_PGDIR_SHIFT	22
+#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
+#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
+
 
 #ifndef __ASSEMBLY__
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
@@ -166,7 +172,7 @@
 #define _PAGE_PCD	0x010
 #define _PAGE_ACCESSED	0x020
 #define _PAGE_DIRTY	0x040
-#define _PAGE_4M	0x080	/* 4 MB page, Pentium+, if present.. */
+#define _PAGE_PSE	0x080	/* 4 MB (or 2MB) page, Pentium+, if present.. */
 #define _PAGE_GLOBAL	0x100	/* Global TLB entry PPro+ */
 
 #define _PAGE_PROTNONE	0x080	/* If not present */
@@ -213,40 +219,24 @@
 
 /* page table for 0-4MB for everybody */
 extern unsigned long pg0[1024];
-/* zero page used for uninitialized stuff */
-extern unsigned long empty_zero_page[1024];
 
 /*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page))
 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE(vaddr) ((unsigned long) empty_zero_page)
-
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR			(8*sizeof(unsigned long))
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK			(~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-/* 64-bit machines, beware!  SRB. */
-#define SIZEOF_PTR_LOG2			2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+/*
+ * Handling allocation failures during page table setup.
+ */
+extern void __handle_bad_pmd(pmd_t * pmd);
+extern void __handle_bad_pmd_kernel(pmd_t * pmd);
 
 #define pte_none(x)	(!pte_val(x))
 #define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
 #define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
+#define pte_pagenr(x)	((unsigned long)((pte_val(x) >> PAGE_SHIFT)))
 
 #define pmd_none(x)	(!pmd_val(x))
 #define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
@@ -254,14 +244,12 @@
 #define pmd_clear(xp)	do { pmd_val(*(xp)) = 0; } while (0)
 
 /*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-extern inline int pgd_none(pgd_t pgd)		{ return 0; }
-extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
-extern inline int pgd_present(pgd_t pgd)	{ return 1; }
-extern inline void pgd_clear(pgd_t * pgdp)	{ }
+ * Permanent address of a page. Obviously must never be
+ * called on a highmem page.
+ */
+#define page_address(page) ({ if (PageHighMem(page)) BUG(); PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); })
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+#define pte_page(x) (mem_map+pte_pagenr(x))
 
 /*
  * The following only work if pte_present() is true.
@@ -288,8 +276,15 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-#define mk_pte(page, pgprot) \
-({ pte_t __pte; pte_val(__pte) = __pa(page) + pgprot_val(pgprot); __pte; })
+
+extern inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+	pte_t __pte;
+
+	pte_val(__pte) = (page-mem_map)*(unsigned long long)PAGE_SIZE +
+				pgprot_val(pgprot);
+	return __pte;
+}
 
 /* This takes a physical page address that is used by the remapping functions */
 #define mk_pte_phys(physpage, pgprot) \
@@ -298,28 +293,29 @@
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
-#define pte_page(pte) \
-((unsigned long) __va(pte_val(pte) & PAGE_MASK))
+#define page_pte_prot(page,prot) mk_pte(page, prot)
+#define page_pte(page) page_pte_prot(page, __pgprot(0))
 
 #define pmd_page(pmd) \
 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 
-/* to find an entry in a page-table-directory */
-#define pgd_offset(mm, address) \
-((mm)->pgd + ((address) >> PGDIR_SHIFT))
+/* to find an entry in a page-table-directory. */
+#define __pgd_offset(address) \
+		((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+
+#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-/* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
-{
-	return (pmd_t *) dir;
-}
+#define __pmd_offset(address) \
+		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
 
-/* Find an entry in the third-level page table.. */ 
-#define pte_offset(pmd, address) \
-((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
+/* Find an entry in the third-level page table.. */
+#define __pte_offset(address) \
+		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \
+			__pte_offset(address))
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
@@ -327,17 +323,25 @@
  * if any.
  */
 
-#define pgd_quicklist (current_cpu_data.pgd_quick)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (current_cpu_data.pte_quick)
-#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
-
 extern __inline__ pgd_t *get_pgd_slow(void)
 {
 	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
 
 	if (ret) {
+#if 0
+		/*
+		 * On PAE allocating a whole page is overkill - we will
+		 * either embedd this in mm_struct, or do a SLAB cache.
+		 */
+		memcpy(ret, swapper_pg_dir, PTRS_PER_PGD * sizeof(pgd_t));
+#endif
+#if CONFIG_X86_PAE
+		int i;
+		for (i = 0; i < USER_PTRS_PER_PGD; i++)
+			__pgd_clear(ret + i);
+#else
 		memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+#endif
 		memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
 	return ret;
@@ -395,30 +399,15 @@
 	free_page((unsigned long)pte);
 }
 
-/* We don't use pmd cache, so these are dummy routines */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
-}
-
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
-{
-}
-
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pte_kernel(pmd_t *pmd);
-
 #define pte_free_kernel(pte)    free_pte_slow(pte)
-#define pte_free(pte)           free_pte_slow(pte)
-#define pgd_free(pgd)           free_pgd_slow(pgd)
-#define pgd_alloc()             get_pgd_fast()
+#define pte_free(pte)	   free_pte_slow(pte)
+#define pgd_free(pgd)	   free_pgd_slow(pgd)
+#define pgd_alloc()	     get_pgd_fast()
 
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
 {
+	if (!pmd)
+		BUG();
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 	if (pmd_none(*pmd)) {
 		pte_t * page = (pte_t *) get_pte_fast();
@@ -429,7 +418,7 @@
 		return page + address;
 	}
 	if (pmd_bad(*pmd)) {
-		__bad_pte_kernel(pmd);
+		__handle_bad_pmd_kernel(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -437,13 +426,13 @@
 
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
-	address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 
 	if (pmd_none(*pmd))
 		goto getnew;
 	if (pmd_bad(*pmd))
 		goto fix;
-	return (pte_t *) (pmd_page(*pmd) + address);
+	return (pte_t *)pmd_page(*pmd) + address;
 getnew:
 {
 	unsigned long page = (unsigned long) get_pte_fast();
@@ -451,25 +440,19 @@
 	if (!page)
 		return get_pte_slow(pmd, address);
 	pmd_val(*pmd) = _PAGE_TABLE + __pa(page);
-	return (pte_t *) (page + address);
+	return (pte_t *)page + address;
 }
 fix:
-	__bad_pte(pmd);
+	__handle_bad_pmd(pmd);
 	return NULL;
 }
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
+ * (In the PAE case we free the page.)
  */
-extern inline void pmd_free(pmd_t * pmd)
-{
-}
-
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
-{
-	return (pmd_t *) pgd;
-}
+#define pmd_free(pmd)	   free_pmd_slow(pmd)
 
 #define pmd_free_kernel		pmd_free
 #define pmd_alloc_kernel	pmd_alloc
@@ -483,7 +466,7 @@
 #ifdef __SMP__
 	int i;
 #endif	
-        
+
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (!p->mm)
@@ -512,9 +495,8 @@
 {
 }
 
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+#define SWP_TYPE(entry) (((pte_val(entry)) >> 1) & 0x3f)
+#define SWP_OFFSET(entry) ((pte_val(entry)) >> 8)
 
 #define module_map      vmalloc
 #define module_unmap    vfree
@@ -527,4 +509,4 @@
 
 #define io_remap_page_range remap_page_range
 
-#endif /* _I386_PAGE_H */
+#endif /* _I386_PGTABLE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.3.22/linux/include/asm-i386/processor.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-i386/processor.h	Fri Oct 22 12:46:19 1999
@@ -46,6 +46,7 @@
 	int	coma_bug;
 	unsigned long loops_per_sec;
 	unsigned long *pgd_quick;
+	unsigned long *pmd_quick;
 	unsigned long *pte_quick;
 	unsigned long pgtable_cache_sz;
 };
@@ -106,6 +107,12 @@
 #define current_cpu_data boot_cpu_data
 #endif
 
+#define cpu_has_pge \
+		(boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+#define cpu_has_pse \
+		(boot_cpu_data.x86_capability & X86_FEATURE_PSE)
+#define cpu_has_pae \
+		(boot_cpu_data.x86_capability & X86_FEATURE_PAE)
 #define cpu_has_tsc \
 		(cpu_data[smp_processor_id()].x86_capability & X86_FEATURE_TSC)
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.3.22/linux/include/asm-i386/smp.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-i386/smp.h	Fri Oct 22 12:46:20 1999
@@ -166,7 +166,8 @@
  
 extern int smp_found_config;
 extern void init_smp_config(void);
-extern unsigned long smp_alloc_memory(unsigned long mem_base);
+extern void init_smp_mappings(void);
+extern void smp_alloc_memory(void);
 extern unsigned long cpu_present_map;
 extern unsigned long cpu_online_map;
 extern volatile unsigned long smp_invalidate_needed;
@@ -179,6 +180,7 @@
 extern void smp_local_timer_interrupt(struct pt_regs * regs);
 extern void (*mtrr_hook) (void);
 extern void setup_APIC_clocks(void);
+extern void zap_low_mappings (void);
 extern volatile int cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
 extern inline int cpu_logical_map(int cpu)
diff -u --recursive --new-file v2.3.22/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.3.22/linux/include/asm-ppc/machdep.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/machdep.h	Wed Oct 20 22:13:20 1999
@@ -12,8 +12,7 @@
 struct pci_bus;	
 
 struct machdep_calls {
-	void		(*setup_arch)(unsigned long * memory_start_p,
-				unsigned long * memory_end_p);
+	void		(*setup_arch)(void);
 	/* Optional, may be NULL. */
 	int		(*setup_residual)(char *buffer);
 	/* Optional, may be NULL. */
diff -u --recursive --new-file v2.3.22/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.3.22/linux/include/asm-ppc/page.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/page.h	Wed Oct 20 22:13:20 1999
@@ -76,7 +76,7 @@
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-extern void clear_page(unsigned long page);
+extern void clear_page(void *page);
 #define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 
 /* map phys->virtual and virtual->phys for RAM pages */
diff -u --recursive --new-file v2.3.22/linux/include/asm-ppc/pci-bridge.h linux/include/asm-ppc/pci-bridge.h
--- v2.3.22/linux/include/asm-ppc/pci-bridge.h	Tue Apr 14 17:34:00 1998
+++ linux/include/asm-ppc/pci-bridge.h	Wed Oct 20 22:13:20 1999
@@ -1,7 +1,7 @@
 #ifndef _ASM_PCI_BRIDGE_H
 #define _ASM_PCI_BRIDGE_H
 
-unsigned long pmac_find_bridges(unsigned long, unsigned long);
+void pmac_find_bridges(void);
 
 /*
  * pci_io_base returns the memory address at which you can access
diff -u --recursive --new-file v2.3.22/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.22/linux/include/asm-ppc/pgtable.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/pgtable.h	Wed Oct 20 22:13:21 1999
@@ -5,6 +5,7 @@
 
 #ifndef __ASSEMBLY__
 #include <linux/mm.h>
+#include <linux/threads.h>
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -50,7 +51,8 @@
 #define flush_cache_page(vma, p)	do { } while (0)
 
 extern void flush_icache_range(unsigned long, unsigned long);
-extern void flush_page_to_ram(unsigned long);
+extern void __flush_page_to_ram(unsigned long page_va);
+#define flush_page_to_ram(page)	__flush_page_to_ram(page_address(page))
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
@@ -109,6 +111,16 @@
 #define PTRS_PER_PGD	1024
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
 
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
 /*
  * Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 64MB value just means that there will be a 64MB "hole" after the
@@ -126,7 +138,7 @@
  * system.  This really does become a problem for machines with good amounts
  * of RAM.  -- Cort
  */
-#define VMALLOC_OFFSET (0x4000000) /* 64M */
+#define VMALLOC_OFFSET (0x1000000) /* 16M */
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END	ioremap_bot
@@ -216,6 +228,14 @@
 #define __S110	PAGE_SHARED
 #define __S111	PAGE_SHARED
 
+#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page))
+
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
  * BAD_PAGE is used for a bogus page.
@@ -223,15 +243,12 @@
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-#ifndef __ASSEMBLY__
 extern pte_t __bad_page(void);
 extern pte_t * __bad_pagetable(void);
 
-extern unsigned long empty_zero_page[1024];
-#endif __ASSEMBLY__
 #define BAD_PAGETABLE	__bad_pagetable()
 #define BAD_PAGE	__bad_page()
-#define ZERO_PAGE(vaddr)	((unsigned long) empty_zero_page)
+#endif /* __ASSEMBLY__ */
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR	(8*sizeof(unsigned long))
@@ -243,17 +260,24 @@
 /* 64-bit machines, beware!  SRB. */
 #define SIZEOF_PTR_LOG2	2
 
-#ifndef __ASSEMBLY__
-extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
-extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-
-extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != 0; }
-extern inline int pmd_present(pmd_t pmd)	{ return (pmd_val(pmd) & PAGE_MASK) != 0; }
-extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
-
+#define pte_none(pte)		(!pte_val(pte))
+#define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
+#define pte_clear(ptep)		do { pte_val(*(ptep)) = 0; } while (0)
+#define pte_pagenr(x)		((unsigned long)((pte_val(x) >> PAGE_SHIFT)))
+
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define	pmd_bad(pmd)		((pmd_val(pmd) & ~PAGE_MASK) != 0)
+#define	pmd_present(pmd)	((pmd_val(pmd) & PAGE_MASK) != 0)
+#define	pmd_clear(pmdp)		do { pmd_val(*(pmdp)) = 0; } while (0)
+
+/*
+ * Permanent address of a page.
+ */
+#define page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define pages_to_mb(x)		((x) >> (20-PAGE_SHIFT))
+#define pte_page(x)		(mem_map+pte_pagenr(x))
 
+#ifndef __ASSEMBLY__
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -262,7 +286,10 @@
 extern inline int pgd_none(pgd_t pgd)		{ return 0; }
 extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
 extern inline int pgd_present(pgd_t pgd)	{ return 1; }
-extern inline void pgd_clear(pgd_t * pgdp)	{ }
+#define pgd_clear(xp)	do { pgd_val(*(xp)) = 0; } while (0)
+
+#define pgd_page(pgd) \
+	((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
 
 /*
  * The following only work if pte_present() is true.
@@ -313,43 +340,37 @@
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-#if 1
 #define set_pte(pteptr, pteval)	((*(pteptr)) = (pteval))
-#else
-extern inline void set_pte(pte_t *pteptr, pte_t pteval)
-{
-	unsigned long val = pte_val(pteval);
-	extern void xmon(void *);
-
-	if ((val & _PAGE_PRESENT) && ((val < 0x111000 || (val & 0x800)
-	    || ((val & _PAGE_HWWRITE) && (~val & (_PAGE_RW|_PAGE_DIRTY)))) {
-		printk("bad pte val %lx ptr=%p\n", val, pteptr);
-		xmon(0);
-	}
-	*pteptr = pteval;
-}
-#endif
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
 
-static inline pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = (page) | pgprot_val(pgprot); return pte; }
+extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+{
+	pte_t pte;
+	pte_val(pte) = physpage | pgprot_val(pgprot);
+	return pte;
+}
 
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = __pa(page) | pgprot_val(pgprot); return pte; }
+extern inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+	pte_t pte;
+	pte_val(pte) = ((page - mem_map) << PAGE_SHIFT) | pgprot_val(pgprot);
+	return pte;
+}
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline unsigned long pte_page(pte_t pte)
-{ return (unsigned long) __va(pte_val(pte) & PAGE_MASK); }
+{
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	return pte;
+}
 
-extern inline unsigned long pmd_page(pmd_t pmd)
-{ return pmd_val(pmd); }
+#define page_pte_prot(page,prot) mk_pte(page, prot)
+#define page_pte(page)	page_pte_prot(page, __pgprot(0))
 
+#define pmd_page(pmd)	(pmd_val(pmd))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
@@ -418,7 +439,7 @@
 
 extern __inline__ pgd_t *get_pgd_slow(void)
 {
-	pgd_t *ret/* = (pgd_t *)__get_free_page(GFP_KERNEL)*/, *init;
+	pgd_t *ret, *init;
 
 	if ( (ret = (pgd_t *)get_zero_page_fast()) == NULL )
 	{
@@ -427,7 +448,6 @@
 	}
 	if (ret) {
 		init = pgd_offset(&init_mm, 0);
-		/*memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));*/
 		memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
 			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
@@ -612,9 +632,9 @@
 extern void flush_hash_page(unsigned context, unsigned long va);
 
 
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+#define SWP_TYPE(entry) (((pte_val(entry)) >> 1) & 0x7f)
+#define SWP_OFFSET(entry) ((pte_val(entry)) >> 8)
+#define SWP_ENTRY(type,offset) __pte(((type) << 1) | ((offset) << 8))
 
 #define module_map      vmalloc
 #define module_unmap    vfree
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/addrspace.h linux/include/asm-sh/addrspace.h
--- v2.3.22/linux/include/asm-sh/addrspace.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/addrspace.h	Mon Oct 18 11:16:13 1999
@@ -3,39 +3,48 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
- * Copyright (C) 1999 by Niibe Yutaka
+ * Copyright (C) 1999 by Kaz Kojima
  *
  * Defitions for the address spaces of the SH CPUs.
  */
 #ifndef __ASM_SH_ADDRSPACE_H
 #define __ASM_SH_ADDRSPACE_H
 
-/*
- * Memory segments (32bit kernel mode addresses)
- */
-#define KUSEG                   0x00000000
-#define KSEG0                   0x80000000
-#define KSEG1                   0xa0000000
-#define KSEG2                   0xc0000000
-#define KSEG3                   0xe0000000
+/* Memory segments (32bit Priviledged mode addresses)  */
+#define P0SEG		0x00000000
+#define P1SEG		0x80000000
+#define P2SEG		0xa0000000
+#define P3SEG		0xc0000000
+#define P4SEG		0xe0000000
 
-/*
- * Returns the kernel segment base of a given address
- */
-#define KSEGX(a)                (((unsigned long)(a)) & 0xe0000000)
+#if defined(__sh3__)
+/* Should fill here */
+#elif defined(__SH4__)
+/* Detailed P4SEG  */
+#define P4SEG_STORE_QUE	(P4SEG)
+#define P4SEG_IC_ADDR	0xf0000000
+#define P4SEG_IC_DATA	0xf1000000
+#define P4SEG_ITLB_ADDR	0xf2000000
+#define P4SEG_ITLB_DATA	0xf3000000
+#define P4SEG_OC_ADDR	0xf4000000
+#define P4SEG_OC_DATA	0xf5000000
+#define P4SEG_TLB_ADDR	0xf6000000
+#define P4SEG_TLB_DATA	0xf7000000
+#define P4SEG_REG_BASE	0xff000000
+#endif
 
-/*
- * Returns the physical address of a KSEG0/KSEG1 address
- */
-#define PHYSADDR(a)		(((unsigned long)(a)) & 0x1fffffff)
+/* Returns the privileged segment base of a given address  */
+#define PXSEG(a)	(((unsigned long)(a)) & 0xe0000000)
+
+/* Returns the physical address of a PnSEG (n=1,2) address   */
+#define PHYSADDR(a)	(((unsigned long)(a)) & 0x1fffffff)
 
 /*
- * Map an address to a certain kernel segment
+ * Map an address to a certain privileged segment
  */
-#define KSEG0ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG0))
-#define KSEG1ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG1))
-#define KSEG2ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG2))
-#define KSEG3ADDR(a)		((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG3))
+#define P1SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P1SEG))
+#define P2SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P2SEG))
+#define P3SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG))
+#define P4SEGADDR(a)	((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG))
 
 #endif /* __ASM_SH_ADDRSPACE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/atomic.h linux/include/asm-sh/atomic.h
--- v2.3.22/linux/include/asm-sh/atomic.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/atomic.h	Mon Oct 18 11:16:13 1999
@@ -25,7 +25,7 @@
  * on us. We need to use _exactly_ the address the user gave us,
  * not some alias that contains the same information.
  */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
 
 /*
  * To get proper branch prediction for the main line, we must branch
@@ -37,8 +37,7 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*(long *)v += i;
 	restore_flags(flags);
 }
@@ -47,8 +46,7 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*(long *)v -= i;
 	restore_flags(flags);
 }
@@ -57,8 +55,7 @@
 {
 	unsigned long temp, flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	temp = *(long *)v;
 	temp += i;
 	*(long *)v = temp;
@@ -71,8 +68,7 @@
 {
 	unsigned long temp, flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	temp = *(long *)v;
 	temp -= i;
 	*(long *)v = temp;
@@ -90,22 +86,20 @@
 #define atomic_inc(v) atomic_add(1,(v))
 #define atomic_dec(v) atomic_sub(1,(v))
 
-extern __inline__ void atomic_clear_mask(int mask, atomic_t *v)
+extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*(long *)v &= ~mask;
 	restore_flags(flags);
 }
 
-extern __inline__ void atomic_set_mask(int mask, atomic_t *v)
+extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*(long *)v |= mask;
 	restore_flags(flags);
 }
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/bitops.h linux/include/asm-sh/bitops.h
--- v2.3.22/linux/include/asm-sh/bitops.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/bitops.h	Mon Oct 18 11:16:13 1999
@@ -14,8 +14,7 @@
 
 	a += nr >> 5;
 	mask = 1 << (nr & 0x1f);
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*a |= mask;
 	restore_flags(flags);
 }
@@ -28,8 +27,7 @@
 
 	a += nr >> 5;
 	mask = 1 << (nr & 0x1f);
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*a &= ~mask;
 	restore_flags(flags);
 }
@@ -42,8 +40,7 @@
 
 	a += nr >> 5;
 	mask = 1 << (nr & 0x1f);
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	*a ^= mask;
 	restore_flags(flags);
 }
@@ -56,8 +53,7 @@
 
 	a += nr >> 5;
 	mask = 1 << (nr & 0x1f);
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	retval = (mask & *a) != 0;
 	*a |= mask;
 	restore_flags(flags);
@@ -73,8 +69,7 @@
 
 	a += nr >> 5;
 	mask = 1 << (nr & 0x1f);
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	retval = (mask & *a) != 0;
 	*a &= ~mask;
 	restore_flags(flags);
@@ -90,8 +85,7 @@
 
 	a += nr >> 5;
 	mask = 1 << (nr & 0x1f);
-	save_flags(flags);
-	cli();
+	save_and_cli(flags);
 	retval = (mask & *a) != 0;
 	*a ^= mask;
 	restore_flags(flags);
@@ -112,7 +106,7 @@
 	__asm__("1:\n"
 		"shlr	%1\n\t"
 		"bt/s	1b\n\t"
-		"add	#1, %0"
+		" add	#1, %0"
 		: "=r" (result)
 		: "r" (word), "0" (~0L));
 	return result;
@@ -165,7 +159,7 @@
 
 	ADDR += nr >> 3;
 	mask = 1 << (nr & 0x07);
-	save_flags(flags); cli();
+	save_and_cli(flags);
 	retval = (mask & *ADDR) != 0;
 	*ADDR |= mask;
 	restore_flags(flags);
@@ -180,7 +174,7 @@
 
 	ADDR += nr >> 3;
 	mask = 1 << (nr & 0x07);
-	save_flags(flags); cli();
+	save_and_cli(flags);
 	retval = (mask & *ADDR) != 0;
 	*ADDR &= ~mask;
 	restore_flags(flags);
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h
--- v2.3.22/linux/include/asm-sh/bugs.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-sh/bugs.h	Mon Oct 18 11:16:13 1999
@@ -16,5 +16,23 @@
 
 static void __init check_bugs(void)
 {
+	extern unsigned long loops_per_sec;
+
+	cpu_data->loops_per_sec = loops_per_sec;
+	
+	switch (cpu_data->type) {
+	case CPU_SH7708:
+		printk("CPU: SH7708/SH7709\n");
+		break;
+	case CPU_SH7729:
+		printk("CPU: SH7709A/SH7729\n");
+		break;
+	case CPU_SH7750:
+		printk("CPU: SH7750\n");
+		break;
+	default:
+		printk("CPU: ??????\n");
+		break;
+	}
 }
 #endif /* __ASM_SH_BUGS_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/byteorder.h linux/include/asm-sh/byteorder.h
--- v2.3.22/linux/include/asm-sh/byteorder.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/byteorder.h	Mon Oct 18 11:16:13 1999
@@ -5,7 +5,6 @@
  * Copyright (C) 1999  Niibe Yutaka
  */
 
-#include <linux/config.h>
 #include <asm/types.h>
 
 static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
@@ -34,7 +33,7 @@
 #  define __SWAB_64_THRU_32__
 #endif
 
-#ifdef CONFIG_LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN__
 #include <linux/byteorder/little_endian.h>
 #else
 #include <linux/byteorder/big_endian.h>
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/cache.h linux/include/asm-sh/cache.h
--- v2.3.22/linux/include/asm-sh/cache.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/cache.h	Mon Oct 18 11:16:13 1999
@@ -6,7 +6,11 @@
 #define __ASM_SH_CACHE_H
 
 /* bytes per L1 cache line */
+#if defined(__sh3__)
 #define        L1_CACHE_BYTES  16
+#elif defined(__SH4__)
+#define        L1_CACHE_BYTES  32
+#endif
 
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
@@ -19,5 +23,9 @@
   __attribute__((__aligned__(L1_CACHE_BYTES),			\
 		 __section__(".data.cacheline_aligned")))
 #endif
+
+extern void cache_flush_area(unsigned long start, unsigned long end);
+extern void cache_purge_area(unsigned long start, unsigned long end);
+extern void cache_wback_area(unsigned long start, unsigned long end);
 
 #endif /* __ASM_SH_CACHE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/checksum.h linux/include/asm-sh/checksum.h
--- v2.3.22/linux/include/asm-sh/checksum.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/checksum.h	Mon Oct 18 11:16:13 1999
@@ -1,22 +1,13 @@
 #ifndef __ASM_SH_CHECKSUM_H
 #define __ASM_SH_CHECKSUM_H
 
-
-/*
- *	This is a version of ip_compute_csum() optimized for IP headers,
- *	which always checksum on 4 octet boundaries.
- */
-extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
-
 /*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
+ * 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 by Kaz Kojima & Niibe Yutaka
  */
-extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
-					   unsigned long daddr,
-					   unsigned short len,
-					   unsigned short proto,
-					   unsigned int sum);
 
 /*
  * computes the checksum of a memory block at buff, length len,
@@ -30,55 +21,220 @@
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
 
 /*
  * the same as csum_partial, but copies from src while it
- * checksums
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum);
+
+asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+						   int *src_err_ptr, int *dst_err_ptr);
 
 /*
- * the same as csum_partial, but copies from user space (but on the alpha
- * we have just one address space, so this is identical to the above)
+ *	Note: when you get a NULL pointer exception here this means someone
+ *	passed in an incorrect kernel address to one of these functions. 
+ *	
+ *	If you use these functions directly please don't forget the 
+ *	verify_area().
+ */
+extern __inline__
+unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+					int len, int sum)
+{
+	return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+}
+
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+						int len, int sum, int *err_ptr)
+{
+	return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+}
+
+#if 0
+
+/* Not used at the moment. It is difficult to imagine for what purpose
+   it can be used :-) Please, do not forget to verify_area before it --ANK
+ */
+
+/*
+ * This combination is currently not used, but possible:
+ */
+
+extern __inline__
+unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
+					int len, int sum, int *err_ptr)
+{
+	return csum_partial_copy_generic ( src, dst, len, sum, NULL, err_ptr);
+}
+#endif
+
+/*
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
  *
- * this is obsolete and will go away.
+ * these functions should go away after some time.
  */
+
 #define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
 
 /*
- * this is a new version of the above that records errors it finds in *errp,
- * but continues and zeros the rest of the buffer.
+ *	Fold a partial checksum
  */
-unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
+
+static __inline__ unsigned int csum_fold(unsigned int sum)
+{
+	unsigned int __dummy;
+	__asm__("clrt\n\t"
+		"mov	%0,%1\n\t"
+		"shll16	%0\n\t"
+		"addc	%0,%1\n\t"
+		"movt	%0\n\t"
+		"shlr16	%1\n\t"
+		"add	%1,%0"
+		: "=r" (sum), "=&r" (__dummy)
+		: "0" (sum));
+	return ~sum;
+}
 
 /*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ *
+ *      i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted
+ *      for linux by * Arnt Gulbrandsen.
  */
+static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+	unsigned int sum, __dummy;
+
+	__asm__ __volatile__(
+		"mov.l	@%1+,%0\n\t"
+		"add	#-4,%2\n\t"
+		"clrt\n\t"
+		"mov.l	@%1+,%3\n\t"
+		"addc	%3,%0\n\t"
+		"mov.l	@%1+,%3\n\t"
+		"addc	%3,%0\n\t"
+		"mov.l	@%1+,%3\n\t"
+		"addc	%3,%0\n"
+		"1:\t"
+		"mov.l	@%1+,%3\n\t"
+		"addc	%3,%0\n\t"
+		"movt	%3\n\t"
+		"dt	%2\n\t"
+		"bf/s	1b\n\t"
+		" cmp/eq #1,%3\n\t"
+		"mov	#0,%3\n\t"
+		"addc	%3,%0\n\t"
+	/* Since the input registers which are loaded with iph and ihl
+	   are modified, we must also specify them as outputs, or gcc
+	   will assume they contain their original values. */
+	: "=r" (sum), "=r" (iph), "=r" (ihl), "=&z" (__dummy)
+	: "1" (iph), "2" (ihl));
+
+	return	csum_fold(sum);
+}
 
-extern unsigned short ip_compute_csum(unsigned char * buff, int len);
+static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
+						   unsigned long daddr,
+						   unsigned short len,
+						   unsigned short proto,
+						   unsigned int sum) 
+{
+#ifdef __LITTLE_ENDIAN__
+	unsigned long len_proto = (ntohs(len)<<16)+proto*256;
+#else
+	unsigned long len_proto = (proto<<16)+len;
+#endif
+	__asm__("clrt\n\t"
+		"addc	%0,%1\n\t"
+		"addc	%2,%1\n\t"
+		"addc	%3,%1\n\t"
+		"movt	%0\n\t"
+		"add	%1,%0"
+		: "=r" (sum), "=r" (len_proto)
+		: "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
+	return sum;
+}
 
 /*
- *	Fold a partial checksum without adding pseudo headers
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
  */
+static __inline__ unsigned short int csum_tcpudp_magic(unsigned long saddr,
+						       unsigned long daddr,
+						       unsigned short len,
+						       unsigned short proto,
+						       unsigned int sum) 
+{
+	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
 
-static inline unsigned short csum_fold(unsigned int sum)
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
 {
-	sum = (sum & 0xffff) + (sum >> 16);
-	sum = (sum & 0xffff) + (sum >> 16);
-	return ~sum;
+    return csum_fold (csum_partial(buff, len, 0));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
-/*
-extern unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
-                                          struct in6_addr *daddr,
-                                          __u16 len,
-                                          unsigned short proto,
-                                          unsigned int sum);
-*/
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+						     struct in6_addr *daddr,
+						     __u16 len,
+						     unsigned short proto,
+						     unsigned int sum) 
+{
+	unsigned int __dummy;
+	__asm__("clrt\n\t"
+		"mov.l	@(0,%2),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(4,%2),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(8,%2),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(12,%2),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(0,%3),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(4,%3),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(8,%3),%1\n\t"
+		"addc	%1,%0\n\t"
+		"mov.l	@(12,%3),%1\n\t"
+		"addc	%1,%0\n\t"
+		"addc	%4,%0\n\t"
+		"addc	%5,%0\n\t"
+		"movt	%1\n\t"
+		"add	%1,%0\n"
+		: "=r" (sum), "=&r" (__dummy)
+		: "r" (saddr), "r" (daddr), 
+		  "r" (htonl((__u32) (len))), "r" (htonl(proto)), "0" (sum));
+
+	return csum_fold(sum);
+}
+
+/* 
+ *	Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+				    int len, int sum, int *err_ptr)
+{
+	if (access_ok(VERIFY_WRITE, dst, len))
+		return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+	if (len)
+		*err_ptr = -EFAULT;
+
+	return -1; /* invalid checksum */
+}
 #endif /* __ASM_SH_CHECKSUM_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/delay.h linux/include/asm-sh/delay.h
--- v2.3.22/linux/include/asm-sh/delay.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/delay.h	Mon Oct 18 11:16:13 1999
@@ -2,26 +2,26 @@
 #define __ASM_SH_DELAY_H
 
 /*
- * Copyright (C) 1999  Niibe Yutaka
+ * Copyright (C) 1999  Kaz Kojima
  */
 
 extern __inline__ void __delay(unsigned long loops)
 {
-	unsigned long __dummy;
 	__asm__ __volatile__(
- 		"1:\t"
-		"dt	%0\n\t"
-		"bf	1b"
-		:"=r" (__dummy)
-		:"0" (loops));
+		"tst	%0,%0\n\t"
+		"1:\t"
+		"bf/s	1b\n\t"
+		" dt	%0"
+		: "=r" (loops)
+		: "0" (loops));
 }
 
 extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
 {
 	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
-	__asm__("mul.l	%0,%2\n\t"
-		"sts	macl,%0"
-		: "=&r" (usecs)
+	__asm__("dmulu.l	%0,%2\n\t"
+		"sts	mach,%0"
+		: "=r" (usecs)
 		: "0" (usecs), "r" (lps)
 		: "macl", "mach");
         __delay(usecs);
@@ -35,10 +35,5 @@
 #endif
 
 #define udelay(usecs) __udelay((usecs),__udelay_val)
-
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
-{
-	return (a*b)/c;
-}
 
 #endif /* __ASM_SH_DELAY_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/elf.h linux/include/asm-sh/elf.h
--- v2.3.22/linux/include/asm-sh/elf.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-sh/elf.h	Mon Oct 18 11:16:13 1999
@@ -5,7 +5,6 @@
  * ELF register definitions..
  */
 
-#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <asm/byteorder.h>
@@ -15,12 +14,10 @@
 #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
-#ifdef CONFIG_CPU_SH4
+/* Though SH-3 has no floating point regs.. */
+#define ELF_NFPREG 34
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-#else /* SH 3 has no floating point regs */
-typedef struct { void *null; } elf_fpregset_t;
-#endif
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -31,7 +28,7 @@
  * These are used to set parameters in the core dumps.
  */
 #define ELF_CLASS	ELFCLASS32
-#ifdef __LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN__
 #define ELF_DATA	ELFDATA2LSB
 #else
 #define ELF_DATA	ELFDATA2MSB
@@ -67,6 +64,12 @@
    but that could change... */
 
 #define ELF_PLATFORM  (NULL)
+
+#define ELF_PLAT_INIT(_r) \
+  do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
+       _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \
+       _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \
+       _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; } while (0)
 
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) \
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/hardirq.h linux/include/asm-sh/hardirq.h
--- v2.3.22/linux/include/asm-sh/hardirq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/hardirq.h	Mon Oct 18 11:16:13 1999
@@ -14,7 +14,7 @@
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
 #define hardirq_exit(cpu)	(local_irq_count[cpu]--)
 
-#define synchronize_irq()	do { } while (0)
+#define synchronize_irq()	barrier()
 
 #else
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/hdreg.h linux/include/asm-sh/hdreg.h
--- v2.3.22/linux/include/asm-sh/hdreg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/hdreg.h	Mon Oct 18 11:16:13 1999
@@ -0,0 +1,12 @@
+/*
+ *  linux/include/asm-sh/hdreg.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+#ifndef __ASM_SH_HDREG_H
+#define __ASM_SH_HDREG_H
+
+typedef unsigned short ide_ioreg_t;
+
+#endif /* __ASM_SH_HDREG_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h
--- v2.3.22/linux/include/asm-sh/ide.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/ide.h	Mon Oct 18 11:16:13 1999
@@ -0,0 +1,112 @@
+/*
+ *  linux/include/asm-sh/ide.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the i386 architecture specific IDE code.
+ *  In future, SuperH code.
+ */
+
+#ifndef __ASM_SH_IDE_H
+#define __ASM_SH_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+#define MAX_HWIFS	10
+#endif
+
+#define ide__sti()	__sti()
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 14;
+		case 0x170: return 15;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		case 0x1e0: return 8;
+		case 0x160: return 12;
+		default:
+			return 0;
+	}
+}
+
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0:	return 0x1f0;
+		case 1:	return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		case 4: return 0x1e0;
+		case 5: return 0x160;
+		default:
+			return 0;
+	}
+}
+
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+}
+
+static __inline__ void ide_init_default_hwifs(void)
+{
+#ifndef CONFIG_BLK_DEV_IDEPCI
+	hw_regs_t hw;
+	int index;
+
+	for(index = 0; index < MAX_HWIFS; index++) {
+		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+		hw.irq = ide_default_irq(ide_default_io_base(index));
+		ide_register_hw(&hw, NULL);
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+}
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned head		: 4;	/* always zeros here */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit7		: 1;	/* always 1 */
+	} b;
+	} select_t;
+
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_fix_driveid(id)		do {} while (0)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_IDE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/io.h linux/include/asm-sh/io.h
--- v2.3.22/linux/include/asm-sh/io.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/io.h	Mon Oct 18 11:16:13 1999
@@ -1,6 +1,18 @@
 #ifndef __ASM_SH_IO_H
 #define __ASM_SH_IO_H
-/* XXXXXXXXXXXXXXXXX */
+
+/*
+ * Convention:
+ *    read{b,w,l}/write{b,w,l} are for PCI,
+ *    while in{b,w,l}/out{b,w,l} are for ISA
+ * These may (will) be platform specific function.
+ *
+ * In addition, we have 
+ *   ctrl_in{b,w,l}/ctrl_out{b,w,l} for SuperH specific I/O.
+ *   which are processor specific.
+ */
+
+#include <asm/cache.h>
 
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
@@ -20,7 +32,7 @@
        return *(volatile unsigned long*)addr;
 }
 
-extern __inline__ void writeb(unsigned short b, unsigned long addr)
+extern __inline__ void writeb(unsigned char b, unsigned long addr)
 {
        *(volatile unsigned char*)addr = b;
 }
@@ -75,6 +87,36 @@
        return writel(b,addr);
 }
 
+extern __inline__ unsigned long ctrl_inb(unsigned long addr)
+{
+       return *(volatile unsigned char*)addr;
+}
+
+extern __inline__ unsigned long ctrl_inw(unsigned long addr)
+{
+       return *(volatile unsigned short*)addr;
+}
+
+extern __inline__ unsigned long ctrl_inl(unsigned long addr)
+{
+       return *(volatile unsigned long*)addr;
+}
+
+extern __inline__ void ctrl_outb(unsigned char b, unsigned long addr)
+{
+       *(volatile unsigned char*)addr = b;
+}
+
+extern __inline__ void ctrl_outw(unsigned short b, unsigned long addr)
+{
+       *(volatile unsigned short*)addr = b;
+}
+
+extern __inline__ void ctrl_outl(unsigned int b, unsigned long addr)
+{
+        *(volatile unsigned long*)addr = b;
+}
+
 #define inb_p inb
 #define outb_p outb
 
@@ -93,7 +135,7 @@
 
 extern __inline__ void * phys_to_virt(unsigned long address)
 {
-	return (void *)KSEG0ADDR(address);
+	return (void *)P1SEGADDR(address);
 }
 
 extern void * ioremap(unsigned long phys_addr, unsigned long size);
@@ -115,7 +157,7 @@
  */
 extern __inline__ void * ioremap(unsigned long offset, unsigned long size)
 {
-	return (void *) KSEG1ADDR(offset);
+	return (void *) P2SEGADDR(offset);
 }
 
 /*
@@ -125,7 +167,7 @@
  */
 extern __inline__ void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
-	return (void *) KSEG1ADDR(offset);
+	return (void *) P2SEGADDR(offset);
 }
 
 extern __inline__ void iounmap(void *addr)
@@ -148,11 +190,30 @@
 	return retval;
 }
 
-/* Nothing to do */
+/*
+ * The caches on some architectures aren't dma-coherent and have need to
+ * handle this in software.  There are three types of operations that
+ * can be applied to dma buffers.
+ *
+ *  - dma_cache_wback_inv(start, size) makes caches and RAM coherent by
+ *    writing the content of the caches back to memory, if necessary.
+ *    The function also invalidates the affected part of the caches as
+ *    necessary before DMA transfers from outside to memory.
+ *  - dma_cache_inv(start, size) invalidates the affected parts of the
+ *    caches.  Dirty lines of the caches may be written back or simply
+ *    be discarded.  This operation is necessary before dma operations
+ *    to the memory.
+ *  - dma_cache_wback(start, size) writes back any dirty lines but does
+ *    not invalidate the cache.  This can be used before DMA reads from
+ *    memory,
+ */
 
-#define dma_cache_inv(_start,_size)		do { } while (0)
-#define dma_cache_wback(_start,_size)		do { } while (0)
-#define dma_cache_wback_inv(_start,_size)	do { } while (0)
+#define dma_cache_wback_inv(_start,_size) \
+    cache_flush_area((unsigned long)(_start),((unsigned long)(_start)+(_size)))
+#define dma_cache_inv(_start,_size) \
+    cache_purge_area((unsigned long)(_start),((unsigned long)(_start)+(_size)))
+#define dma_cache_wback(_start,_size) \
+    cache_wback_area((unsigned long)(_start),((unsigned long)(_start)+(_size)))
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_SH_IO_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/ioctl.h linux/include/asm-sh/ioctl.h
--- v2.3.22/linux/include/asm-sh/ioctl.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/ioctl.h	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl.h,v 1.5 1993/07/19 21:53:50 root Exp root $
+/* $Id: ioctl.h,v 1.1 1999/09/18 17:29:53 gniibe Exp $
  *
  * linux/ioctl.h for Linux by H.H. Bergman.
  */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/ioctls.h linux/include/asm-sh/ioctls.h
--- v2.3.22/linux/include/asm-sh/ioctls.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/ioctls.h	Mon Oct 18 11:16:13 1999
@@ -39,9 +39,9 @@
 
 #define TIOCSTI		_IOW('T', 18, char) /* 0x5412 */
 #define TIOCMGET	_IOR('T', 21, unsigned int) /* 0x5415 */
-#define TIOCMBIS	_IOW('T', 22, unsigne int) /* 0x5416 */
-#define TIOCMBIC	_IOW('T', 23, unsigne int) /* 0x5417 */
-#define TIOCMSET	_IOW('T', 24, unsigne int) /* 0x5418 */
+#define TIOCMBIS	_IOW('T', 22, unsigned int) /* 0x5416 */
+#define TIOCMBIC	_IOW('T', 23, unsigned int) /* 0x5417 */
+#define TIOCMSET	_IOW('T', 24, unsigned int) /* 0x5418 */
 # define TIOCM_LE	0x001
 # define TIOCM_DTR	0x002
 # define TIOCM_RTS	0x004
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/irq.h linux/include/asm-sh/irq.h
--- v2.3.22/linux/include/asm-sh/irq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/irq.h	Mon Oct 18 11:16:13 1999
@@ -14,13 +14,13 @@
 #define TIMER_PRIORITY		 1
 
 /*
- * 40 = 24+16
+ * 48 = 32+16
  *
- * 24 for on chip support modules.
+ * 32 for on chip support modules.
  * 16 for external interrupts.
  *
  */
-#define NR_IRQS	40
+#define NR_IRQS	48
 
 extern void disable_irq(unsigned int);
 extern void disable_irq_nosync(unsigned int);
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/mmu_context.h linux/include/asm-sh/mmu_context.h
--- v2.3.22/linux/include/asm-sh/mmu_context.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/mmu_context.h	Mon Oct 18 11:16:13 1999
@@ -24,6 +24,8 @@
 extern __inline__ void
 get_new_mmu_context(struct mm_struct *mm)
 {
+	extern void flush_tlb_all(void);
+
 	unsigned long mc = ++mmu_context_cache;
 
 	if (!(mc & MMU_CONTEXT_ASID_MASK)) {
@@ -38,7 +40,7 @@
 	mm->context = mc;
 }
 
-/*P
+/*
  * Get MMU context if needed.
  */
 extern __inline__ void
@@ -53,7 +55,7 @@
 	}
 }
 
-/*P
+/*
  * Initialize the context related info for a new mm_struct
  * instance.
  */
@@ -63,7 +65,7 @@
 	mm->context = NO_CONTEXT;
 }
 
-/*P
+/*
  * Destroy context related info for an mm_struct that is about
  * to be put to rest.
  */
@@ -74,18 +76,35 @@
 
 /* Other MMU related constants. */
 
+#if defined(__sh3__)
 #define MMU_PTEH	0xFFFFFFF0	/* Page table entry register HIGH */
 #define MMU_PTEL	0xFFFFFFF4	/* Page table entry register LOW */
+#define MMU_TTB		0xFFFFFFF8	/* Translation table base register */
+#define MMU_TEA		0xFFFFFFFC	/* TLB Exception Address */
+
 #define MMUCR		0xFFFFFFE0	/* MMU Control Register */
 
 #define MMU_TLB_ADDRESS_ARRAY 0xF2000000
 #define MMU_PAGE_ASSOC_BIT 0x80
 
 #define MMU_NTLB_ENTRIES       128	/* for 7708 */
-
 #define MMU_CONTROL_INIT 0x007	/* SV=0, TF=1, IX=1, AT=1 */
 
-#include <asm/uaccess.h> /* to get the definition of  __m */
+#elif defined(__SH4__)
+#define MMU_PTEH	0xFF000000	/* Page table entry register HIGH */
+#define MMU_PTEL	0xFF000004	/* Page table entry register LOW */
+#define MMU_TTB		0xFF000008	/* Translation table base register */
+#define MMU_TEA		0xFF00000C	/* TLB Exception Address */
+
+#define MMUCR		0xFF000010	/* MMU Control Register */
+
+#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000
+#define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
+#define MMU_PAGE_ASSOC_BIT 0x80
+
+#define MMU_NTLB_ENTRIES       64	/* for 7750 */
+#define MMU_CONTROL_INIT 0x205	/* SQMD=1, SV=0, TI=1, AT=1 */
+#endif
 
 extern __inline__ void set_asid (unsigned long asid)
 {
@@ -105,7 +124,7 @@
 	return asid;
 }
 
-/*P
+/*
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
@@ -117,7 +136,6 @@
 
 /* MMU_TTB can be used for optimizing the fault handling.
    (Currently not used) */
-#define MMU_TTB   0xFFFFFFF8	/* Translation table base register */
 extern __inline__ void switch_mm(struct mm_struct *prev,
 				 struct mm_struct *next,
 				 struct task_struct *tsk, unsigned int cpu)
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/namei.h linux/include/asm-sh/namei.h
--- v2.3.22/linux/include/asm-sh/namei.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/namei.h	Mon Oct 18 11:16:13 1999
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
+/* $Id: namei.h,v 1.1 1999/09/18 17:30:11 gniibe Exp $
  * linux/include/asm-sh/namei.h
  *
  * Included from linux/fs/namei.c
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/page.h linux/include/asm-sh/page.h
--- v2.3.22/linux/include/asm-sh/page.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/page.h	Mon Oct 18 11:16:13 1999
@@ -5,12 +5,12 @@
  * Copyright (C) 1999  Niibe Yutaka
  */
 
-/* XXX 
-   [ P0 (virtual) ]               0x00000000     <------ User space
-   [ P1 (fixed)  write-through]   0x80000000     <------ Kernel space
-   [ P2 (fixed)  non-cachable]    0xA0000000     <------ Physical access
-   [ P3 (virtual) write-back]     0xC0000000     <------ not used
-   [ P4 control   ]               0xE0000000
+/*
+   [ P0/U0 (virtual) ]		0x00000000     <------ User space
+   [ P1 (fixed)   cached ]	0x80000000     <------ Kernel space
+   [ P2 (fixed)  non-cachable]	0xA0000000     <------ Physical access
+   [ P3 (virtual) cached]	0xC0000000     <------ not used
+   [ P4 control   ]		0xE0000000
  */
 
 #include <linux/config.h>
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- v2.3.22/linux/include/asm-sh/pgtable.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/pgtable.h	Mon Oct 18 11:16:13 1999
@@ -3,19 +3,18 @@
 
 /* Copyright (C) 1999 Niibe Yutaka */
 
-#include <linux/config.h>
-
 /*
  * This file contains the functions and defines necessary to modify and use
  * the SuperH page table tree.
  */
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
+#include <asm/addrspace.h>
 #include <linux/threads.h>
 
 extern pgd_t swapper_pg_dir[1024];
 
-#ifdef CONFIG_CPU_SH3
+#if defined(__sh3__)
 /* Cache flushing:
  *
  *  - flush_cache_all() flushes entire cache
@@ -33,17 +32,17 @@
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
-#elif CONFIG_CPU_SH4
+#elif defined(__SH4__)
 /*
  *  Caches are broken on SH-4, so we need them.
- *  You do bad job!
  */
-flush_cache_all()
-flush_cache_mm(mm)
-flush_cache_range(mm, start, end)
-flush_cache_page(vma, vmaddr)
-flush_page_to_ram(page)
-flush_icache_range(start, end)
+extern void flush_cache_all(void);
+extern void flush_cache_mm(struct mm_struct *mm);
+extern void flush_cache_range(struct mm_struct *mm, unsigned long start,
+			      unsigned long end);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_page_to_ram(unsigned long page);
+extern void flush_icache_range(unsigned long start, unsigned long end);
 #endif
 
 /* TLB flushing:
@@ -86,9 +85,9 @@
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
 #ifndef __ASSEMBLY__
-#define VMALLOC_START	0xc0000000
+#define VMALLOC_START	P3SEG
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END	0xe0000000
+#define VMALLOC_END	P4SEG
 
 #define _PAGE_READ 	0x001  /* software: read access alowed */
 #define _PAGE_ACCESSED	0x002  /* software: page referenced */
@@ -100,11 +99,17 @@
 /*		 	0x080  */
 #define _PAGE_PRESENT	0x100  /* V-bit   : page is valid */
 
+#if defined(__sh3__)
 /* Mask which drop software flags */
-#define _PAGE_FLAGS_HARDWARE_MASK	0xfffff164
+#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff164
 /* Flags defalult: SZ=1 (4k-byte), C=1 (cachable), SH=0 (not shared) */
 #define _PAGE_FLAGS_HARDWARE_DEFAULT	0x00000018
-
+#elif defined(__SH4__)
+/* Mask which drops software flags */
+#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff164
+/* Flags defalult: SZ=01 (4k-byte), C=1 (cachable), SH=0 (not shared), WT=0 */
+#define _PAGE_FLAGS_HARDWARE_DEFAULT	0x00000018
+#endif
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/processor.h linux/include/asm-sh/processor.h
--- v2.3.22/linux/include/asm-sh/processor.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/processor.h	Mon Oct 18 11:16:13 1999
@@ -20,9 +20,20 @@
 /*
  *  CPU type and hardware bug flags. Kept separately for each CPU.
  */
+enum cpu_type {
+	CPU_SH7708,		/* Represents 7708, 7708S, 7708R, 7709 */
+	CPU_SH7729,		/* Represents 7709A, 7729 */
+	CPU_SH7750,
+	CPU_SH_NONE
+};
 
 struct sh_cpuinfo {
+	enum cpu_type type;
 	unsigned long loops_per_sec;
+
+	char	hard_math;
+
+	/* Not yet used */
 	unsigned long *pgd_quick;
 	unsigned long *pte_quick;
 	unsigned long pgtable_cache_sz;
@@ -30,7 +41,7 @@
 
 extern struct sh_cpuinfo boot_cpu_data;
 
-#define cpu_data &boot_cpu_data
+#define cpu_data (&boot_cpu_data)
 #define current_cpu_data boot_cpu_data
 
 /*
@@ -43,6 +54,33 @@
  */
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
+#define NUM_FPU_REGS	16
+
+struct sh_fpu_hard_struct {
+	unsigned long fp_regs[NUM_FPU_REGS];
+	unsigned long xf_regs[NUM_FPU_REGS];
+	unsigned long fpscr;
+	unsigned long fpul;
+
+	long status; /* software status information */
+};
+
+/* Dummy fpu emulator  */
+struct sh_fpu_soft_struct {
+	unsigned long fp_regs[NUM_FPU_REGS];
+	unsigned long xf_regs[NUM_FPU_REGS];
+	unsigned long fpscr;
+	unsigned long fpul;
+
+	unsigned char	lookahead;
+	unsigned long	entry_pc;
+};
+
+union sh_fpu_union {
+	struct sh_fpu_hard_struct hard;
+	struct sh_fpu_soft_struct soft;
+};
+
 struct thread_struct {
 	unsigned long sp;
 	unsigned long pc;
@@ -50,6 +88,9 @@
 	unsigned long trap_no, error_code;
 	unsigned long address;
 	/* Hardware debugging registers may come here */
+
+	/* floating point info */
+	union sh_fpu_union fpu;
 };
 
 #define INIT_MMAP \
@@ -59,6 +100,8 @@
 	sizeof(init_stack) + (long) &init_stack, /* sp */	\
 	0,					 /* pc */	\
 	0, 0, \
+	0, \
+	{{{0,}},} \
 }
 
 /*
@@ -69,7 +112,7 @@
 	regs->pr = 0;   		 	 \
 	regs->sr = 0;		/* User mode. */ \
 	regs->pc = new_pc;			 \
-	regs->u_regs[UREG_SP] = new_sp
+	regs->sp = new_sp
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -95,6 +138,49 @@
 #define copy_segments(p, mm)	do { } while(0)
 #define release_segments(mm)	do { } while(0)
 #define forget_segments()	do { } while (0)
+
+/*
+ * FPU lazy state save handling..
+ */
+#define SR_FD	0x00008000
+
+extern __inline__ void release_fpu(void)
+{
+	unsigned long __dummy;
+
+	/* Set FD flag in SR */
+	__asm__ __volatile__ ("stc	sr,%0\n\t"
+			      "or	%1,%0\n\t"
+			      "ldc	%0,sr"
+			      : "=&r" (__dummy)
+			      : "r" (SR_FD));
+}
+
+extern __inline__ void grab_fpu(void)
+{
+	unsigned long __dummy;
+
+	/* Clear out FD flag in SR */
+	__asm__ __volatile__ ("stc	sr,%0\n\t"
+			      "and	%1,%0\n\t"
+			      "ldc	%0,sr"
+			      : "=&r" (__dummy)
+			      : "r" (~SR_FD));
+}
+
+extern void save_fpu(struct task_struct *__tsk);
+
+#define unlazy_fpu(tsk) do { \
+	if (tsk->flags & PF_USEDFPU) \
+		save_fpu(tsk); \
+} while (0)
+
+#define clear_fpu(tsk) do { \
+	if (tsk->flags & PF_USEDFPU) { \
+		tsk->flags &= ~PF_USEDFPU; \
+		release_fpu(); \
+	} \
+} while (0)
 
 /*
  * Return saved PC of a blocked thread.
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/ptrace.h linux/include/asm-sh/ptrace.h
--- v2.3.22/linux/include/asm-sh/ptrace.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/ptrace.h	Mon Oct 18 11:16:13 1999
@@ -2,7 +2,7 @@
 #define __ASM_SH_PTRACE_H
 
 /*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999  Niibe Yutaka
  *
  */
 
@@ -12,12 +12,13 @@
  */
 struct pt_regs {
 	long syscall_nr;
-	unsigned long u_regs[16];
+	unsigned long sr;
+	unsigned long sp;
+	unsigned long regs[15];
 	unsigned long gbr;
 	unsigned long mach;
 	unsigned long macl;
 	unsigned long pr;
-	unsigned long sr;
 	unsigned long pc;
 };
 
@@ -27,5 +28,4 @@
 extern void show_regs(struct pt_regs *);
 #endif
 
-#define UREG_SP 15
 #endif /* __ASM_SH_PTRACE_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/sigcontext.h linux/include/asm-sh/sigcontext.h
--- v2.3.22/linux/include/asm-sh/sigcontext.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/sigcontext.h	Mon Oct 18 11:16:13 1999
@@ -5,13 +5,14 @@
 	unsigned long	oldmask;
 
 	/* CPU registers */
-	unsigned long   u_regs[16];
-	unsigned long gbr;
-	unsigned long mach;
-	unsigned long macl;
-	unsigned long pr;
-	unsigned long sr;
-	unsigned long pc;
+	unsigned long sc_regs[15];
+	unsigned long sc_gbr;
+	unsigned long sc_mach;
+	unsigned long sc_macl;
+	unsigned long sc_pr;
+	unsigned long sc_sp;
+	unsigned long sc_sr;
+	unsigned long sc_pc;
 };
 
 #endif /* __ASM_SH_SIGCONTEXT_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/signal.h linux/include/asm-sh/signal.h
--- v2.3.22/linux/include/asm-sh/signal.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/signal.h	Mon Oct 18 11:16:13 1999
@@ -6,10 +6,6 @@
 /* Avoid too many header ordering problems.  */
 struct siginfo;
 
-#ifdef __KERNEL__
-/* Most things should be clean enough to redefine this at will, if care
-   is taken to make libc match.  */
-
 #define _NSIG		64
 #define _NSIG_BPW	32
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
@@ -19,14 +15,6 @@
 typedef struct {
 	unsigned long sig[_NSIG_WORDS];
 } sigset_t;
-
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG		32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
 
 #define SIGHUP		 1
 #define SIGINT		 2
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/smp_lock.h linux/include/asm-sh/smp_lock.h
--- v2.3.22/linux/include/asm-sh/smp_lock.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-#ifndef __ASM_SH_SMPLOCK_H
-#define __ASM_SH_SMPLOCK_H
-
-#ifndef __SMP__
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else
-
-#error "We do not support SMP on SH yet"
-
-#endif /* __SMP__ */
-
-#endif /* __ASM_SH_SMPLOCK_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/smplock.h linux/include/asm-sh/smplock.h
--- v2.3.22/linux/include/asm-sh/smplock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/smplock.h	Mon Oct 18 11:16:13 1999
@@ -0,0 +1,70 @@
+#ifndef __ASM_SH_SMPLOCK_H
+#define __ASM_SH_SMPLOCK_H
+
+/*
+ * 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 __SMP__
+
+#define lock_kernel()				do { } while(0)
+#define unlock_kernel()				do { } while(0)
+#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
+#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
+
+#else
+
+#error "We do not support SMP on SH yet"
+/*
+ * Default SMP lock implementation
+ */
+
+#include <linux/interrupt.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t kernel_flag;
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+	if (!++current->lock_depth)
+		spin_lock(&kernel_flag);
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+	if (--current->lock_depth < 0)
+		spin_unlock(&kernel_flag);
+}
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu) \
+do { \
+	if (task->lock_depth >= 0) \
+		spin_unlock(&kernel_flag); \
+	release_irqlock(cpu); \
+	__sti(); \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task) \
+do { \
+	if (task->lock_depth >= 0) \
+		spin_lock(&kernel_flag); \
+} while (0)
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_SH_SMPLOCK_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/socket.h linux/include/asm-sh/socket.h
--- v2.3.22/linux/include/asm-sh/socket.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/socket.h	Mon Oct 18 11:16:13 1999
@@ -33,19 +33,10 @@
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	23
 #define SO_SECURITY_ENCRYPTION_NETWORK		24
 
-/* Nasty libc5 fixup - bletch */
-#if defined(__KERNEL__)
-/* Socket types. */
-#define SOCK_STREAM	1		/* stream (connection) socket	*/
-#define SOCK_DGRAM	2		/* datagram (conn.less) socket	*/
-#define SOCK_RAW	3		/* raw socket			*/
-#define SOCK_RDM	4		/* reliably-delivered message	*/
-#define SOCK_SEQPACKET	5		/* sequential packet socket	*/
-#define SOCK_PACKET	10		/* linux specific way of	*/
-					/* getting packets at the dev	*/
-					/* level.  For writing rarp and	*/
-					/* other similar things on the	*/
-					/* user level.			*/
-#endif					
+#define SO_BINDTODEVICE	25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
 
 #endif /* __ASM_SH_SOCKET_H */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/softirq.h linux/include/asm-sh/softirq.h
--- v2.3.22/linux/include/asm-sh/softirq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/softirq.h	Mon Oct 18 11:16:13 1999
@@ -13,8 +13,7 @@
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
 
 #define get_active_bhs()	(bh_mask & bh_active)
-/* XXX */
-#define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
+#define clear_active_bhs(x)	atomic_clear_mask((x),(atomic_t *)&bh_active)
 
 extern inline void init_bh(int nr, void (*routine)(void))
 {
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/system.h linux/include/asm-sh/system.h
--- v2.3.22/linux/include/asm-sh/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/system.h	Mon Oct 18 11:16:13 1999
@@ -26,6 +26,7 @@
  register unsigned long *__ts6 __asm__ ("r6") = &next->thread.sp; \
  register unsigned long __ts7 __asm__ ("r7") = next->thread.pc; \
  __asm__ __volatile__ (".balign 4\n\t" \
+		       "stc.l	gbr,@-r15\n\t" \
 		       "sts.l	pr,@-r15\n\t" \
 		       "mov.l	r8,@-r15\n\t" \
 		       "mov.l	r9,@-r15\n\t" \
@@ -41,11 +42,11 @@
 		       "mov.l	%0,@r2		! save PC\n\t" \
 		       "mov.l	2f,%0\n\t" \
 		       "jmp	@%0		! call __switch_to\n\t" \
-		       " lds	r7,pr		!  with return to new PC\n" \
-		       "2:\n" \
-		       ".long	" "_" "__switch_to\n\t" \
+		       " lds	r7,pr		!  with return to new PC\n\t" \
 		       ".balign	4\n"	\
-		       "1:\n" \
+		       "2:\n\t" \
+		       ".long	" "_" "__switch_to\n" \
+		       "1:\n\t" \
 		       "mov.l	@r15+,%0	! pop R0 from new stack\n\t" \
 		       "mov.l	@r15+,r14\n\t" \
 		       "mov.l	@r15+,r13\n\t" \
@@ -55,6 +56,7 @@
 		       "mov.l	@r15+,r9\n\t" \
 		       "mov.l	@r15+,r8\n\t" \
 		       "lds.l	@r15+,pr\n\t" \
+		       "ldc.l	@r15+,gbr\n\t" \
 		       :"=&z" (__last) \
 		       :"0" (prev), \
 			"r" (__ts1), "r" (__ts2), \
@@ -84,6 +86,9 @@
 #define mb()	__asm__ __volatile__ ("": : :"memory")
 #define rmb()	mb()
 #define wmb()	__asm__ __volatile__ ("": : :"memory")
+#define set_rmb(var, value) do { xchg(&var, value); } while (0)
+#define set_mb(var, value) set_rmb(var, value)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 /* Interrupt Control */
 extern __inline__ void __sti(void)
@@ -164,7 +169,7 @@
 	return retval;
 }
 
-static __inline__ unsigned long __xchg(unsigned long x, void * ptr, int size)
+static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 {
 	switch (size) {
 	case 4:
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/termbits.h linux/include/asm-sh/termbits.h
--- v2.3.22/linux/include/asm-sh/termbits.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/termbits.h	Mon Oct 18 11:16:13 1999
@@ -117,10 +117,21 @@
 #define HUPCL	0002000
 #define CLOCAL	0004000
 #define CBAUDEX 0010000
-#define  B57600  0010001
-#define  B115200 0010002
-#define  B230400 0010003
-#define  B460800 0010004
+#define    B57600 0010001
+#define   B115200 0010002
+#define   B230400 0010003
+#define   B460800 0010004
+#define   B500000 0010005
+#define   B576000 0010006
+#define   B921600 0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
 #define CIBAUD	  002003600000	/* input baud rate (not used) */
 #define CMSPAR	  010000000000		/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/termios.h linux/include/asm-sh/termios.h
--- v2.3.22/linux/include/asm-sh/termios.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/termios.h	Mon Oct 18 11:16:13 1999
@@ -47,7 +47,12 @@
 #define N_AX25		5
 #define N_X25		6	/* X.25 async */
 #define N_6PACK		7
-#define N_MASC		8	/* Reserved fo Mobitex module <kaz@cafe.net> */
+#define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964		9	/* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA		11	/* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC		13	/* synchronous HDLC */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/types.h linux/include/asm-sh/types.h
--- v2.3.22/linux/include/asm-sh/types.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/types.h	Mon Oct 18 11:16:13 1999
@@ -27,16 +27,16 @@
  */
 #ifdef __KERNEL__
 
-typedef signed char s8;
+typedef __signed__ char s8;
 typedef unsigned char u8;
 
-typedef signed short s16;
+typedef __signed__ short s16;
 typedef unsigned short u16;
 
-typedef signed int s32;
+typedef __signed__ int s32;
 typedef unsigned int u32;
 
-typedef signed long long s64;
+typedef __signed__ long long s64;
 typedef unsigned long long u64;
 
 #define BITS_PER_LONG 32
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/uaccess.h linux/include/asm-sh/uaccess.h
--- v2.3.22/linux/include/asm-sh/uaccess.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/uaccess.h	Mon Oct 18 11:16:13 1999
@@ -1,7 +1,8 @@
-/*
+/* $Id: uaccess.h,v 1.3 1999/10/12 14:46:20 gniibe Exp $
+ *
  * User space memory access functions
  *
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999  Niibe Yutaka
  *
  *  Based on:
  *     MIPS implementation version 1.15 by
@@ -48,7 +49,7 @@
 	unsigned long flag,sum; \
 	__asm__("clrt; addc %3,%1; movt %0; cmp/hi %4,%1; rotcl %0" \
 		:"=&r" (flag), "=r" (sum) \
-		:"1" (addr), "r" (size), "r" (current->addr_limit.seg)); \
+		:"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)); \
 	flag; })
 
 #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
@@ -229,11 +230,11 @@
 		"mov.l	5f,%1\n\t"
 		"jmp	@%1\n\t"
 		" mov	%7,%0\n\t"
-		".align 4\n"
+		".balign 4\n"
 		"5:	.long 2b\n"
 		".previous\n"
 		".section __ex_table,\"a\"\n"
-		"	.align 4\n"
+		"	.balign 4\n"
 		"	.long 9b,3b\n"
 		"	.long 1b,2b\n"
 		".previous"
@@ -313,11 +314,11 @@
 		"mov.l	4f,%0\n\t"
 		"jmp	@%0\n\t"
 		" mov	%7,%0\n"
-		".align 4\n"
+		".balign 4\n"
 		"4:	.long 2b\n"
 		".previous\n"
 		".section __ex_table,\"a\"\n"
-		"	.align 4\n"
+		"	.balign 4\n"
 		"	.long 1b,3b\n"
 		".previous"
 		: "=&r" (res), "=&r" (__a), "=&r" (__s)
@@ -356,11 +357,11 @@
 		"mov.l	4f,%1\n\t"
 		"jmp	@%1\n\t"
 		" mov	%8,%0\n\t"
-		".align 4\n"
+		".balign 4\n"
 		"4:	.long 2b\n"
 		".previous\n"
 		".section __ex_table,\"a\"\n"
-		"	.align 4\n"
+		"	.balign 4\n"
 		"	.long 9b,3b\n"
 		"	.long 1b,2b\n"
 		".previous"
@@ -380,46 +381,51 @@
 __sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
 } __sfu_res; })
 
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
 /*
  * Return the size of a string (including the ending 0!)
  */
-extern __inline__ long __strlen_user(const char *__s)
+extern __inline__ long __strnlen_user(const char *__s, long __n)
 {
 	unsigned long res;
 	unsigned long __dummy;
 
 	__asm__ __volatile__(
 		"mov	#-1,%1\n"
-		"9:\n"
+		"9:\n\t"
+		"cmp/eq	%4,%0\n\t"
+		"bt	5f\n\t"
 		"cmp/eq	#0,%1\n\t"
 		"bf/s	9b\n\t"
 		"1:\t"
 		" mov.b	@%0+,%1\n\t"
+		"5:\t"
 		"sub	%3,%0\n"
 		"2:\n"
 		".section .fixup,\"ax\"\n"
 		"3:\n\t"
 		"mov.l	4f,%1\n\t"
 		"jmp	@%1\n\t"
-		" mov	%4,%0\n"
-		".align 4\n"
+		" mov	%5,%0\n"
+		".balign 4\n"
 		"4:	.long 2b\n"
 		".previous\n"
 		".section __ex_table,\"a\"\n"
-		"	.align 4\n"
+		"	.balign 4\n"
 		"	.long 1b,3b\n"
 		".previous"
 		: "=&r" (res), "=&z" (__dummy)
-		: "0" (__s), "r" (__s), "i" (-EFAULT));
+		: "0" (__s), "r" (__s), "r" (__s+__n), "i" (-EFAULT));
 	return res;
 }
 
-extern __inline__ long strlen_user(const char *s)
+extern __inline__ long strnlen_user(const char *s, long n)
 {
-	if(!access_ok(VERIFY_READ, s, 0))
+	if(!access_ok(VERIFY_READ, s, n))
 		return 0;
 	else
-		return __strlen_user(s);
+		return __strnlen_user(s, n);
 }
 
 struct exception_table_entry
diff -u --recursive --new-file v2.3.22/linux/include/asm-sh/unistd.h linux/include/asm-sh/unistd.h
--- v2.3.22/linux/include/asm-sh/unistd.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/unistd.h	Mon Oct 18 11:16:13 1999
@@ -222,7 +222,8 @@
 register long __sc0 __asm__ ("r0") = __NR_##name; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
-	: "0" (__sc0)); \
+	: "0" (__sc0) \
+	: "memory" ); \
 __syscall_return(type,__sc0); \
 }
 
@@ -233,7 +234,8 @@
 register long __sc4 __asm__ ("r4") = (long) arg1; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
-	: "0" (__sc0), "r" (__sc4)); \
+	: "0" (__sc0), "r" (__sc4) \
+	: "memory"); \
 __syscall_return(type,__sc0); \
 }
 
@@ -245,7 +247,8 @@
 register long __sc5 __asm__ ("r5") = (long) arg2; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
-	: "0" (__sc0), "r" (__sc4), "r" (__sc5)); \
+	: "0" (__sc0), "r" (__sc4), "r" (__sc5) \
+	: "memory"); \
 __syscall_return(type,__sc0); \
 }
 
@@ -258,7 +261,8 @@
 register long __sc6 __asm__ ("r6") = (long) arg3; \
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
-	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)); \
+	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \
+	: "memory"); \
 __syscall_return(type,__sc0); \
 }
 
@@ -273,7 +277,8 @@
 __asm__ __volatile__ ("trapa	#0" \
 	: "=z" (__sc0) \
 	: "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6),  \
-	  "r" (__sc7)); \
+	  "r" (__sc7) \
+	: "memory" ); \
 __syscall_return(type,__sc0); \
 }
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/acpi.h linux/include/linux/acpi.h
--- v2.3.22/linux/include/linux/acpi.h	Sat Oct  9 11:47:50 1999
+++ linux/include/linux/acpi.h	Wed Oct 20 17:56:58 1999
@@ -28,8 +28,8 @@
 #define ACPI_MINOR_DEV 167
 
 /* RSDP location */
-#define ACPI_BIOS_ROM_BASE ((__u8*) 0xe0000)
-#define ACPI_BIOS_ROM_END  ((__u8*) 0x100000)
+#define ACPI_BIOS_ROM_BASE (0x0e0000)
+#define ACPI_BIOS_ROM_END  (0x100000)
 
 /* Table signatures */
 #define ACPI_RSDP1_SIG 0x20445352 /* 'RSD ' */
diff -u --recursive --new-file v2.3.22/linux/include/linux/bigmem.h linux/include/linux/bigmem.h
--- v2.3.22/linux/include/linux/bigmem.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/bigmem.h	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-#ifndef _LINUX_BIGMEM_H
-#define _LINUX_BIGMEM_H
-
-#include <linux/config.h>
-
-#ifdef CONFIG_BIGMEM
-
-#include <asm/bigmem.h>
-
-/* declarations for linux/mm/bigmem.c */
-extern unsigned long bigmem_mapnr;
-extern int nr_free_bigpages;
-
-extern struct page * prepare_bigmem_swapout(struct page *);
-extern struct page * replace_with_bigmem(struct page *);
-
-#else /* CONFIG_BIGMEM */
-
-#define prepare_bigmem_swapout(page) page
-#define replace_with_bigmem(page) page
-#define kmap(kaddr, type) kaddr
-#define kunmap(vaddr, type) do { } while (0)
-#define nr_free_bigpages 0
-
-#endif /* CONFIG_BIGMEM */
-
-/* when CONFIG_BIGMEM is not set these will be plain clear/copy_page */
-extern inline void clear_bigpage(unsigned long kaddr)
-{
-	unsigned long vaddr;
-
-	vaddr = kmap(kaddr, KM_WRITE);
-	clear_page(vaddr);
-	kunmap(vaddr, KM_WRITE);
-}
-
-extern inline void copy_bigpage(unsigned long to, unsigned long from)
-{
-	unsigned long vfrom, vto;
-
-	vfrom = kmap(from, KM_READ);
-	vto = kmap(to, KM_WRITE);
-	copy_page(vto, vfrom);
-	kunmap(vfrom, KM_READ);
-	kunmap(vto, KM_WRITE);
-}
-
-#endif /* _LINUX_BIGMEM_H */
diff -u --recursive --new-file v2.3.22/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.3.22/linux/include/linux/binfmts.h	Wed Aug 18 16:43:33 1999
+++ linux/include/linux/binfmts.h	Fri Oct 22 12:46:26 1999
@@ -18,7 +18,7 @@
  */
 struct linux_binprm{
 	char buf[128];
-	unsigned long page[MAX_ARG_PAGES];
+	struct page *page[MAX_ARG_PAGES];
 	unsigned long p; /* current top of mem */
 	int sh_bang;
 	struct dentry * dentry;
diff -u --recursive --new-file v2.3.22/linux/include/linux/bootmem.h linux/include/linux/bootmem.h
--- v2.3.22/linux/include/linux/bootmem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/bootmem.h	Fri Oct 22 12:47:22 1999
@@ -0,0 +1,29 @@
+#ifndef _LINUX_BOOTMEM_H
+#define _LINUX_BOOTMEM_H
+
+#include <linux/config.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+
+/*
+ *  simple boot-time physical memory area allocator.
+ */
+
+extern unsigned long max_low_pfn;
+
+extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend);
+extern void __init reserve_bootmem (unsigned long addr, unsigned long size);
+extern void __init free_bootmem (unsigned long addr, unsigned long size);
+extern void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal);
+#define alloc_bootmem(x) \
+	__alloc_bootmem((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+#define alloc_bootmem_pages(x) \
+	__alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+#define alloc_bootmem_low_pages(x) \
+	__alloc_bootmem((x), PAGE_SIZE, 0)
+extern unsigned long __init free_all_bootmem (void);
+
+#endif /* _LINUX_BOOTMEM_H */
+
+
+
diff -u --recursive --new-file v2.3.22/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.3.22/linux/include/linux/cdrom.h	Mon Oct  4 15:49:30 1999
+++ linux/include/linux/cdrom.h	Tue Oct 19 13:47:40 1999
@@ -273,6 +273,7 @@
 	unsigned char 	*buffer;
 	unsigned int 	buflen;
 	int		stat;
+	void		*reserved[4];
 };
 
 
@@ -655,6 +656,14 @@
 } dvd_authinfo;
 
 #ifdef __KERNEL__
+
+struct cdrom_write_settings {
+	unsigned char fpacket;		/* fixed/variable packets */
+	unsigned long packet_size;	/* write out this number of packets */
+	unsigned long nwa;		/* next writeable address */
+	unsigned char writeable;	/* cdrom is writeable */
+};
+
 /* Uniform cdrom data structures for cdrom.c */
 struct cdrom_device_info {
 	struct cdrom_device_ops  *ops;  /* link to device_ops */
@@ -673,6 +682,7 @@
 /* per-device flags */
         __u8 sanyo_slot		: 2;	/* Sanyo 3 CD changer support */
         __u8 reserved		: 6;	/* not used yet */
+	struct cdrom_write_settings write;
 };
 
 struct cdrom_device_ops {
@@ -760,8 +770,6 @@
         __u8 uru			: 1;
         __u8 dbc_v			: 1;
 	__u8 did_v			: 1;
-#else
-#error "Please fix <asm/byteorder.h>"
 #endif
 	__u8 disc_type;
 	__u8 n_sessions_msb;
@@ -806,8 +814,6 @@
 	__u8 nwa_v			: 1;
 	__u8 lra_v			: 1;
 	__u8 reserved3			: 6;
-#else
-#error "Please fix <asm/byteorder.h>"
 #endif
 	__u32 track_start;
 	__u32 next_writable;
@@ -835,15 +841,12 @@
 	__u8 reserved1     : 4;
 	__u8 door_open     : 1;
 	__u8 mech_state    : 3;
-#else
-#error "Please fix <asm/byteorder.h>"
 #endif
 	__u8     curlba[3];
 	__u8     nslots;
 	__u8 short slot_tablelen;
 };
 
-
 struct cdrom_slot {
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 disc_present : 1;
@@ -853,8 +856,6 @@
 	__u8 change       : 1;
 	__u8 reserved1    : 6;
 	__u8 disc_present : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
 #endif
 	__u8 reserved2[3];
 };
@@ -871,6 +872,71 @@
 	mechtype_individual_changer = 4,
 	mechtype_cartridge_changer  = 5
 } mechtype_t;
+
+struct mode_page_header {
+	__u16 mode_data_length;
+	__u8 medium_type;
+	__u8 reserved1;
+	__u8 reserved2;
+	__u8 reserved3;
+	__u16 desc_length;
+};
+
+typedef struct {
+	struct mode_page_header header;
+#if defined(__BIG_ENDIAN_BITFIELD)
+	__u8 ps			: 1;
+	__u8 reserved1		: 1;
+	__u8 page_code		: 6;
+        __u8 page_length;
+	__u8 reserved2		: 1;
+	__u8 bufe		: 1;
+	__u8 ls_v		: 1;
+	__u8 test_write		: 1;
+        __u8 write_type		: 4;
+	__u8 multi_session	: 2; /* or border, DVD */
+	__u8 fp			: 1;
+	__u8 copy		: 1;
+	__u8 track_mode		: 4;
+	__u8 reserved3		: 4;
+	__u8 data_block_type	: 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 page_code		: 6;
+	__u8 reserved1		: 1;
+	__u8 ps			: 1;
+        __u8 page_length;
+        __u8 write_type		: 4;
+	__u8 test_write		: 1;
+	__u8 ls_v		: 1;
+	__u8 bufe		: 1;
+	__u8 reserved2		: 1;
+	__u8 track_mode		: 4;
+	__u8 copy		: 1;
+	__u8 fp			: 1;
+	__u8 multi_session	: 2; /* or border, DVD */
+	__u8 data_block_type	: 4;
+	__u8 reserved3		: 4;
+#endif
+	__u8 link_size;
+	__u8 reserved4;
+#if defined(__BIG_ENDIAN_BITFIELD)
+	__u8 reserved5		: 2;
+	__u8 app_code		: 6;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 app_code		: 6;
+	__u8 reserved5		: 2;
+#endif
+	__u8 session_format;
+	__u8 reserved6;
+	__u32 packet_size;
+	__u16 audio_pause;
+	__u8 mcn[16];
+	__u8 isrc[16];
+	__u8 subhdr0;
+	__u8 subhdr1;
+	__u8 subhdr2;
+	__u8 subhdr3;
+} write_param_page __attribute__((packed));
 
 #endif  /* End of kernel only stuff */ 
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.22/linux/include/linux/fs.h	Fri Oct 15 15:25:14 1999
+++ linux/include/linux/fs.h	Fri Oct 22 12:46:24 1999
@@ -323,6 +323,11 @@
 #include <linux/quota.h>
 #include <linux/mount.h>
 
+/*
+ * oh the beauties of C type declarations.
+ */
+struct page;
+
 struct inode {
 	struct list_head	i_hash;
 	struct list_head	i_list;
@@ -350,7 +355,7 @@
 	wait_queue_head_t	i_wait;
 	struct file_lock	*i_flock;
 	struct vm_area_struct	*i_mmap;
-	struct page		*i_pages;
+	struct list_head	i_pages;
 	spinlock_t		i_shared_lock;
 	struct dquot		*i_dquot[MAXQUOTAS];
 	struct pipe_inode_info	*i_pipe;
@@ -769,8 +774,6 @@
 extern int try_to_free_buffers(struct page *);
 extern void refile_buffer(struct buffer_head * buf);
 
-extern atomic_t buffermem;
-
 #define BUF_CLEAN	0
 #define BUF_LOCKED	1	/* Buffers scheduled for write */
 #define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
@@ -874,7 +877,7 @@
 	int error;
 } read_descriptor_t;
 
-typedef int (*read_actor_t)(read_descriptor_t *, const char *, unsigned long);
+typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
 
 
 extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
@@ -886,7 +889,14 @@
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *);
 extern ino_t iunique(struct super_block *, ino_t);
-extern struct inode * iget(struct super_block *, unsigned long);
+
+typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+static inline struct inode *iget(struct super_block *sb, unsigned long ino)
+{
+	return iget4(sb, ino, NULL, NULL);
+}
+
 extern void clear_inode(struct inode *);
 extern struct inode * get_empty_inode(void);
 
@@ -934,11 +944,14 @@
 
 
 extern struct super_block *get_super(kdev_t);
+struct super_block *get_empty_super(void);
+void remove_vfsmnt(kdev_t dev);
 extern void put_super(kdev_t);
 unsigned long generate_cluster(kdev_t, int b[], int);
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
 extern kdev_t ROOT_DEV;
 
+extern void show_buffers(void);
 extern void mount_root(void);
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff -u --recursive --new-file v2.3.22/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.3.22/linux/include/linux/hdreg.h	Wed Aug 18 16:43:30 1999
+++ linux/include/linux/hdreg.h	Fri Oct 22 12:46:21 1999
@@ -81,6 +81,8 @@
 #define WIN_SRST		0x08	/* ATAPI soft reset command */
 #define WIN_PACKETCMD		0xa0	/* Send a packet command. */
 
+#define EXABYTE_ENABLE_NEST	0xf0
+
 /* WIN_SMART sub-commands */
 
 #define SMART_READ_VALUES	0xd0
diff -u --recursive --new-file v2.3.22/linux/include/linux/highmem.h linux/include/linux/highmem.h
--- v2.3.22/linux/include/linux/highmem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/highmem.h	Fri Oct 22 12:46:21 1999
@@ -0,0 +1,77 @@
+#ifndef _LINUX_HIGHMEM_H
+#define _LINUX_HIGHMEM_H
+
+#include <linux/config.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_HIGHMEM
+
+extern struct page *highmem_start_page;
+
+#include <asm/highmem.h>
+
+/* declarations for linux/mm/highmem.c */
+extern unsigned long highmem_mapnr;
+extern unsigned long nr_free_highpages;
+
+extern struct page * prepare_highmem_swapout(struct page *);
+extern struct page * replace_with_highmem(struct page *);
+
+#else /* CONFIG_HIGHMEM */
+
+#define prepare_highmem_swapout(page) page
+#define replace_with_highmem(page) page
+#define kmap(page, type) page_address(page)
+#define kunmap(vaddr, type) do { } while (0)
+#define nr_free_highpages 0UL
+
+#endif /* CONFIG_HIGHMEM */
+
+/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
+extern inline void clear_highpage(struct page *page)
+{
+	unsigned long kaddr;
+
+	kaddr = kmap(page, KM_WRITE);
+	clear_page((void *)kaddr);
+	kunmap(kaddr, KM_WRITE);
+}
+
+extern inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size)
+{
+	unsigned long kaddr;
+
+	if (offset + size > PAGE_SIZE)
+		BUG();
+	kaddr = kmap(page, KM_WRITE);
+	memset((void *)(kaddr + offset), 0, size);
+	kunmap(kaddr, KM_WRITE);
+}
+
+/*
+ * Same but also flushes aliased cache contents to RAM.
+ */
+extern inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size)
+{
+	unsigned long kaddr;
+
+	if (offset + size > PAGE_SIZE)
+		BUG();
+	kaddr = kmap(page, KM_WRITE);
+	memset((void *)(kaddr + offset), 0, size);
+	flush_page_to_ram(page);
+	kunmap(kaddr, KM_WRITE);
+}
+
+extern inline void copy_highpage(struct page *to, struct page *from)
+{
+	unsigned long vfrom, vto;
+
+	vfrom = kmap(from, KM_READ);
+	vto = kmap(to, KM_WRITE);
+	copy_page((void *)vto, (void *)vfrom);
+	kunmap(vfrom, KM_READ);
+	kunmap(vto, KM_WRITE);
+}
+
+#endif /* _LINUX_HIGHMEM_H */
diff -u --recursive --new-file v2.3.22/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.22/linux/include/linux/ide.h	Mon Oct 11 15:38:15 1999
+++ linux/include/linux/ide.h	Fri Oct 22 12:46:32 1999
@@ -236,6 +236,7 @@
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long service_start;	/* time we started last request */
 	unsigned long service_time;	/* service time of last request */
+	unsigned long timeout;		/* max time to wait for irq */
 	special_t	special;	/* special action flags */
 	byte     keep_settings;		/* restore settings after drive reset */
 	byte     using_dma;		/* disk is using dma for read/write */
@@ -338,6 +339,7 @@
  * This is used to provide support for strange interfaces
  */
 typedef void (ide_selectproc_t) (ide_drive_t *);
+typedef void (ide_resetproc_t) (ide_drive_t *);
 
 /*
  * hwif_chipset_t is used to keep track of the specific hardware
@@ -367,6 +369,7 @@
 	struct gendisk	*gd;		/* gendisk structure */
 	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
 	ide_selectproc_t *selectproc;	/* tweaks hardware to select drive */
+	ide_resetproc_t	*resetproc;	/* routine to reset controller after a disk reset */
 	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
 	unsigned long	*dmatable;	/* dma physical region descriptor table */
 	struct hwif_s	*mate;		/* other hwif from same PCI chip */
@@ -581,7 +584,7 @@
  * This is used on exit from the driver, to designate the next irq handler
  * and also to start the safety timer.
  */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout);
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler);
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
diff -u --recursive --new-file v2.3.22/linux/include/linux/iobuf.h linux/include/linux/iobuf.h
--- v2.3.22/linux/include/linux/iobuf.h	Fri Oct 15 15:25:14 1999
+++ linux/include/linux/iobuf.h	Fri Oct 22 12:46:39 1999
@@ -41,7 +41,6 @@
 	 * region, there won't necessarily be page structs defined for
 	 * every address. */
 
-	unsigned long *	pagelist;
 	struct page **	maplist;
 
 	unsigned int	locked : 1;	/* If set, pages has been locked */
diff -u --recursive --new-file v2.3.22/linux/include/linux/joystick.h linux/include/linux/joystick.h
--- v2.3.22/linux/include/linux/joystick.h	Wed Aug 18 16:44:44 1999
+++ linux/include/linux/joystick.h	Fri Oct 22 12:47:32 1999
@@ -173,26 +173,16 @@
  * Parport stuff
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 #define USE_PARPORT
-#endif
 
-#ifdef USE_PARPORT
 #include <linux/parport.h>
+#include <linux/parport_pc.h>
 #define JS_PAR_DATA_IN(y)	parport_read_data(y->port)
 #define JS_PAR_DATA_OUT(x,y)	parport_write_data(y->port, x)
 #define JS_PAR_STATUS(y)	parport_read_status(y->port)
 #define JS_PAR_CTRL_IN(y)	parport_read_control(y->port)
 #define JS_PAR_CTRL_OUT(x,y)	parport_write_control(y->port, x)
-#define JS_PAR_ECTRL_OUT(x,y)	parport_write_econtrol(y->port, x)
-#else
-#define JS_PAR_DATA_IN(y)	inb(y)
-#define JS_PAR_DATA_OUT(x,y)	outb(x,y)
-#define JS_PAR_STATUS(y)	inb(y+1)
-#define JS_PAR_CTRL_IN(y)	inb(y+2)
-#define JS_PAR_CTRL_OUT(x,y)	outb(x,y+2)
-#define JS_PAR_ECTRL_OUT(x,y)	outb(x,y+0x402)
-#endif
+#define JS_PAR_ECTRL_OUT(x,y)	outb(x, ECONTROL(y->port))
 
 #define JS_PAR_STATUS_INVERT	(0x80)
 #define JS_PAR_CTRL_INVERT	(0x04)
diff -u --recursive --new-file v2.3.22/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.3.22/linux/include/linux/kernel.h	Fri Sep 10 23:57:37 1999
+++ linux/include/linux/kernel.h	Tue Oct 19 10:22:19 1999
@@ -94,9 +94,10 @@
 	unsigned long totalswap;	/* Total swap space size */
 	unsigned long freeswap;		/* swap space still available */
 	unsigned short procs;		/* Number of current processes */
-	unsigned long totalbig;		/* Total big memory size */
-	unsigned long freebig;		/* Available big memory size */
-	char _f[20-2*sizeof(long)];	/* Padding: libc5 uses this.. */
+	unsigned long totalhigh;	/* Total high memory size */
+	unsigned long freehigh;		/* Available high memory size */
+	unsigned int mem_unit;		/* Memory unit size in bytes */
+	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
 };
 
 #endif
diff -u --recursive --new-file v2.3.22/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.22/linux/include/linux/mm.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/mm.h	Fri Oct 22 12:46:27 1999
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/string.h>
+#include <linux/list.h>
 
 extern unsigned long max_mapnr;
 extern unsigned long num_physpages;
@@ -103,9 +104,8 @@
 	void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot);
 	int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
 	void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise);
-	unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access);
-	unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
-		unsigned long page);
+	struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access);
+	struct page * (*wppage)(struct vm_area_struct * area, unsigned long address, struct page * page);
 	int (*swapout)(struct vm_area_struct *, struct page *);
 };
 
@@ -119,8 +119,7 @@
  */
 typedef struct page {
 	/* these must be first (free area handling) */
-	struct page *next;
-	struct page *prev;
+	struct list_head list;
 	struct inode *inode;
 	unsigned long offset;
 	struct page *next_hash;
@@ -149,11 +148,11 @@
 #define PG_uptodate		 3
 #define PG_decr_after		 5
 #define PG_DMA			 7
-#define PG_Slab			 8
+#define PG_slab			 8
 #define PG_swap_cache		 9
 #define PG_skip			10
 #define PG_swap_entry		11
-#define PG_BIGMEM		12
+#define PG_highmem		12
 				/* bits 21-30 unused */
 #define PG_reserved		31
 
@@ -183,27 +182,32 @@
 #define PageReferenced(page)	(test_bit(PG_referenced, &(page)->flags))
 #define PageDecrAfter(page)	(test_bit(PG_decr_after, &(page)->flags))
 #define PageDMA(page)		(test_bit(PG_DMA, &(page)->flags))
-#define PageSlab(page)		(test_bit(PG_Slab, &(page)->flags))
+#define PageSlab(page)		(test_bit(PG_slab, &(page)->flags))
 #define PageSwapCache(page)	(test_bit(PG_swap_cache, &(page)->flags))
 #define PageReserved(page)	(test_bit(PG_reserved, &(page)->flags))
 
-#define PageSetSlab(page)	(set_bit(PG_Slab, &(page)->flags))
+#define PageSetSlab(page)	(set_bit(PG_slab, &(page)->flags))
 #define PageSetSwapCache(page)	(set_bit(PG_swap_cache, &(page)->flags))
 
 #define PageTestandSetSwapCache(page)	\
 			(test_and_set_bit(PG_swap_cache, &(page)->flags))
 
-#define PageClearSlab(page)	(clear_bit(PG_Slab, &(page)->flags))
+#define PageClearSlab(page)	(clear_bit(PG_slab, &(page)->flags))
 #define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
 
 #define PageTestandClearSwapCache(page)	\
 			(test_and_clear_bit(PG_swap_cache, &(page)->flags))
-#ifdef CONFIG_BIGMEM
-#define PageBIGMEM(page)	(test_bit(PG_BIGMEM, &(page)->flags))
+#ifdef CONFIG_HIGHMEM
+#define PageHighMem(page)	(test_bit(PG_highmem, &(page)->flags))
 #else
-#define PageBIGMEM(page) 0 /* needed to optimize away at compile time */
+#define PageHighMem(page) 0 /* needed to optimize away at compile time */
 #endif
 
+#define SetPageReserved(page)	do { set_bit(PG_reserved, &(page)->flags); \
+					} while (0)
+#define ClearPageReserved(page)	do { test_and_clear_bit(PG_reserved, &(page)->flags); } while (0)
+
+
 /*
  * Various page->flags bits:
  *
@@ -224,7 +228,7 @@
  *   (e.g. a private data page of one process).
  *
  * A page may be used for kmalloc() or anyone else who does a
- * get_free_page(). In this case the page->count is at least 1, and
+ * __get_free_page(). In this case the page->count is at least 1, and
  * all other fields are unused but should be 0 or NULL. The
  * management of this page is the responsibility of the one who uses
  * it.
@@ -281,20 +285,27 @@
  * goes to clearing the page. If you want a page without the clearing
  * overhead, just use __get_free_page() directly..
  */
+extern struct page * __get_pages(int gfp_mask, unsigned long order);
 #define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0)
 #define __get_dma_pages(gfp_mask, order) __get_free_pages((gfp_mask) | GFP_DMA,(order))
 extern unsigned long FASTCALL(__get_free_pages(int gfp_mask, unsigned long gfp_order));
+extern struct page * get_free_highpage(int gfp_mask);
 
-extern inline unsigned long get_free_page(int gfp_mask)
+extern inline unsigned long get_zeroed_page(int gfp_mask)
 {
 	unsigned long page;
 
 	page = __get_free_page(gfp_mask);
 	if (page)
-		clear_page(page);
+		clear_page((void *)page);
 	return page;
 }
 
+/*
+ * The old interface name will be removed in 2.5:
+ */
+#define get_free_page get_zeroed_page
+
 /* memory.c & swap.c*/
 
 #define free_page(addr) free_pages((addr),0)
@@ -302,7 +313,7 @@
 extern int FASTCALL(__free_page(struct page *));
 
 extern void show_free_areas(void);
-extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
+extern struct page * put_dirty_page(struct task_struct * tsk, struct page *page,
 	unsigned long address);
 
 extern void clear_page_tables(struct mm_struct *, unsigned long, int);
@@ -322,12 +333,13 @@
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
 
-extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
-extern void mem_init(unsigned long start_mem, unsigned long end_mem);
+extern void paging_init(void);
+extern void free_area_init(unsigned long);
+extern void mem_init(void);
 extern void show_mem(void);
 extern void oom(struct task_struct * tsk);
 extern void si_meminfo(struct sysinfo * val);
-extern void swapin_readahead(unsigned long);
+extern void swapin_readahead(pte_t);
 
 /* mmap.c */
 extern void vma_init(void);
@@ -359,18 +371,18 @@
 #define __GFP_HIGH	0x08
 #define __GFP_IO	0x10
 #define __GFP_SWAP	0x20
-#ifdef CONFIG_BIGMEM
-#define __GFP_BIGMEM	0x40
+#ifdef CONFIG_HIGHMEM
+#define __GFP_HIGHMEM	0x40
 #else
-#define __GFP_BIGMEM	0x0 /* noop */
+#define __GFP_HIGHMEM	0x0 /* noop */
 #endif
 
 #define __GFP_DMA	0x80
 
 #define GFP_BUFFER	(__GFP_LOW | __GFP_WAIT)
 #define GFP_ATOMIC	(__GFP_HIGH)
-#define GFP_BIGUSER	(__GFP_LOW | __GFP_WAIT | __GFP_IO | __GFP_BIGMEM)
 #define GFP_USER	(__GFP_LOW | __GFP_WAIT | __GFP_IO)
+#define GFP_HIGHUSER	(GFP_USER | __GFP_HIGHMEM)
 #define GFP_KERNEL	(__GFP_MED | __GFP_WAIT | __GFP_IO)
 #define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
 #define GFP_KSWAPD	(__GFP_IO | __GFP_SWAP)
@@ -380,10 +392,10 @@
 
 #define GFP_DMA		__GFP_DMA
 
-/* Flag - indicates that the buffer can be taken from big memory which is not
+/* Flag - indicates that the buffer can be taken from high memory which is not
    directly addressable by the kernel */
 
-#define GFP_BIGMEM	__GFP_BIGMEM
+#define GFP_HIGHMEM	__GFP_HIGHMEM
 
 /* vma is the first one with  address < vma->vm_end,
  * and even  address < vma->vm_start. Have to extend vma. */
@@ -422,10 +434,16 @@
 
 extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned long addr);
 
-#define buffer_under_min()	((atomic_read(&buffermem) >> PAGE_SHIFT) * 100 < \
+#define buffer_under_min()	(atomic_read(&buffermem_pages) * 100 < \
 				buffer_mem.min_percent * num_physpages)
 #define pgcache_under_min()	(atomic_read(&page_cache_size) * 100 < \
 				page_cache.min_percent * num_physpages)
+
+#define vmlist_access_lock(mm)		spin_lock(&mm->page_table_lock)
+#define vmlist_access_unlock(mm)	spin_unlock(&mm->page_table_lock)
+#define vmlist_modify_lock(mm)		vmlist_access_lock(mm)
+#define vmlist_modify_unlock(mm)	vmlist_access_unlock(mm)
+
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/nfs.h linux/include/linux/nfs.h
--- v2.3.22/linux/include/linux/nfs.h	Tue Jun  8 22:11:58 1999
+++ linux/include/linux/nfs.h	Mon Oct 18 11:26:37 1999
@@ -122,15 +122,6 @@
 	struct nfs_time		ctime;
 };
 
-struct nfs_sattr {
-	__u32			mode;
-	__u32			uid;
-	__u32			gid;
-	__u32			size;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-};
-
 struct nfs_fsinfo {
 	__u32			tsize;
 	__u32			bsize;
@@ -150,7 +141,7 @@
 
 struct nfs_sattrargs {
 	struct nfs_fh *		fh;
-	struct nfs_sattr *	sattr;
+	struct iattr *		sattr;
 };
 
 struct nfs_diropargs {
@@ -173,7 +164,7 @@
 struct nfs_createargs {
 	struct nfs_fh *		fh;
 	const char *		name;
-	struct nfs_sattr *	sattr;
+	struct iattr *		sattr;
 };
 
 struct nfs_renameargs {
@@ -193,7 +184,7 @@
 	struct nfs_fh *		fromfh;
 	const char *		fromname;
 	const char *		topath;
-	struct nfs_sattr *	sattr;
+	struct iattr *		sattr;
 };
 
 struct nfs_readdirargs {
diff -u --recursive --new-file v2.3.22/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.3.22/linux/include/linux/nfs_fs.h	Wed Aug 18 16:44:22 1999
+++ linux/include/linux/nfs_fs.h	Fri Oct 22 12:47:07 1999
@@ -77,11 +77,14 @@
 			       : NFS_SERVER(inode)->acregmax)
 
 #define NFS_FLAGS(inode)		((inode)->u.nfs_i.flags)
-#define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATE)
+#define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
 #define NFS_WRITEBACK(inode)		((inode)->u.nfs_i.writeback)
 #define NFS_COOKIES(inode)		((inode)->u.nfs_i.cookies)
 #define NFS_DIREOF(inode)		((inode)->u.nfs_i.direof)
 
+#define NFS_FILEID(inode)		((inode)->u.nfs_i.fileid)
+#define NFS_FSID(inode)			((inode)->u.nfs_i.fsid)
+
 /*
  * These are the default flags for swap requests
  */
@@ -137,7 +140,7 @@
 extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 			struct nfs_fattr *fattr);
 extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_sattr *sattr, struct nfs_fattr *fattr);
+			struct nfs_fattr *fattr, struct iattr *sattr);
 extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
 			const char *name, struct nfs_fh *fhandle,
 			struct nfs_fattr *fattr);
@@ -148,7 +151,7 @@
 			int swap, unsigned long offset, unsigned int count,
 			const void *buffer, struct nfs_fattr *fattr);
 extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
+			const char *name, struct iattr *sattr,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
 			const char *name);
@@ -159,9 +162,9 @@
 			struct nfs_fh *dir, const char *name);
 extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
 			const char *name, const char *path,
-			struct nfs_sattr *sattr);
+			struct iattr *sattr);
 extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
+			const char *name, struct iattr *sattr,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
 			const char *name);
@@ -174,13 +177,14 @@
  */
 extern struct super_block *nfs_read_super(struct super_block *, void *, int);
 extern int init_nfs_fs(void);
+extern void nfs_zap_caches(struct inode *);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
 				struct nfs_fattr *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_revalidate(struct dentry *);
 extern int nfs_open(struct inode *, struct file *);
 extern int nfs_release(struct inode *, struct file *);
-extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *);
+extern int __nfs_revalidate_inode(struct nfs_server *, struct dentry *);
 
 /*
  * linux/fs/nfs/file.c
@@ -244,9 +248,9 @@
 nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
+	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
 		return 0;
-	return _nfs_revalidate_inode(server, dentry);
+	return __nfs_revalidate_inode(server, dentry);
 }
 
 /* NFS root */
diff -u --recursive --new-file v2.3.22/linux/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- v2.3.22/linux/include/linux/nfs_fs_i.h	Wed Jun 16 19:26:27 1999
+++ linux/include/linux/nfs_fs_i.h	Mon Oct 18 11:26:37 1999
@@ -9,6 +9,12 @@
  */
 struct nfs_inode_info {
 	/*
+	 * The 64bit 'inode number'
+	 */
+	__u32 fsid;
+	__u32 fileid;
+
+	/*
 	 * Various flags
 	 */
 	unsigned short		flags;
@@ -49,7 +55,7 @@
 /*
  * Legal inode flag values
  */
-#define NFS_INO_REVALIDATE	0x0001		/* revalidating attrs */
+#define NFS_INO_REVALIDATING	0x0001		/* revalidating attrs */
 #define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
 
 /*
diff -u --recursive --new-file v2.3.22/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.3.22/linux/include/linux/pagemap.h	Mon Oct  4 15:49:30 1999
+++ linux/include/linux/pagemap.h	Fri Oct 22 12:46:29 1999
@@ -11,10 +11,16 @@
 
 #include <linux/mm.h>
 #include <linux/fs.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
 
-static inline unsigned long page_address(struct page * page)
+extern inline pte_t get_pagecache_pte(struct page *page)
 {
-	return PAGE_OFFSET + ((page - mem_map) << PAGE_SHIFT);
+	/*
+	 * the pagecache is still machineword sized. The rest of the VM
+	 * can deal with arbitrary sized ptes.
+	 */
+        return __pte(page->offset);
 }
 
 /*
@@ -30,8 +36,8 @@
 #define PAGE_CACHE_MASK		PAGE_MASK
 #define PAGE_CACHE_ALIGN(addr)	(((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK)
 
-#define page_cache_alloc()	__get_free_page(GFP_USER)
-#define page_cache_free(x)	free_page(x)
+#define page_cache_alloc()	__get_pages(GFP_USER, 0)
+#define page_cache_free(x)	__free_page(x)
 #define page_cache_release(x)	__free_page(x)
 
 /*
@@ -54,7 +60,7 @@
  * inode pointer and offsets are distributed (ie, we
  * roughly know which bits are "significant")
  */
-static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
+extern inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
 {
 #define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
 #define o (offset >> PAGE_SHIFT)
@@ -82,26 +88,37 @@
 extern void add_to_page_cache(struct page * page, struct inode * inode, unsigned long offset);
 extern int add_to_page_cache_unique(struct page * page, struct inode * inode, unsigned long offset, struct page **hash);
 
-static inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long offset)
+extern inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long offset)
 {
 	__add_page_to_hash_queue(page, page_hash(inode,offset));
 }
 
-static inline void add_page_to_inode_queue(struct inode * inode, struct page * page)
+extern inline void add_page_to_inode_queue(struct inode * inode, struct page * page)
 {
-	struct page **p = &inode->i_pages;
+	struct list_head *head = &inode->i_pages;
 
-	inode->i_nrpages++;
+	if (!inode->i_nrpages++) {
+		if (!list_empty(head))
+			BUG();
+	} else {
+		if (list_empty(head))
+			BUG();
+	}
+	list_add(&page->list, head);
 	page->inode = inode;
-	page->prev = NULL;
-	if ((page->next = *p) != NULL)
-		page->next->prev = page;
-	*p = page;
+}
+
+extern inline void remove_page_from_inode_queue(struct page * page)
+{
+	struct inode * inode = page->inode;
+
+	inode->i_nrpages--;
+	list_del(&page->list);
 }
 
 extern void ___wait_on_page(struct page *);
 
-static inline void wait_on_page(struct page * page)
+extern inline void wait_on_page(struct page * page)
 {
 	if (PageLocked(page))
 		___wait_on_page(page);
diff -u --recursive --new-file v2.3.22/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.22/linux/include/linux/pci.h	Fri Oct 15 15:25:14 1999
+++ linux/include/linux/pci.h	Fri Oct 22 12:46:20 1999
@@ -406,6 +406,7 @@
 
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
+int pcibios_enable_device(struct pci_dev *);
 char *pcibios_setup (char *str);
 
 void pcibios_update_resource(struct pci_dev *, struct resource *,
@@ -460,9 +461,11 @@
 int pci_write_config_byte(struct pci_dev *dev, int where, u8 val);
 int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
 int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
+int pci_enable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
+int pci_set_power_state(struct pci_dev *dev, int state);
 
-/* Helper functions (drivers/pci/setup.c) */
+/* Helper functions for low-level code (drivers/pci/setup.c) */
 
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
@@ -471,7 +474,7 @@
 		    int (*)(struct pci_dev *, u8, u8));
 
 /*
- * simple PCI probing for drivers
+ * simple PCI probing for drivers (drivers/pci/helper.c)
  */
  
 struct pci_simple_probe_entry;
@@ -524,8 +527,8 @@
 unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from)
 { return NULL; }
 
-extern inline void pci_set_master(struct pci_dev *dev) 
-{ return; }
+extern inline void pci_set_master(struct pci_dev *dev) { }
+extern inline int pci_enable_device(struct pci_dev *dev) { return 0; }
 
 extern inline int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
 		      pci_simple_probe_callback cb, void *drvr_data)
diff -u --recursive --new-file v2.3.22/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.22/linux/include/linux/pci_ids.h	Fri Oct 15 15:25:14 1999
+++ linux/include/linux/pci_ids.h	Fri Oct 15 18:55:26 1999
@@ -100,6 +100,7 @@
 #define PCI_DEVICE_ID_COMPAQ_TOKENRING	0x0508
 #define PCI_DEVICE_ID_COMPAQ_1280	0x3033
 #define PCI_DEVICE_ID_COMPAQ_TRIFLEX	0x4000
+#define PCI_DEVICE_ID_COMPAQ_6010	0x6010
 #define PCI_DEVICE_ID_COMPAQ_SMART2P	0xae10
 #define PCI_DEVICE_ID_COMPAQ_NETEL100	0xae32
 #define PCI_DEVICE_ID_COMPAQ_NETEL10	0xae34
@@ -727,6 +728,10 @@
 #define PCI_VENDOR_ID_RENDITION		0x1163
 #define PCI_DEVICE_ID_RENDITION_VERITE	0x0001
 #define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000
+
+#define PCI_VENDOR_ID_RCC		0x1166
+#define PCI_DEVICE_ID_RCC_HE		0x0008
+#define PCI_DEVICE_ID_RCC_LE		0x0009
 
 #define PCI_VENDOR_ID_TOSHIBA		0x1179
 #define PCI_DEVICE_ID_TOSHIBA_601	0x0601
diff -u --recursive --new-file v2.3.22/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.22/linux/include/linux/proc_fs.h	Sat Oct  9 11:47:50 1999
+++ linux/include/linux/proc_fs.h	Fri Oct 22 12:46:32 1999
@@ -550,6 +550,7 @@
         return 0;
 }
 
+extern struct proc_dir_entry proc_root;
 
 #endif /* CONFIG_PROC_FS */
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.22/linux/include/linux/sched.h	Fri Oct 15 15:25:14 1999
+++ linux/include/linux/sched.h	Fri Oct 22 12:46:27 1999
@@ -357,6 +357,10 @@
 	struct signal_queue *sigqueue, **sigqueue_tail;
 	unsigned long sas_ss_sp;
 	size_t sas_ss_size;
+	
+/* Thread group tracking */
+   	u32 parent_exec_id;
+   	u32 self_exec_id;
 };
 
 /*
@@ -422,6 +426,7 @@
 /* files */	&init_files, \
 /* mm */	NULL, &init_mm, \
 /* signals */	SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
+/* exec cts */	0,0, \
 }
 
 #ifndef INIT_TASK_SIZE
diff -u --recursive --new-file v2.3.22/linux/include/linux/shm.h linux/include/linux/shm.h
--- v2.3.22/linux/include/linux/shm.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/shm.h	Tue Oct 19 10:22:19 1999
@@ -24,7 +24,7 @@
 	struct shmid_ds		u;
 	/* the following are private */
 	unsigned long		shm_npages;	/* size of segment (pages) */
-	unsigned long		*shm_pages;	/* array of ptrs to frames -> SHMMAX */ 
+	pte_t			*shm_pages;	/* array of ptrs to frames -> SHMMAX */ 
 	struct vm_area_struct	*attaches;	/* descriptors for attaches */
 };
 
@@ -72,7 +72,7 @@
 asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr);
 asmlinkage long sys_shmdt (char *shmaddr);
 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
-extern void shm_unuse(unsigned long entry, unsigned long page);
+extern void shm_unuse(pte_t entry, struct page *page);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.3.22/linux/include/linux/slab.h	Wed Aug 18 16:43:42 1999
+++ linux/include/linux/slab.h	Fri Oct 22 12:46:29 1999
@@ -45,7 +45,7 @@
 #define	SLAB_CTOR_VERIFY	0x004UL		/* tell constructor it's a verify call */
 
 /* prototypes */
-extern long kmem_cache_init(long, long);
+extern void kmem_cache_init(void);
 extern void kmem_cache_sizes_init(void);
 extern kmem_cache_t *kmem_find_general_cachep(size_t);
 extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
diff -u --recursive --new-file v2.3.22/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.22/linux/include/linux/swap.h	Tue Aug 31 17:29:15 1999
+++ linux/include/linux/swap.h	Fri Oct 22 12:46:20 1999
@@ -35,8 +35,6 @@
 #define MAX_SWAP_BADPAGES \
 	((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int))
 
-#undef DEBUG_SWAP
-
 #include <asm/atomic.h>
 
 #define SWP_USED	1
@@ -69,7 +67,7 @@
 extern atomic_t nr_async_pages;
 extern struct inode swapper_inode;
 extern atomic_t page_cache_size;
-extern atomic_t buffermem;
+extern atomic_t buffermem_pages;
 
 /* Incomplete types for prototype declarations: */
 struct task_struct;
@@ -87,36 +85,35 @@
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *, int);
-extern void rw_swap_page_nolock(int, unsigned long, char *, int);
-extern void swap_after_unlock_page (unsigned long entry);
+extern void rw_swap_page_nolock(int, pte_t, char *, int);
 
 /* linux/mm/page_alloc.c */
 
 /* linux/mm/swap_state.c */
 extern void show_swap_cache_info(void);
-extern void add_to_swap_cache(struct page *, unsigned long);
-extern int swap_duplicate(unsigned long);
+extern void add_to_swap_cache(struct page *, pte_t);
+extern int swap_duplicate(pte_t);
 extern int swap_check_entry(unsigned long);
-struct page * lookup_swap_cache(unsigned long);
-extern struct page * read_swap_cache_async(unsigned long, int);
+struct page * lookup_swap_cache(pte_t);
+extern struct page * read_swap_cache_async(pte_t, int);
 #define read_swap_cache(entry) read_swap_cache_async(entry, 1);
-extern int FASTCALL(swap_count(unsigned long));
-extern unsigned long acquire_swap_entry(struct page *page);
+extern int swap_count(struct page *);
+extern pte_t acquire_swap_entry(struct page *page);
 
 /*
  * Make these inline later once they are working properly.
  */
 extern void __delete_from_swap_cache(struct page *page);
 extern void delete_from_swap_cache(struct page *page);
-extern void free_page_and_swap_cache(unsigned long addr);
+extern void free_page_and_swap_cache(struct page *page);
 
 /* linux/mm/swapfile.c */
 extern unsigned int nr_swapfiles;
 extern struct swap_info_struct swap_info[];
 extern int is_swap_partition(kdev_t);
 void si_swapinfo(struct sysinfo *);
-unsigned long get_swap_page(void);
-extern void FASTCALL(swap_free(unsigned long));
+pte_t get_swap_page(void);
+extern void swap_free(pte_t);
 struct swap_list_t {
 	int head;	/* head of priority-ordered swapfile list */
 	int next;	/* swapfile to be used next */
@@ -158,7 +155,7 @@
 		return 1;
 	count = page_count(page);
 	if (PageSwapCache(page))
-		count += swap_count(page->offset) - 2;
+		count += swap_count(page) - 2;
 	return  count > 1;
 }
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.3.22/linux/include/linux/sysv_fs.h	Wed Aug 18 16:45:22 1999
+++ linux/include/linux/sysv_fs.h	Fri Oct 22 12:48:29 1999
@@ -384,7 +384,6 @@
 extern void sysv_free_block(struct super_block * sb, unsigned int block);
 extern unsigned long sysv_count_free_blocks(struct super_block *sb);
 
-extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
 extern int sysv_get_block(struct inode *, long, struct buffer_head *, int);
 extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
 
diff -u --recursive --new-file v2.3.22/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.3.22/linux/include/linux/tty.h	Mon Oct 11 15:38:15 1999
+++ linux/include/linux/tty.h	Fri Oct 22 12:46:27 1999
@@ -339,12 +339,13 @@
 
 extern int kmsg_redirect;
 
-extern unsigned long con_init(unsigned long);
+extern void con_init(void);
+extern void console_init(void);
 
 extern int rs_init(void);
 extern int lp_init(void);
 extern int pty_init(void);
-extern int tty_init(void);
+extern void tty_init(void);
 extern int ip2_init(void);
 extern int pcxe_init(void);
 extern int pc_init(void);
@@ -393,7 +394,7 @@
 
 /* serial.c */
 
-extern long serial_console_init(long kmem_start, long kmem_end);
+extern void serial_console_init(void);
  
 /* pcxx.c */
 
diff -u --recursive --new-file v2.3.22/linux/include/net/ip.h linux/include/net/ip.h
--- v2.3.22/linux/include/net/ip.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/ip.h	Fri Oct 22 12:47:42 1999
@@ -137,6 +137,7 @@
 
 extern int sysctl_local_port_range[2];
 
+#ifdef CONFIG_INET
 extern __inline__ int ip_send(struct sk_buff *skb)
 {
 	if (skb->len > skb->dst->pmtu)
@@ -181,6 +182,7 @@
 	buf[3]=addr&0x7F;
 }
 
+#endif
 
 extern int	ip_call_ra_chain(struct sk_buff *skb);
 
diff -u --recursive --new-file v2.3.22/linux/include/pcmcia/cs.h linux/include/pcmcia/cs.h
--- v2.3.22/linux/include/pcmcia/cs.h	Tue Sep  7 12:14:07 1999
+++ linux/include/pcmcia/cs.h	Wed Oct 20 21:33:12 1999
@@ -1,5 +1,5 @@
 /*
- * cs.h 1.67 1999/09/02 18:34:59
+ * cs.h 1.68 1999/10/20 18:59:32
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -292,6 +292,7 @@
 #define WIN_SHARED		0x0040
 #define WIN_FIRST_SHARED	0x0080
 #define WIN_USE_WAIT		0x0100
+#define WIN_STRICT_ALIGN	0x0200
 #define WIN_MAP_BELOW_1MB	0x0400
 #define WIN_PREFETCH		0x0800
 #define WIN_CACHEABLE		0x1000
@@ -437,30 +438,6 @@
 extern int CardServices(int func, void *a1, void *a2, void *a3);
 #else
 extern int CardServices(int func, ...);
-#endif
-
-#ifdef __BEOS__
-#define SS_MODULE_NAME(s)	("busses/pcmcia/" s "/v1")
-#define MTD_MODULE_NAME(s)	("busses/pcmcia/" s "/v1")
-#define CS_CLIENT_MODULE_NAME	"bus_managers/pcmcia_cs/client/v1"
-typedef struct cs_client_module_info {
-    bus_manager_info	binfo;
-    int (*_CardServices)(int, ...);
-    int (*_MTDHelperEntry)(int, ...);
-    void (*_add_timer)(struct timer_list *);
-    void (*_del_timer)(struct timer_list *);
-} cs_client_module_info;
-#define CS_SOCKET_MODULE_NAME "bus_managers/pcmcia_cs/socket/v1"
-typedef struct cs_socket_module_info {
-    bus_manager_info	binfo;
-    int (*_register_ss_entry)(int, ss_entry_t);
-    void (*_unregister_ss_entry)(ss_entry_t);
-    void (*_add_timer)(struct timer_list *);
-    void (*_del_timer)(struct timer_list *);
-    int (*register_resource)(int, u_long, u_long);
-    int (*release_resource)(int, u_long, u_long);
-    int (*check_resource)(int, u_long, u_long);
-} cs_socket_module_info;
 #endif
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.3.22/linux/include/pcmcia/cs_types.h linux/include/pcmcia/cs_types.h
--- v2.3.22/linux/include/pcmcia/cs_types.h	Tue Sep  7 12:14:07 1999
+++ linux/include/pcmcia/cs_types.h	Wed Oct 20 21:33:12 1999
@@ -30,9 +30,7 @@
 #ifndef _LINUX_CS_TYPES_H
 #define _LINUX_CS_TYPES_H
 
-#ifdef __linux__
 #include <linux/types.h>
-#endif
 
 typedef u_short	socket_t;
 typedef u_short	ioaddr_t;
diff -u --recursive --new-file v2.3.22/linux/include/pcmcia/driver_ops.h linux/include/pcmcia/driver_ops.h
--- v2.3.22/linux/include/pcmcia/driver_ops.h	Tue Sep  7 12:14:07 1999
+++ linux/include/pcmcia/driver_ops.h	Wed Oct 20 21:33:12 1999
@@ -68,15 +68,6 @@
 int register_driver(struct driver_operations *ops);
 void unregister_driver(struct driver_operations *ops);
 
-#ifdef __BEOS__
-#define CB_ENABLER_MODULE_NAME	"bus_managers/cb_enabler/v1"
-typedef struct cb_enabler_module_info {
-    bus_manager_info	binfo;
-    int (*register_driver)(struct driver_operations *ops);
-    void (*unregister_driver)(struct driver_operations *ops);
-} cb_enabler_module_info;
-#endif /* __BEOS__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_DRIVER_OPS_H */
diff -u --recursive --new-file v2.3.22/linux/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- v2.3.22/linux/include/pcmcia/ds.h	Tue Sep  7 12:14:07 1999
+++ linux/include/pcmcia/ds.h	Wed Oct 20 21:33:12 1999
@@ -143,21 +143,6 @@
 #define register_pcmcia_driver register_pccard_driver
 #define unregister_pcmcia_driver unregister_pccard_driver
 
-#ifdef __BEOS__
-#define DS_MODULE_NAME "bus_managers/pcmcia_ds/v1"
-typedef struct ds_module_info {
-    bus_manager_info binfo;
-    int (*_register_pccard_driver)(dev_info_t *,
-				   dev_link_t *(*)(void),
-				   void (*)(dev_link_t *));
-    int (*_unregister_pccard_driver)(dev_info_t *);
-    struct driver_info_t **root_driver;
-    int *sockets;
-    struct socket_info_t **socket_table;
-    sem_id *list_sem;
-} ds_module_info;
-#endif /* __BEOS__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_DS_H */
diff -u --recursive --new-file v2.3.22/linux/include/pcmcia/version.h linux/include/pcmcia/version.h
--- v2.3.22/linux/include/pcmcia/version.h	Tue Sep  7 12:14:07 1999
+++ linux/include/pcmcia/version.h	Wed Oct 20 21:33:12 1999
@@ -1,4 +1,4 @@
-/* version.h 1.72 1999/08/05 06:09:53 (David Hinds) */
+/* version.h 1.74 1999/09/29 20:41:44 (David Hinds) */
 
-#define CS_RELEASE "3.1.0"
-#define CS_RELEASE_CODE 0x3100
+#define CS_RELEASE "3.1.2"
+#define CS_RELEASE_CODE 0x3102
diff -u --recursive --new-file v2.3.22/linux/init/main.c linux/init/main.c
--- v2.3.22/linux/init/main.c	Fri Oct 15 15:25:14 1999
+++ linux/init/main.c	Tue Oct 19 10:22:19 1999
@@ -24,6 +24,7 @@
 #include <linux/blk.h>
 #include <linux/hdreg.h>
 #include <linux/iobuf.h>
+#include <linux/bootmem.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -56,6 +57,10 @@
 #include <linux/isapnp.h>
 #endif
 
+#ifdef CONFIG_IRDA
+#include <net/irda/irda_device.h>
+#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.
@@ -75,7 +80,6 @@
 
 extern void init_IRQ(void);
 extern void init_modules(void);
-extern long console_init(long, long);
 extern void sock_init(void);
 extern void fork_init(unsigned long);
 extern void mca_init(void);
@@ -106,9 +110,6 @@
 
 extern void time_init(void);
 
-static unsigned long memory_start = 0;
-static unsigned long memory_end = 0;
-
 int rows, cols;
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -419,7 +420,7 @@
 }
 
 
-extern void setup_arch(char **, unsigned long *, unsigned long *);
+extern void setup_arch(char **);
 extern void cpu_idle(void);
 
 #ifndef __SMP__
@@ -446,15 +447,15 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
-
+	unsigned long mempages;
 /*
  * Interrupts are still disabled. Do necessary setups, then
  * enable them
  */
 	lock_kernel();
 	printk(linux_banner);
-	setup_arch(&command_line, &memory_start, &memory_end);
-	memory_start = paging_init(memory_start,memory_end);
+	setup_arch(&command_line);
+	paging_init();
 	trap_init();
 	init_IRQ();
 	sched_init();
@@ -466,40 +467,45 @@
 	 * we've done PCI setups etc, and console_init() must be aware of
 	 * this. But we do want output early, in case something goes wrong.
 	 */
-	memory_start = console_init(memory_start,memory_end);
+	console_init();
 #ifdef CONFIG_MODULES
 	init_modules();
 #endif
 	if (prof_shift) {
-		prof_buffer = (unsigned int *) memory_start;
+		unsigned int size;
 		/* only text is profiled */
 		prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
 		prof_len >>= prof_shift;
-		memory_start += prof_len * sizeof(unsigned int);
-		memset(prof_buffer, 0, prof_len * sizeof(unsigned int));
+		
+		size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1;
+		prof_buffer = (unsigned int *) alloc_bootmem(size);
+		memset(prof_buffer, 0, size);
 	}
 
-	memory_start = kmem_cache_init(memory_start, memory_end);
+	kmem_cache_init();
 	sti();
 	calibrate_delay();
 #ifdef CONFIG_BLK_DEV_INITRD
+	// FIXME, use the bootmem.h interface.
 	if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
 		printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
 		    "disabling it.\n",initrd_start,memory_start);
 		initrd_start = 0;
 	}
 #endif
-	mem_init(memory_start,memory_end);
+	mem_init();
 	kmem_cache_sizes_init();
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
-	fork_init(memory_end-memory_start);
+	mempages = num_physpages;
+
+	fork_init(mempages);
 	filescache_init();
 	dcache_init();
 	vma_init();
-	buffer_init(memory_end-memory_start);
-	page_cache_init(memory_end-memory_start);
+	buffer_init(mempages);
+	page_cache_init(mempages);
 	kiobuf_init();
 	signals_init();
 	inode_init();
diff -u --recursive --new-file v2.3.22/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.22/linux/ipc/shm.c	Sat Oct  9 11:47:50 1999
+++ linux/ipc/shm.c	Tue Oct 19 10:22:20 1999
@@ -1,13 +1,14 @@
 /*
  * linux/ipc/shm.c
  * Copyright (C) 1992, 1993 Krishna Balasubramanian
- *         Many improvements/fixes by Bruno Haible.
+ *	 Many improvements/fixes by Bruno Haible.
  * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
  * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
  *
  * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  * BIGMEM support, Andrea Arcangeli <andrea@suse.de>
  * SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
+ * HIGHMEM support, Ingo Molnar <mingo@redhat.com>
  */
 
 #include <linux/config.h>
@@ -19,20 +20,19 @@
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
 extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
-extern unsigned long get_swap_page (void);
 static int findkey (key_t key);
 static int newseg (key_t key, int shmflg, int size);
 static int shm_map (struct vm_area_struct *shmd);
 static void killseg (int id);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
-static unsigned long shm_nopage(struct vm_area_struct *, unsigned long, int);
+static struct page * shm_nopage(struct vm_area_struct *, unsigned long, int);
 static int shm_swapout(struct vm_area_struct *, struct page *);
 #ifdef CONFIG_PROC_FS
 static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
@@ -108,7 +108,7 @@
 {
 	struct shmid_kernel *shp;
 	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
-	int id, i;
+	int id;
 
 	if (size < SHMMIN)
 		return -EINVAL;
@@ -131,7 +131,7 @@
 		return -ENOMEM;
 	}
 	lock_kernel();
-	shp->shm_pages = (ulong *) vmalloc (numpages*sizeof(ulong));
+	shp->shm_pages = (pte_t *) vmalloc (numpages*sizeof(pte_t));
 	unlock_kernel();
 	if (!shp->shm_pages) {
 		kfree(shp);
@@ -141,7 +141,8 @@
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
+	memset(shp->shm_pages, 0, numpages*sizeof(pte_t));
+
 	shp->u.shm_perm.key = key;
 	shp->u.shm_perm.mode = (shmflg & S_IRWXUGO);
 	shp->u.shm_perm.cuid = shp->u.shm_perm.uid = current->euid;
@@ -214,33 +215,29 @@
 	int rss, swp;
 
 	shp = shm_segs[id];
-	if (shp == IPC_NOID || shp == IPC_UNUSED) {
-		printk ("shm nono: killseg called on unused seg id=%d\n", id);
-		return;
-	}
+	if (shp == IPC_NOID || shp == IPC_UNUSED)
+		BUG();
 	shp->u.shm_perm.seq++;     /* for shmat */
 	shm_seq = (shm_seq+1) % ((unsigned)(1<<31)/SHMMNI); /* increment, but avoid overflow */
 	shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
 	used_segs--;
 	if (id == max_shmid)
 		while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));
-	if (!shp->shm_pages) {
-		printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
-		return;
-	}
+	if (!shp->shm_pages)
+		BUG();
 	spin_unlock(&shm_lock);
 	numpages = shp->shm_npages;
 	for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
 		pte_t pte;
-		pte = __pte(shp->shm_pages[i]);
+		pte = shp->shm_pages[i];
 		if (pte_none(pte))
 			continue;
 		if (pte_present(pte)) {
-			free_page (pte_page(pte));
+			__free_page (pte_page(pte));
 			rss++;
 		} else {
 			lock_kernel();
-			swap_free(pte_val(pte));
+			swap_free(pte);
 			unlock_kernel();
 			swp++;
 		}
@@ -462,8 +459,10 @@
 	   > (unsigned long) current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
 	current->mm->total_vm += tmp >> PAGE_SHIFT;
+	vmlist_modify_lock(current->mm);
 	insert_vm_struct(current->mm, shmd);
 	merge_segments(current->mm, shmd->vm_start, shmd->vm_end);
+	vmlist_modify_unlock(current->mm);
 
 	return 0;
 }
@@ -482,16 +481,12 @@
 
 	down(&current->mm->mmap_sem);
 	spin_lock(&shm_lock);
-	if (shmid < 0) {
-		/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
+	if (shmid < 0)
 		goto out;
-	}
 
 	shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
-	if (shp == IPC_UNUSED || shp == IPC_NOID) {
-		/* printk("shmat() -> EINVAL because shmid = %d is invalid\n",shmid); */
+	if (shp == IPC_UNUSED || shp == IPC_NOID)
 		goto out;
-	}
 
 	if (!(addr = (ulong) shmaddr)) {
 		if (shmflg & SHM_REMAP)
@@ -524,16 +519,9 @@
 	 */
 	if (addr < current->mm->start_stack &&
 	    addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4))
-	{
-		/* printk("shmat() -> EINVAL because segment intersects stack\n"); */
 		goto out;
-	}
-	if (!(shmflg & SHM_REMAP))
-		if ((shmd = find_vma_intersection(current->mm, addr, addr + shp->u.shm_segsz))) {
-			/* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx) intersects an already mapped interval [0x%lx,0x%lx).\n",
-				addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */
-			goto out;
-		}
+	if (!(shmflg & SHM_REMAP) && find_vma_intersection(current->mm, addr, addr + shp->u.shm_segsz))
+		goto out;
 
 	err = -EACCES;
 	if (ipcperms(&shp->u.shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
@@ -566,7 +554,7 @@
 	shmd->vm_offset = 0;
 	shmd->vm_ops = &shm_vm_ops;
 
-	shp->u.shm_nattch++;            /* prevent destruction */
+	shp->u.shm_nattch++;	    /* prevent destruction */
 	spin_unlock(&shm_lock);
 	err = shm_map (shmd);
 	spin_lock(&shm_lock);
@@ -666,86 +654,76 @@
 /*
  * page not present ... go through shm_pages
  */
-static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
 {
 	pte_t pte;
 	struct shmid_kernel *shp;
 	unsigned int idx;
-	unsigned long page;
-	struct page * page_map;
+	struct page * page;
 
 	shp = *(struct shmid_kernel **) shmd->vm_private_data;
 	idx = (address - shmd->vm_start + shmd->vm_offset) >> PAGE_SHIFT;
 
-#ifdef DEBUG_SHM
-	if (shp == IPC_UNUSED || shp == IPC_NOID) {
-		printk ("shm_nopage: id=%d invalid. Race.\n", id);
-		return 0;
-	}
-	if (idx >= shp->shm_npages) {
-		printk ("shm_nopage : too large page index. id=%d\n", id);
-		return 0;
-	}
-#endif
-
 	spin_lock(&shm_lock);
- again:
-	pte = __pte(shp->shm_pages[idx]);
+again:
+	pte = shp->shm_pages[idx];
 	if (!pte_present(pte)) {
 		if (pte_none(pte)) {
 			spin_unlock(&shm_lock);
-			page = __get_free_page(GFP_BIGUSER);
+			page = get_free_highpage(GFP_HIGHUSER);
 			if (!page)
 				goto oom;
-			clear_bigpage(page);
+			clear_highpage(page);
 			spin_lock(&shm_lock);
-			if (pte_val(pte) != shp->shm_pages[idx])
+			if (pte_val(pte) != pte_val(shp->shm_pages[idx]))
 				goto changed;
 		} else {
-			unsigned long entry = pte_val(pte);
+			pte_t entry = pte;
 
 			spin_unlock(&shm_lock);
-			page_map = lookup_swap_cache(entry);
-			if (!page_map) {
+			BUG();
+			page = lookup_swap_cache(entry);
+			if (!page) {
 				lock_kernel();
 				swapin_readahead(entry);
-				page_map = read_swap_cache(entry);
+				page = read_swap_cache(entry);
 				unlock_kernel();
-				if (!page_map)
+				if (!page)
 					goto oom;
 			}
-			delete_from_swap_cache(page_map);
-			page_map = replace_with_bigmem(page_map);
-			page = page_address(page_map);
+			delete_from_swap_cache(page);
+			page = replace_with_highmem(page);
 			lock_kernel();
 			swap_free(entry);
 			unlock_kernel();
 			spin_lock(&shm_lock);
 			shm_swp--;
-			pte = __pte(shp->shm_pages[idx]);
+			pte = shp->shm_pages[idx];
 			if (pte_present(pte))
 				goto present;
 		}
 		shm_rss++;
 		pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
-		shp->shm_pages[idx] = pte_val(pte);
+		shp->shm_pages[idx] = pte;
 	} else
 		--current->maj_flt;  /* was incremented in do_no_page */
 
-done:	/* pte_val(pte) == shp->shm_pages[idx] */
-	get_page(mem_map + MAP_NR(pte_page(pte)));
+done:
+	/* pte_val(pte) == shp->shm_pages[idx] */
+	get_page(pte_page(pte));
 	spin_unlock(&shm_lock);
 	current->min_flt++;
 	return pte_page(pte);
 
 changed:
-	free_page(page);
+	__free_page(page);
 	goto again;
 present:
-	free_page(page);
+	if (page)
+		free_page_and_swap_cache(page);
 	goto done;
 oom:
-	return -1;
+	return (struct page *)(-1);
 }
 
 /*
@@ -758,7 +736,7 @@
 {
 	pte_t page;
 	struct shmid_kernel *shp;
-	unsigned long swap_nr;
+	pte_t swap_entry;
 	unsigned long id, idx;
 	int loop = 0;
 	int counter;
@@ -766,7 +744,7 @@
 	
 	counter = shm_rss >> prio;
 	lock_kernel();
-	if (!counter || !(swap_nr = get_swap_page())) {
+	if (!counter || !pte_val(swap_entry = get_swap_page())) {
 		unlock_kernel();
 		return 0;
 	}
@@ -793,36 +771,37 @@
 	if (idx >= shp->shm_npages)
 		goto next_id;
 
-	page = __pte(shp->shm_pages[idx]);
+	page = shp->shm_pages[idx];
 	if (!pte_present(page))
 		goto check_table;
-	page_map = &mem_map[MAP_NR(pte_page(page))];
+	page_map = pte_page(page);
 	if ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))
 		goto check_table;
-	if (!(gfp_mask & __GFP_BIGMEM) && PageBIGMEM(page_map))
+	if (!(gfp_mask & __GFP_HIGHMEM) && PageHighMem(page_map))
 		goto check_table;
 	swap_attempts++;
 
 	if (--counter < 0) { /* failed */
- failed:
+failed:
 		spin_unlock(&shm_lock);
 		lock_kernel();
-		swap_free (swap_nr);
+		swap_free(swap_entry);
 		unlock_kernel();
 		return 0;
 	}
-	if (page_count(mem_map + MAP_NR(pte_page(page))) != 1)
+	if (page_count(page_map))
 		goto check_table;
-	if (!(page_map = prepare_bigmem_swapout(page_map)))
+	if (!(page_map = prepare_highmem_swapout(page_map)))
 		goto check_table;
-	shp->shm_pages[idx] = swap_nr;
+	shp->shm_pages[idx] = swap_entry;
 	swap_successes++;
 	shm_swp++;
 	shm_rss--;
 	spin_unlock(&shm_lock);
+
 	lock_kernel();
-	swap_duplicate(swap_nr);
-	add_to_swap_cache(page_map, swap_nr);
+	swap_duplicate(swap_entry);
+	add_to_swap_cache(page_map, swap_entry);
 	rw_swap_page(WRITE, page_map, 0);
 	unlock_kernel();
 
@@ -834,13 +813,13 @@
  * Free the swap entry and set the new pte for the shm page.
  */
 static void shm_unuse_page(struct shmid_kernel *shp, unsigned long idx,
-			   unsigned long page, unsigned long entry)
+			pte_t entry, struct page *page)
 {
 	pte_t pte;
 
 	pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
-	shp->shm_pages[idx] = pte_val(pte);
-	get_page(mem_map + MAP_NR(page));
+	shp->shm_pages[idx] = pte;
+	get_page(page);
 	shm_rss++;
 
 	shm_swp--;
@@ -854,20 +833,21 @@
 /*
  * unuse_shm() search for an eventually swapped out shm page.
  */
-void shm_unuse(unsigned long entry, unsigned long page)
+void shm_unuse(pte_t entry, struct page *page)
 {
 	int i, n;
 
 	spin_lock(&shm_lock);
-	for (i = 0; i < SHMMNI; i++)
-		if (shm_segs[i] != IPC_UNUSED && shm_segs[i] != IPC_NOID)
-			for (n = 0; n < shm_segs[i]->shm_npages; n++)
-				if (shm_segs[i]->shm_pages[n] == entry)
-				{
-					shm_unuse_page(shm_segs[i], n,
-						       page, entry);
-					return;
-				}
+	for (i = 0; i < SHMMNI; i++) {
+		struct shmid_kernel *seg = shm_segs[i];
+		if ((seg == IPC_UNUSED) || (seg == IPC_NOID))
+			continue;
+		for (n = 0; n < seg->shm_npages; n++)
+			if (pte_val(seg->shm_pages[n]) == pte_val(entry)) {
+				shm_unuse_page(seg, n, entry, page);
+				return;
+			}
+	}
 	spin_unlock(&shm_lock);
 }
 
diff -u --recursive --new-file v2.3.22/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.22/linux/kernel/exit.c	Thu Aug 26 13:05:42 1999
+++ linux/kernel/exit.c	Mon Oct 18 11:35:32 1999
@@ -135,7 +135,9 @@
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (p->p_opptr == father) {
+			/* We dont want people slaying init */
 			p->exit_signal = SIGCHLD;
+			p->self_exec_id++;
 			p->p_opptr = child_reaper; /* init */
 			if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
 		}
@@ -288,7 +290,7 @@
  */
 static void exit_notify(void)
 {
-	struct task_struct * p;
+	struct task_struct * p, *t;
 
 	forget_original_parent(current);
 	/*
@@ -300,15 +302,39 @@
 	 * and we were the only connection outside, so our pgrp
 	 * is about to become orphaned.
 	 */
-	if ((current->p_pptr->pgrp != current->pgrp) &&
-	    (current->p_pptr->session == current->session) &&
+	 
+	t = current->p_pptr;
+	
+	if ((t->pgrp != current->pgrp) &&
+	    (t->session == current->session) &&
 	    will_become_orphaned_pgrp(current->pgrp, current) &&
 	    has_stopped_jobs(current->pgrp)) {
 		kill_pg(current->pgrp,SIGHUP,1);
 		kill_pg(current->pgrp,SIGCONT,1);
 	}
 
-	/* Let father know we died */
+	/* Let father know we died 
+	 *
+	 * Thread signals are configurable, but you aren't going to use
+	 * that to send signals to arbitary processes. 
+	 * That stops right now.
+	 *
+	 * If the parent exec id doesn't match the exec id we saved
+	 * when we started then we know the parent has changed security
+	 * domain.
+	 *
+	 * If our self_exec id doesn't match our parent_exec_id then
+	 * we have changed execution domain as these two values started
+	 * the same after a fork.
+	 *	
+	 */
+	
+	if(current->exit_signal != SIGCHLD &&
+	    ( current->parent_exec_id != t->self_exec_id  ||
+	      current->self_exec_id != current->parent_exec_id) 
+	    && !capable(CAP_KILL))
+		current->exit_signal = SIGCHLD;
+
 	notify_parent(current, current->exit_signal);
 
 	/*
diff -u --recursive --new-file v2.3.22/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.22/linux/kernel/fork.c	Mon Oct 11 15:38:15 1999
+++ linux/kernel/fork.c	Tue Oct 19 10:22:19 1999
@@ -19,8 +19,8 @@
 #include <linux/vmalloc.h>
 
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
 #include <asm/uaccess.h>
+#include <asm/mmu_context.h>
 
 /* The idle threads do not count.. */
 int nr_threads=0;
@@ -157,7 +157,7 @@
 	return 0;
 }
 
-void __init fork_init(unsigned long memsize)
+void __init fork_init(unsigned long mempages)
 {
 	int i;
 
@@ -175,7 +175,7 @@
 	 * value: the thread structures can take up at most half
 	 * of memory.
 	 */
-	max_threads = memsize / THREAD_SIZE / 2;
+	max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 2;
 
 	init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
 	init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
@@ -693,6 +693,11 @@
 	if (retval)
 		goto bad_fork_cleanup_sighand;
 	p->semundo = NULL;
+	
+	/* Our parent execution domain becomes current domain
+	   These must match for thread signalling to apply */
+	   
+	p->parent_exec_id = p->self_exec_id;
 
 	/* ok, now we should be set up.. */
 	p->swappable = 1;
diff -u --recursive --new-file v2.3.22/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.22/linux/kernel/ksyms.c	Fri Oct 15 15:25:14 1999
+++ linux/kernel/ksyms.c	Mon Oct 18 11:26:37 1999
@@ -36,6 +36,7 @@
 #include <linux/swap.h>
 #include <linux/ctype.h>
 #include <linux/file.h>
+#include <linux/iobuf.h>
 #include <linux/console.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
@@ -118,11 +119,13 @@
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(get_fs_type);
+EXPORT_SYMBOL(get_empty_super);
+EXPORT_SYMBOL(remove_vfsmnt);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(_fput);
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
-EXPORT_SYMBOL(iget);
+EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
 EXPORT_SYMBOL(lookup_dentry);
@@ -140,6 +143,9 @@
 EXPORT_SYMBOL(d_path);
 EXPORT_SYMBOL(__mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_inode_dirty);
+EXPORT_SYMBOL(free_kiovec);
+EXPORT_SYMBOL(brw_kiovec);
+EXPORT_SYMBOL(alloc_kiovec);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
 EXPORT_SYMBOL(filp_open);
diff -u --recursive --new-file v2.3.22/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.3.22/linux/kernel/ptrace.c	Tue Aug 31 17:29:15 1999
+++ linux/kernel/ptrace.c	Wed Oct 20 22:13:20 1999
@@ -10,7 +10,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -23,7 +23,9 @@
 	pgd_t * pgdir;
 	pmd_t * pgmiddle;
 	pte_t * pgtable;
-	unsigned long page;
+	unsigned long mapnr;
+	unsigned long maddr; 
+	struct page *page;
 
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
@@ -39,27 +41,25 @@
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable))
 		goto fault_in_page;
-	page = pte_page(*pgtable);
+	mapnr = pte_pagenr(*pgtable);
 	if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
 		goto fault_in_page;
-	if (MAP_NR(page) >= max_mapnr)
+	if (mapnr >= max_mapnr)
 		return 0;
+	page = mem_map + mapnr;
 	flush_cache_page(vma, addr);
-	{
-		void *src = (void *) (page + (addr & ~PAGE_MASK));
-		void *dst = buf;
-
-		if (write) {
-			dst = src;
-			src = buf;
-		}
-		src = (void *) kmap((unsigned long) src, KM_READ);
-		dst = (void *) kmap((unsigned long) dst, KM_WRITE);
-		memcpy(dst, src, len);
-		kunmap((unsigned long) src, KM_READ);
-		kunmap((unsigned long) dst, KM_WRITE);
+
+	if (write) {
+		maddr = kmap(page, KM_WRITE);
+		memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
+		flush_page_to_ram(page);
+		kunmap(maddr, KM_WRITE);
+	} else {
+		maddr = kmap(page, KM_READ);
+		memcpy(buf, (char *)maddr + (addr & ~PAGE_MASK), len);
+		flush_page_to_ram(page);
+		kunmap(maddr, KM_READ);
 	}
-	flush_page_to_ram(page);
 	return len;
 
 fault_in_page:
@@ -69,23 +69,25 @@
 	return 0;
 
 bad_pgd:
-	printk("ptrace: bad pgd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pgd_val(*pgdir));
+	pgd_ERROR(*pgdir);
 	return 0;
 
 bad_pmd:
-	printk("ptrace: bad pmd in '%s' at %08lx (%08lx)\n", tsk->comm, addr, pmd_val(*pgmiddle));
+	pmd_ERROR(*pgmiddle);
 	return 0;
 }
 
 int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
 {
 	int copied;
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
-
-	if (!vma)
-		return 0;
+	struct vm_area_struct * vma;
 
 	down(&tsk->mm->mmap_sem);
+	vma = find_extend_vma(tsk, addr);
+	if (!vma) {
+		up(&tsk->mm->mmap_sem);
+		return 0;
+	}
 	copied = 0;
 	for (;;) {
 		unsigned long offset = addr & ~PAGE_MASK;
diff -u --recursive --new-file v2.3.22/linux/kernel/time.c linux/kernel/time.c
--- v2.3.22/linux/kernel/time.c	Thu Aug 26 13:05:42 1999
+++ linux/kernel/time.c	Sat Oct 16 17:23:59 1999
@@ -54,6 +54,10 @@
 	do_get_fast_time(t);
 }
 
+/* The xtime_lock is not only serializing the xtime read/writes but it's also
+   serializing all accesses to the global NTP variables now. */
+extern rwlock_t xtime_lock;
+
 #if !defined(__alpha__) && !defined(__ia64__)
 
 /*
@@ -93,14 +97,14 @@
 		return -EPERM;
 	if (get_user(value, tptr))
 		return -EFAULT;
-	cli();
+	write_lock_irq(&xtime_lock);
 	xtime.tv_sec = value;
 	xtime.tv_usec = 0;
 	time_adjust = 0;	/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	write_unlock_irq(&xtime_lock);
 	return 0;
 }
 
@@ -139,9 +143,9 @@
  */
 inline static void warp_clock(void)
 {
-	cli();
+	write_lock_irq(&xtime_lock);
 	xtime.tv_sec += sys_tz.tz_minuteswest * 60;
-	sti();
+	write_unlock_irq(&xtime_lock);
 }
 
 /*
@@ -222,7 +226,7 @@
 int do_adjtimex(struct timex *txc)
 {
         long ltemp, mtemp, save_adjust;
-	int result = time_state;	/* mostly `TIME_OK' */
+	int result;
 
 	/* In order to modify anything, you gotta be super-user! */
 	if (txc->modes && !capable(CAP_SYS_TIME))
@@ -240,7 +244,8 @@
 		if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
 			return -EINVAL;
 
-	cli(); /* SMP: global cli() is enough protection. */
+	write_lock_irq(&xtime_lock);
+	result = time_state;	/* mostly `TIME_OK' */
 
 	/* Save for later - semantics of adjtime is to return old value */
 	save_adjust = time_adjust;
@@ -385,7 +390,6 @@
 	txc->constant	   = time_constant;
 	txc->precision	   = time_precision;
 	txc->tolerance	   = time_tolerance;
-	do_gettimeofday(&txc->time);
 	txc->tick	   = tick;
 	txc->ppsfreq	   = pps_freq;
 	txc->jitter	   = pps_jitter >> PPS_AVG;
@@ -395,8 +399,8 @@
 	txc->calcnt	   = pps_calcnt;
 	txc->errcnt	   = pps_errcnt;
 	txc->stbcnt	   = pps_stbcnt;
-
-	sti();
+	write_unlock_irq(&xtime_lock);
+	do_gettimeofday(&txc->time);
 	return(result);
 }
 
diff -u --recursive --new-file v2.3.22/linux/mm/Makefile linux/mm/Makefile
--- v2.3.22/linux/mm/Makefile	Tue Aug 31 17:29:15 1999
+++ linux/mm/Makefile	Tue Oct 19 10:22:19 1999
@@ -9,11 +9,11 @@
 
 O_TARGET := mm.o
 O_OBJS	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
-	    vmalloc.o slab.o \
-	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
+	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
+	    page_alloc.o swap_state.o swapfile.o
 
-ifeq ($(CONFIG_BIGMEM),y)
-O_OBJS += bigmem.o
+ifeq ($(CONFIG_HIGHMEM),y)
+O_OBJS += highmem.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.22/linux/mm/bigmem.c linux/mm/bigmem.c
--- v2.3.22/linux/mm/bigmem.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/bigmem.c	Wed Dec 31 16:00:00 1969
@@ -1,71 +0,0 @@
-/*
- * BIGMEM common code and variables.
- *
- * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
- *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de
- */
-
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/bigmem.h>
-
-unsigned long bigmem_mapnr;
-int nr_free_bigpages = 0;
-
-struct page * prepare_bigmem_swapout(struct page * page)
-{
-	/* if this is a bigmem page so it can't be swapped out directly
-	   otherwise the b_data buffer addresses will break
-	   the lowlevel device drivers. */
-	if (PageBIGMEM(page)) {
-		unsigned long regular_page;
-		unsigned long vaddr;
-
-		regular_page = __get_free_page(GFP_ATOMIC);
-		if (!regular_page)
-			return NULL;
-
-		vaddr = kmap(page_address(page), KM_READ);
-		copy_page(regular_page, vaddr);
-		kunmap(vaddr, KM_READ);
-
-		/* ok, we can just forget about our bigmem page since 
-		   we stored its data into the new regular_page. */
-		__free_page(page);
-
-		page = MAP_NR(regular_page) + mem_map;
-	}
-	return page;
-}
-
-struct page * replace_with_bigmem(struct page * page)
-{
-	if (!PageBIGMEM(page) && nr_free_bigpages) {
-		unsigned long kaddr;
-
-		kaddr = __get_free_page(GFP_ATOMIC|GFP_BIGMEM);
-		if (kaddr) {
-			struct page * bigmem_page;
-
-			bigmem_page = MAP_NR(kaddr) + mem_map;
-			if (PageBIGMEM(bigmem_page)) {
-				unsigned long vaddr;
-
-				vaddr = kmap(kaddr, KM_WRITE);
-				copy_page(vaddr, page_address(page));
-				kunmap(vaddr, KM_WRITE);
-
-				/* Preserve the caching of the swap_entry. */
-				bigmem_page->offset = page->offset;
-
-				/* We can just forget the old page since 
-				   we stored its data into the new
-				   bigmem_page. */
-				__free_page(page);
-
-				page = bigmem_page;
-			}
-		}
-	}
-	return page;
-}
diff -u --recursive --new-file v2.3.22/linux/mm/bootmem.c linux/mm/bootmem.c
--- v2.3.22/linux/mm/bootmem.c	Wed Dec 31 16:00:00 1969
+++ linux/mm/bootmem.c	Wed Oct 20 16:46:42 1999
@@ -0,0 +1,236 @@
+/*
+ *  linux/mm/initmem.c
+ *
+ *  Copyright (C) 1999 Ingo Molnar
+ *
+ *  simple boot-time physical memory area allocator and
+ *  free memory collector. It's used to deal with reserved
+ *  system memory and memory holes as well.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+#include <linux/swap.h>
+#include <linux/swapctl.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/dma.h>
+
+/*
+ * Pointer to a bitmap - the bits represent all physical memory pages
+ * from physical address 0 to physical address end_mem.
+ *
+ * Access to this subsystem has to be serialized externally. (this is
+ * true for the boot process anyway)
+ */
+unsigned long max_low_pfn;
+
+static void * bootmem_map = NULL;
+
+/*
+ * Called once to set up the allocator itself.
+ */
+unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
+{
+	unsigned long mapsize = (pages+7)/8;
+
+	if (bootmem_map)
+		BUG();
+	bootmem_map = __va(start << PAGE_SHIFT);
+	max_low_pfn = pages;
+
+	/*
+	 * Initially all pages are reserved - setup_arch() has to
+	 * register free RAM areas explicitly.
+	 */
+	memset(bootmem_map, 0xff, mapsize);
+
+	return mapsize;
+}
+
+/*
+ * Marks a particular physical memory range as usable. Usable RAM
+ * might be used for boot-time allocations - or it might get added
+ * to the free page pool later on.
+ */
+void __init reserve_bootmem (unsigned long addr, unsigned long size)
+{
+	unsigned long i;
+	/*
+	 * round up, partially reserved pages are considered
+	 * fully reserved.
+	 */
+	unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE;
+
+	if (!bootmem_map) BUG();
+	if (!size) BUG();
+
+	if (end > max_low_pfn)
+		BUG();
+	for (i = addr/PAGE_SIZE; i < end; i++)
+		if (test_and_set_bit(i, bootmem_map))
+			BUG();
+}
+
+void __init free_bootmem (unsigned long addr, unsigned long size)
+{
+	unsigned long i;
+	/*
+	 * round down end of usable mem, partially free pages are
+	 * considered reserved.
+	 */
+	unsigned long end = (addr + size)/PAGE_SIZE;
+
+	if (!bootmem_map) BUG();
+	if (!size) BUG();
+
+	if (end > max_low_pfn)
+		BUG();
+	for (i = addr/PAGE_SIZE; i < end; i++) {
+		if (!test_and_clear_bit(i, bootmem_map))
+			BUG();
+	}
+}
+
+/*
+ * We 'merge' subsequent allocations to save space. We might 'lose'
+ * some fraction of a page if allocations cannot be satisfied due to
+ * size constraints on boxes where there is physical RAM space
+ * fragmentation - in these cases * (mostly large memory boxes) this
+ * is not a problem.
+ *
+ * On low memory boxes we get it right in 100% of the cases.
+ */
+static unsigned long last_pos = 0;
+static unsigned long last_offset = 0;
+
+/*
+ * alignment has to be a power of 2 value.
+ */
+void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
+{
+	int area = 0;
+	unsigned long i, start = 0, reserved;
+	void *ret;
+	unsigned long offset, remaining_size;
+	unsigned long areasize, preferred;
+
+	if (!bootmem_map) BUG();
+	if (!size) BUG();
+
+	/*
+	 * We try to allocate bootmem pages above 'goal'
+	 * first, then we try to allocate lower pages.
+	 */
+	if (goal) {
+		preferred = goal >> PAGE_SHIFT;
+		if (preferred >= max_low_pfn)
+			preferred = 0;
+	} else
+		preferred = 0;
+
+	areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
+
+restart_scan:
+	for (i = preferred; i < max_low_pfn; i++) {
+		reserved = test_bit(i, bootmem_map);
+		if (!reserved) {
+			if (!area) {
+				area = 1;
+				start = i;
+			}
+			if (i - start + 1 == areasize)
+				goto found;
+		} else {
+			area = 0;
+			start = -1;
+		}
+	}
+	if (preferred) {
+		preferred = 0;
+		goto restart_scan;
+	}
+	BUG();
+found:
+	if (start >= max_low_pfn)
+		BUG();
+
+	/*
+	 * Is the next page of the previous allocation-end the start
+	 * of this allocation's buffer? If yes then we can 'merge'
+	 * the previous partial page with this allocation.
+	 */
+	if (last_offset && (last_pos+1 == start)) {
+		offset = (last_offset+align-1) & ~(align-1);
+		if (offset > PAGE_SIZE)
+			BUG();
+		remaining_size = PAGE_SIZE-offset;
+		if (remaining_size > PAGE_SIZE)
+			BUG();
+		if (size < remaining_size) {
+			areasize = 0;
+			// last_pos unchanged
+			last_offset = offset+size;
+			ret = __va(last_pos*PAGE_SIZE + offset);
+		} else {
+			size -= remaining_size;
+			areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
+			ret = __va(last_pos*PAGE_SIZE + offset);
+			last_pos = start+areasize-1;
+			last_offset = size;
+		}
+ 		last_offset &= ~PAGE_MASK;
+	} else {
+		last_pos = start + areasize - 1;
+		last_offset = size & ~PAGE_MASK;
+		ret = __va(start * PAGE_SIZE);
+	}
+	/*
+	 * Reserve the area now:
+	 */
+	for (i = start; i < start+areasize; i++)
+		if (test_and_set_bit(i, bootmem_map))
+			BUG();
+
+	return ret;
+}
+
+unsigned long __init free_all_bootmem (void)
+{
+	struct page * page;
+	unsigned long i, count, total = 0;
+
+	if (!bootmem_map) BUG();
+
+	page = mem_map;
+	count = 0;
+	for (i = 0; i < max_low_pfn; i++, page++) {
+		if (!test_bit(i, bootmem_map)) {
+			count++;
+			ClearPageReserved(page);
+			set_page_count(page, 1);
+			if (i >= (__pa(MAX_DMA_ADDRESS) >> PAGE_SHIFT))
+				clear_bit(PG_DMA, &page->flags);
+			__free_page(page);
+		}
+	}
+	total += count;
+	/*
+	 * Now free the allocator bitmap itself, it's not
+	 * needed anymore:
+	 */
+	page = mem_map + MAP_NR(bootmem_map);
+	count = 0;
+	for (i = 0; i < (max_low_pfn/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
+		count++;
+		ClearPageReserved(page);
+		set_page_count(page, 1);
+		__free_page(page);
+	}
+	total += count;
+	bootmem_map = NULL;
+
+	return total;
+}
diff -u --recursive --new-file v2.3.22/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.22/linux/mm/filemap.c	Mon Oct 11 15:38:15 1999
+++ linux/mm/filemap.c	Fri Oct 22 12:44:00 1999
@@ -21,6 +21,7 @@
 #include <linux/swapctl.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/highmem.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -75,24 +76,6 @@
 	atomic_dec(&page_cache_size);
 }
 
-static void remove_page_from_inode_queue(struct page * page)
-{
-	struct inode * inode = page->inode;
-	struct page *prev, *next;
-
-	inode->i_nrpages--;
-	next = page->next;
-	prev = page->prev;
-	if (inode->i_pages == page)
-		inode->i_pages = next;
-	if (next)
-		next->prev = prev;
-	if (prev)
-		prev->next = next;
-	page->next = NULL;
-	page->prev = NULL;
-}
-
 /*
  * Remove a page from the page cache and free it. Caller has to make
  * sure the page is locked and that nobody else uses it - or that usage
@@ -112,49 +95,53 @@
 
 void invalidate_inode_pages(struct inode * inode)
 {
-	struct page ** p;
+	struct list_head *head, *curr;
 	struct page * page;
 
+	head = &inode->i_pages;
 repeat:
 	spin_lock(&pagecache_lock);
-	p = &inode->i_pages;
-	while ((page = *p) != NULL) {
-		get_page(page);
-		if (TryLockPage(page)) {
-			spin_unlock(&pagecache_lock);
-			wait_on_page(page);
-			page_cache_release(page);
-			goto repeat;
-		}
-		if (page_count(page) != 2)
-			printk("hm, busy page invalidated? (not necessarily a bug)\n");
+	curr = head->next;
+
+	while (curr != head) {
+		page = list_entry(curr, struct page, list);
+		curr = curr->next;
+
+		/* We cannot invalidate a locked page */
+		if (PageLocked(page))
+			continue;
+
 		lru_cache_del(page);
 
 		remove_page_from_inode_queue(page);
 		remove_page_from_hash_queue(page);
 		page->inode = NULL;
-		UnlockPage(page);
-		page_cache_release(page);
 		page_cache_release(page);
-
 	}
 	spin_unlock(&pagecache_lock);
 }
+
 /*
  * Truncate the page cache at a set offset, removing the pages
  * that are beyond that offset (and zeroing out partial pages).
  */
 void truncate_inode_pages(struct inode * inode, unsigned long start)
 {
-	struct page ** p;
+	struct list_head *head, *curr;
+	unsigned long offset;
 	struct page * page;
 	int partial = 0;
 
 repeat:
+	head = &inode->i_pages;
 	spin_lock(&pagecache_lock);
-	p = &inode->i_pages;
-	while ((page = *p) != NULL) {
-		unsigned long offset = page->offset;
+	curr = head->next;
+	while (curr != head) {
+
+		page = list_entry(curr, struct page, list);
+		curr = curr->next;
+
+		offset = page->offset;
 
 		/* page wholly truncated - free it */
 		if (offset >= start) {
@@ -190,7 +177,6 @@
 			 */
 			goto repeat;
 		}
-		p = &page->next;
 		/*
 		 * there is only one partial page possible.
 		 */
@@ -200,17 +186,14 @@
 		offset = start - offset;
 		/* partial truncate, clear end of page */
 		if (offset < PAGE_CACHE_SIZE) {
-			unsigned long address;
 			get_page(page);
 			spin_unlock(&pagecache_lock);
 
 			lock_page(page);
 			partial = 1;
 
-			address = page_address(page);
-			memset((void *) (offset + address), 0, PAGE_CACHE_SIZE - offset);
-			flush_page_to_ram(address);
-
+			memclear_highpage_flush(page, offset,
+						PAGE_CACHE_SIZE-offset);
 			if (inode->i_op->flushpage)
 				inode->i_op->flushpage(inode, page, offset);
 			/*
@@ -255,7 +238,7 @@
 		/* don't account passes over not DMA pages */
 		if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
 			goto dispose_continue;
-		if (!(gfp_mask & __GFP_BIGMEM) && PageBIGMEM(page))
+		if (!(gfp_mask & __GFP_HIGHMEM) && PageHighMem(page))
 			goto dispose_continue;
 
 		count--;
@@ -291,7 +274,7 @@
 				goto unlock_continue;
 			/* page was locked, inode can't go away under us */
 			if (!page->inode) {
-				atomic_sub(PAGE_CACHE_SIZE, &buffermem);
+				atomic_dec(&buffermem_pages);
 				goto made_buffer_progress;
 			}
 			spin_lock(&pagecache_lock);
@@ -431,16 +414,18 @@
 
 static int do_buffer_fdatasync(struct inode *inode, unsigned long start, unsigned long end, int (*fn)(struct page *))
 {
-	struct page *next;
+	struct list_head *head, *curr;
+	struct page *page;
 	int retval = 0;
 
+	head = &inode->i_pages;
 	start &= PAGE_MASK;
 
 	spin_lock(&pagecache_lock);
-	next = inode->i_pages;
-	while (next) {
-		struct page *page = next;
-		next = page->next;
+	curr = head->next;
+	while (curr != head) {
+		page = list_entry(curr, struct page, list);
+		curr = curr->next;
 		if (!page->buffers)
 			continue;
 		if (page->offset >= end)
@@ -458,7 +443,7 @@
 
 		UnlockPage(page);
 		spin_lock(&pagecache_lock);
-		next = page->next;
+		curr = page->list.next;
 		page_cache_release(page);
 	}
 	spin_unlock(&pagecache_lock);
@@ -487,6 +472,7 @@
 	struct inode * inode, unsigned long offset,
 	struct page **hash)
 {
+	struct page *alias;
 	unsigned long flags;
 
 	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced));
@@ -497,6 +483,9 @@
 	add_page_to_inode_queue(inode, page);
 	__add_page_to_hash_queue(page, hash);
 	lru_cache_add(page);
+	alias = __find_page_nolock(inode, offset, *hash);
+	if (alias != page)
+		BUG();
 }
 
 void add_to_page_cache(struct page * page, struct inode * inode, unsigned long offset)
@@ -532,10 +521,9 @@
  */
 static inline void page_cache_read(struct file * file, unsigned long offset) 
 {
-	unsigned long new_page;
 	struct inode *inode = file->f_dentry->d_inode;
-	struct page ** hash = page_hash(inode, offset);
-	struct page * page; 
+	struct page **hash = page_hash(inode, offset);
+	struct page *page; 
 
 	spin_lock(&pagecache_lock);
 	page = __find_page_nolock(inode, offset, *hash); 
@@ -543,22 +531,20 @@
 	if (page)
 		return;
 
-	new_page = page_cache_alloc();
-	if (!new_page)
+	page = page_cache_alloc();
+	if (!page)
 		return;
-	page = page_cache_entry(new_page);
 
 	if (!add_to_page_cache_unique(page, inode, offset, hash)) {
 		inode->i_op->readpage(file, page);
 		page_cache_release(page);
 		return;
 	}
-
 	/*
 	 * We arrive here in the unlikely event that someone 
 	 * raced with us and added our page to the cache first.
 	 */
-	page_cache_free(new_page);
+	page_cache_free(page);
 	return;
 }
 
@@ -962,13 +948,13 @@
 {
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	size_t pos, pgpos, page_cache;
+	size_t pos, pgpos;
+	struct page *cached_page;
 	int reada_ok;
 	int error;
 	int max_readahead = get_max_readahead(inode);
 
-	page_cache = 0;
-
+	cached_page = NULL;
 	pos = *ppos;
 	pgpos = pos & PAGE_CACHE_MASK;
 /*
@@ -1051,7 +1037,7 @@
 		 * "pos" here (the actor routine has to update the user buffer
 		 * pointers and the remaining count).
 		 */
-		nr = actor(desc, (const char *) (page_address(page) + offset), nr);
+		nr = actor(desc, page, offset, nr);
 		pos += nr;
 		page_cache_release(page);
 		if (nr && desc->count)
@@ -1105,10 +1091,10 @@
 		 *
 		 * We get here with the page cache lock held.
 		 */
-		if (!page_cache) {
+		if (!cached_page) {
 			spin_unlock(&pagecache_lock);
-			page_cache = page_cache_alloc();
-			if (!page_cache) {
+			cached_page = page_cache_alloc();
+			if (!cached_page) {
 				desc->error = -ENOMEM;
 				break;
 			}
@@ -1126,29 +1112,35 @@
 		/*
 		 * Ok, add the new page to the hash-queues...
 		 */
-		page = page_cache_entry(page_cache);
+		page = cached_page;
 		__add_to_page_cache(page, inode, pos & PAGE_CACHE_MASK, hash);
 		spin_unlock(&pagecache_lock);
+		cached_page = NULL;
 
-		page_cache = 0;
 		goto readpage;
 	}
 
 	*ppos = pos;
 	filp->f_reada = 1;
-	if (page_cache)
-		page_cache_free(page_cache);
+	if (cached_page)
+		page_cache_free(cached_page);
 	UPDATE_ATIME(inode);
 }
 
-static int file_read_actor(read_descriptor_t * desc, const char *area, unsigned long size)
+static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
 {
-	unsigned long left;
-	unsigned long count = desc->count;
+	unsigned long kaddr;
+	unsigned long left, count = desc->count;
 
 	if (size > count)
 		size = count;
-	left = __copy_to_user(desc->buf, area, size);
+	/*
+	 * FIXME: We cannot yet sleep with kmaps held.
+	 */
+	kaddr = kmap(page, KM_READ);
+	left = __copy_to_user(desc->buf, (void *)(kaddr+offset), size);
+	kunmap(kaddr, KM_READ);
+	
 	if (left) {
 		size -= left;
 		desc->error = -EFAULT;
@@ -1187,8 +1179,9 @@
 	return retval;
 }
 
-static int file_send_actor(read_descriptor_t * desc, const char *area, unsigned long size)
+static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size)
 {
+	unsigned long kaddr;
 	ssize_t written;
 	unsigned long count = desc->count;
 	struct file *file = (struct file *) desc->buf;
@@ -1198,7 +1191,9 @@
 		size = count;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	written = file->f_op->write(file, area, size, &file->f_pos);
+	kaddr = kmap(page, KM_READ);
+	written = file->f_op->write(file, (char *)kaddr + offset, size, &file->f_pos);
+	kunmap(kaddr, KM_READ);
 	set_fs(old_fs);
 	if (written < 0) {
 		desc->error = written;
@@ -1298,14 +1293,13 @@
  * XXX - at some point, this should return unique values to indicate to
  *       the caller whether this is EIO, OOM, or SIGBUS.
  */
-static unsigned long filemap_nopage(struct vm_area_struct * area,
+static struct page * filemap_nopage(struct vm_area_struct * area,
 	unsigned long address, int no_share)
 {
-	struct file * file = area->vm_file;
-	struct dentry * dentry = file->f_dentry;
-	struct inode * inode = dentry->d_inode;
-	struct page * page, **hash;
-	unsigned long old_page;
+	struct file *file = area->vm_file;
+	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	struct page *page, **hash, *old_page;
 
 	unsigned long offset = address - area->vm_start + area->vm_offset;
 
@@ -1317,7 +1311,7 @@
 	 */
 	if ((offset >= inode->i_size) &&
 		(area->vm_flags & VM_SHARED) && (area->vm_mm == current->mm))
-		return 0;
+		return NULL;
 
 	/*
 	 * Do we have something in the page cache already?
@@ -1340,12 +1334,14 @@
 	 * Found the page and have a reference on it, need to check sharing
 	 * and possibly copy it over to another page..
 	 */
-	old_page = page_address(page);
+	old_page = page;
 	if (no_share) {
-		unsigned long new_page = page_cache_alloc();
+		struct page *new_page = page_cache_alloc();
 
 		if (new_page) {
-			copy_page(new_page, old_page);
+			if (PageHighMem(new_page) || PageHighMem(old_page))
+				BUG();
+			copy_highpage(new_page, old_page);
 			flush_page_to_ram(new_page);
 		}
 		page_cache_release(page);
@@ -1411,7 +1407,7 @@
 	 * mm layer so, possibly freeing the page cache page first.
 	 */
 	page_cache_release(page);
-	return 0;
+	return NULL;
 }
 
 /*
@@ -1419,12 +1415,11 @@
  * if the disk is full.
  */
 static inline int do_write_page(struct inode * inode, struct file * file,
-	const char * page_addr, unsigned long offset)
+	struct page * page, unsigned long offset)
 {
 	int retval;
 	unsigned long size;
 	int (*writepage) (struct file *, struct page *);
-	struct page * page;
 
 	size = offset + PAGE_SIZE;
 	/* refuse to extend file size.. */
@@ -1438,7 +1433,6 @@
 	size -= offset;
 	retval = -EIO;
 	writepage = inode->i_op->writepage;
-	page = mem_map + MAP_NR(page_addr);
 	lock_page(page);
 
 	retval = writepage(file, page);
@@ -1449,7 +1443,7 @@
 
 static int filemap_write_page(struct vm_area_struct * vma,
 			      unsigned long offset,
-			      unsigned long page,
+			      struct page * page,
 			      int wait)
 {
 	int result;
@@ -1466,7 +1460,7 @@
 	 * and file could be released ... increment the count to be safe.
 	 */
 	get_file(file);
-	result = do_write_page(inode, file, (const char *) page, offset);
+	result = do_write_page(inode, file, page, offset);
 	fput(file);
 	return result;
 }
@@ -1480,7 +1474,7 @@
 extern void wakeup_bdflush(int);
 int filemap_swapout(struct vm_area_struct * vma, struct page * page)
 {
-	int retval = filemap_write_page(vma, page->offset, page_address(page), 0);
+	int retval = filemap_write_page(vma, page->offset, page, 0);
 	wakeup_bdflush(0);
 	return retval;
 }
@@ -1489,7 +1483,6 @@
 	unsigned long address, unsigned int flags)
 {
 	pte_t pte = *ptep;
-	unsigned long pageaddr;
 	struct page *page;
 	int error;
 
@@ -1502,8 +1495,7 @@
 		flush_cache_page(vma, address);
 		set_pte(ptep, pte_mkclean(pte));
 		flush_tlb_page(vma, address);
-		pageaddr = pte_page(pte);
-		page = page_cache_entry(pageaddr);
+		page = pte_page(pte);
 		get_page(page);
 	} else {
 		if (pte_none(pte))
@@ -1512,17 +1504,19 @@
 		pte_clear(ptep);
 		flush_tlb_page(vma, address);
 		if (!pte_present(pte)) {
-			swap_free(pte_val(pte));
+			swap_free(pte);
 			return 0;
 		}
-		pageaddr = pte_page(pte);
+		page = pte_page(pte);
 		if (!pte_dirty(pte) || flags == MS_INVALIDATE) {
-			page_cache_free(pageaddr);
+			page_cache_free(page);
 			return 0;
 		}
 	}
-	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, pageaddr, 1);
-	page_cache_free(pageaddr);
+	if (PageHighMem(page))
+		BUG();
+	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page, 1);
+	page_cache_free(page);
 	return error;
 }
 
@@ -1537,7 +1531,7 @@
 	if (pmd_none(*pmd))
 		return 0;
 	if (pmd_bad(*pmd)) {
-		printk("filemap_sync_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		return 0;
 	}
@@ -1552,7 +1546,7 @@
 		error |= filemap_sync_pte(pte, vma, address + offset, flags);
 		address += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 	return error;
 }
 
@@ -1567,7 +1561,7 @@
 	if (pgd_none(*pgd))
 		return 0;
 	if (pgd_bad(*pgd)) {
-		printk("filemap_sync_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
+		pgd_ERROR(*pgd);
 		pgd_clear(pgd);
 		return 0;
 	}
@@ -1582,7 +1576,7 @@
 		error |= filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 	return error;
 }
 
@@ -1595,11 +1589,13 @@
 
 	dir = pgd_offset(vma->vm_mm, address);
 	flush_cache_range(vma->vm_mm, end - size, end);
-	while (address < end) {
+	if (address >= end)
+		BUG();
+	do {
 		error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
 	flush_tlb_range(vma->vm_mm, end - size, end);
 	return error;
 }
@@ -1775,12 +1771,13 @@
 	struct inode	*inode = dentry->d_inode; 
 	unsigned long	pos = *ppos;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-	struct page	*page, **hash;
-	unsigned long	page_cache = 0;
+	struct page	*page, **hash, *cached_page;
 	unsigned long	written;
 	long		status;
 	int		err;
 
+	cached_page = NULL;
+
 	down(&inode->i_sem);
 	err = file->f_error;
 	if (err) {
@@ -1828,18 +1825,18 @@
 repeat_find:
 		page = __find_lock_page(inode, pgpos, hash);
 		if (!page) {
-			if (!page_cache) {
-				page_cache = page_cache_alloc();
-				if (page_cache)
+			if (!cached_page) {
+				cached_page = page_cache_alloc();
+				if (cached_page)
 					goto repeat_find;
 				status = -ENOMEM;
 				break;
 			}
-			page = page_cache_entry(page_cache);
+			page = cached_page;
 			if (add_to_page_cache_unique(page,inode,pgpos,hash))
 				goto repeat_find;
 
-			page_cache = 0;
+			cached_page = NULL;
 		}
 
 		/* We have exclusive IO access to the page.. */
@@ -1870,8 +1867,8 @@
 	}
 	*ppos = pos;
 
-	if (page_cache)
-		page_cache_free(page_cache);
+	if (cached_page)
+		page_cache_free(cached_page);
 
 	err = written ? written : status;
 out:
@@ -1897,11 +1894,11 @@
 	page_cache_release(page);
 }
 
-void __init page_cache_init(unsigned long memory_size)
+void __init page_cache_init(unsigned long mempages)
 {
 	unsigned long htable_size, order;
 
-	htable_size = memory_size >> PAGE_SHIFT;
+	htable_size = mempages;
 	htable_size *= sizeof(struct page *);
 	for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
 		;
@@ -1921,5 +1918,5 @@
 	       (1 << page_hash_bits), order, (PAGE_SIZE << order));
 	if (!page_hash_table)
 		panic("Failed to allocate page hash table\n");
-	memset(page_hash_table, 0, PAGE_HASH_SIZE * sizeof(struct page *));
+	memset((void *)page_hash_table, 0, PAGE_HASH_SIZE * sizeof(struct page *));
 }
diff -u --recursive --new-file v2.3.22/linux/mm/highmem.c linux/mm/highmem.c
--- v2.3.22/linux/mm/highmem.c	Wed Dec 31 16:00:00 1969
+++ linux/mm/highmem.c	Tue Oct 19 10:22:19 1999
@@ -0,0 +1,81 @@
+/*
+ * High memory handling common code and variables.
+ *
+ * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
+ *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * 64-bit physical space. With current x86 CPUs this
+ * means up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+
+unsigned long highmem_mapnr;
+unsigned long nr_free_highpages = 0;
+
+struct page * prepare_highmem_swapout(struct page * page)
+{
+	unsigned long regular_page;
+	unsigned long vaddr;
+	/*
+	 * If this is a highmem page so it can't be swapped out directly
+	 * otherwise the b_data buffer addresses will break
+	 * the lowlevel device drivers.
+	 */
+	if (!PageHighMem(page))
+		return page;
+
+	regular_page = __get_free_page(GFP_ATOMIC);
+	if (!regular_page)
+		return NULL;
+
+	vaddr = kmap(page, KM_READ);
+	copy_page((void *)regular_page, (void *)vaddr);
+	kunmap(vaddr, KM_READ);
+
+	/*
+	 * ok, we can just forget about our highmem page since 
+	 * we stored its data into the new regular_page.
+	 */
+	__free_page(page);
+
+	return mem_map + MAP_NR(regular_page);
+}
+
+struct page * replace_with_highmem(struct page * page)
+{
+	struct page *highpage;
+	unsigned long vaddr;
+
+	if (PageHighMem(page) || !nr_free_highpages)
+		return page;
+
+	highpage = get_free_highpage(GFP_ATOMIC|__GFP_HIGHMEM);
+	if (!highpage)
+		return page;
+	if (!PageHighMem(highpage)) {
+		__free_page(highpage);
+		return page;
+	}
+
+	vaddr = kmap(highpage, KM_WRITE);
+	copy_page((void *)vaddr, (void *)page_address(page));
+	kunmap(vaddr, KM_WRITE);
+
+	/* Preserve the caching of the swap_entry. */
+	highpage->offset = page->offset;
+	highpage->inode = page->inode;
+
+	/*
+	 * We can just forget the old page since 
+	 * we stored its data into the new highmem-page.
+	 */
+	__free_page(page);
+
+	return highpage;
+}
diff -u --recursive --new-file v2.3.22/linux/mm/memory.c linux/mm/memory.c
--- v2.3.22/linux/mm/memory.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/memory.c	Wed Oct 20 22:13:20 1999
@@ -43,7 +43,7 @@
 #include <linux/smp_lock.h>
 #include <linux/swapctl.h>
 #include <linux/iobuf.h>
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -51,19 +51,20 @@
 unsigned long max_mapnr = 0;
 unsigned long num_physpages = 0;
 void * high_memory = NULL;
+struct page *highmem_start_page;
 
 /*
  * We special-case the C-O-W ZERO_PAGE, because it's such
  * a common occurrence (no need to read the page to know
  * that it's zero - better for the cache and memory subsystem).
  */
-static inline void copy_cow_page(unsigned long from, unsigned long to)
+static inline void copy_cow_page(struct page * from, struct page * to)
 {
 	if (from == ZERO_PAGE(to)) {
-		clear_bigpage(to);
+		clear_highpage(to);
 		return;
 	}
-	copy_bigpage(to, from);
+	copy_highpage(to, from);
 }
 
 mem_map_t * mem_map = NULL;
@@ -89,7 +90,7 @@
 	if (pmd_none(*dir))
 		return;
 	if (pmd_bad(*dir)) {
-		printk("free_one_pmd: bad directory entry %08lx\n", pmd_val(*dir));
+		pmd_ERROR(*dir);
 		pmd_clear(dir);
 		return;
 	}
@@ -106,7 +107,7 @@
 	if (pgd_none(*dir))
 		return;
 	if (pgd_bad(*dir)) {
-		printk("free_one_pgd: bad directory entry %08lx\n", pgd_val(*dir));
+		pgd_ERROR(*dir);
 		pgd_clear(dir);
 		return;
 	}
@@ -179,11 +180,10 @@
 		if (pgd_none(*src_pgd))
 			goto skip_copy_pmd_range;
 		if (pgd_bad(*src_pgd)) {
-			printk("copy_pmd_range: bad pgd (%08lx)\n", 
-				pgd_val(*src_pgd));
+			pgd_ERROR(*src_pgd);
 			pgd_clear(src_pgd);
 skip_copy_pmd_range:	address = (address + PGDIR_SIZE) & PGDIR_MASK;
-			if (address >= end)
+			if (!address || (address >= end))
 				goto out;
 			continue;
 		}
@@ -203,7 +203,7 @@
 			if (pmd_none(*src_pmd))
 				goto skip_copy_pte_range;
 			if (pmd_bad(*src_pmd)) {
-				printk("copy_pte_range: bad pmd (%08lx)\n", pmd_val(*src_pmd));
+				pmd_ERROR(*src_pmd);
 				pmd_clear(src_pmd);
 skip_copy_pte_range:		address = (address + PMD_SIZE) & PMD_MASK;
 				if (address >= end)
@@ -227,11 +227,11 @@
 				if (pte_none(pte))
 					goto cont_copy_pte_range;
 				if (!pte_present(pte)) {
-					swap_duplicate(pte_val(pte));
+					swap_duplicate(pte);
 					set_pte(dst_pte, pte);
 					goto cont_copy_pte_range;
 				}
-				page_nr = MAP_NR(pte_page(pte));
+				page_nr = pte_pagenr(pte);
 				if (page_nr >= max_mapnr || 
 				    PageReserved(mem_map+page_nr)) {
 					set_pte(dst_pte, pte);
@@ -272,17 +272,17 @@
 static inline int free_pte(pte_t page)
 {
 	if (pte_present(page)) {
-		unsigned long addr = pte_page(page);
-		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
+		unsigned long nr = pte_pagenr(page);
+		if (nr >= max_mapnr || PageReserved(mem_map+nr))
 			return 0;
 		/* 
 		 * free_page() used to be able to clear swap cache
 		 * entries.  We may now have to do it manually.  
 		 */
-		free_page_and_swap_cache(addr);
+		free_page_and_swap_cache(mem_map+nr);
 		return 1;
 	}
-	swap_free(pte_val(page));
+	swap_free(page);
 	return 0;
 }
 
@@ -302,7 +302,7 @@
 	if (pmd_none(*pmd))
 		return 0;
 	if (pmd_bad(*pmd)) {
-		printk("zap_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		return 0;
 	}
@@ -336,7 +336,7 @@
 	if (pgd_none(*dir))
 		return 0;
 	if (pgd_bad(*dir)) {
-		printk("zap_pmd_range: bad pgd (%08lx)\n", pgd_val(*dir));
+		pgd_ERROR(*dir);
 		pgd_clear(dir);
 		return 0;
 	}
@@ -372,12 +372,14 @@
 	 * even if kswapd happened to be looking at this
 	 * process we _want_ it to get stuck.
 	 */
+	if (address >= end)
+		BUG();
 	spin_lock(&mm->page_table_lock);
-	while (address < end) {
+	do {
 		freed += zap_pmd_range(mm, dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
 	spin_unlock(&mm->page_table_lock);
 	/*
 	 * Update rss for the mm_struct (not necessarily current->mm)
@@ -393,7 +395,7 @@
 /*
  * Do a quick page-table lookup for a single page. 
  */
-static unsigned long follow_page(unsigned long address) 
+static struct page * follow_page(unsigned long address) 
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
@@ -402,31 +404,27 @@
 	pmd = pmd_offset(pgd, address);
 	if (pmd) {
 		pte_t * pte = pte_offset(pmd, address);
-		if (pte && pte_present(*pte)) {
+		if (pte && pte_present(*pte))
 			return pte_page(*pte);
-		}
 	}
 	
 	printk(KERN_ERR "Missing page in follow_page\n");
-	return 0;
+	return NULL;
 }
 
 /* 
  * Given a physical address, is there a useful struct page pointing to it?
  */
 
-static struct page * get_page_map(unsigned long page)
+struct page * get_page_map(struct page *page)
 {
-	struct page *map;
-	
 	if (MAP_NR(page) >= max_mapnr)
 		return 0;
 	if (page == ZERO_PAGE(page))
 		return 0;
-	map = mem_map + MAP_NR(page);
-	if (PageReserved(map))
+	if (PageReserved(page))
 		return 0;
-	return map;
+	return page;
 }
 
 /*
@@ -441,7 +439,6 @@
 	int			err;
 	struct mm_struct *	mm;
 	struct vm_area_struct *	vma = 0;
-	unsigned long		page;
 	struct page *		map;
 	int			doublepage = 0;
 	int			repeat = 0;
@@ -482,13 +479,12 @@
 		if (handle_mm_fault(current, vma, ptr, (rw==READ)) <= 0) 
 			goto out_unlock;
 		spin_lock(&mm->page_table_lock);
-		page = follow_page(ptr);
-		if (!page) {
+		map = follow_page(ptr);
+		if (!map) {
 			dprintk (KERN_ERR "Missing page in map_user_kiobuf\n");
-			map = NULL;
 			goto retry;
 		}
-		map = get_page_map(page);
+		map = get_page_map(map);
 		if (map) {
 			if (TryLockPage(map)) {
 				goto retry;
@@ -496,8 +492,6 @@
 			atomic_inc(&map->count);
 		}
 		spin_unlock(&mm->page_table_lock);
-		dprintk ("Installing page %p %p: %d\n", (void *)page, map, i);
-		iobuf->pagelist[i] = page;
 		iobuf->maplist[i] = map;
 		iobuf->nr_pages = ++i;
 		
@@ -585,14 +579,13 @@
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
 	do {
-		pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address),
-		                               prot));
+		pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address), prot));
 		pte_t oldpage = *pte;
 		set_pte(pte, zero_pte);
 		forget_pte(oldpage);
 		address += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address,
@@ -611,7 +604,7 @@
 		zeromap_pte_range(pte, address, end - address, prot);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 	return 0;
 }
 
@@ -624,7 +617,9 @@
 
 	dir = pgd_offset(current->mm, address);
 	flush_cache_range(current->mm, beg, end);
-	while (address < end) {
+	if (address >= end)
+		BUG();
+	do {
 		pmd_t *pmd = pmd_alloc(dir, address);
 		error = -ENOMEM;
 		if (!pmd)
@@ -634,7 +629,7 @@
 			break;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
 	flush_tlb_range(current->mm, beg, end);
 	return error;
 }
@@ -665,7 +660,7 @@
 		address += PAGE_SIZE;
 		phys_addr += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -685,7 +680,7 @@
 		remap_pte_range(pte, address, end - address, address + phys_addr, prot);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 	return 0;
 }
 
@@ -699,7 +694,9 @@
 	phys_addr -= from;
 	dir = pgd_offset(current->mm, from);
 	flush_cache_range(current->mm, beg, end);
-	while (from < end) {
+	if (from >= end)
+		BUG();
+	do {
 		pmd_t *pmd = pmd_alloc(dir, from);
 		error = -ENOMEM;
 		if (!pmd)
@@ -709,7 +706,7 @@
 			break;
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (from && (from < end));
 	flush_tlb_range(current->mm, beg, end);
 	return error;
 }
@@ -718,37 +715,35 @@
  * This routine is used to map in a page into an address space: needed by
  * execve() for the initial stack and environment pages.
  */
-unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsigned long address)
+struct page * put_dirty_page(struct task_struct * tsk, struct page *page,
+						 unsigned long address)
 {
 	pgd_t * pgd;
 	pmd_t * pmd;
 	pte_t * pte;
 
-	if (MAP_NR(page) >= max_mapnr)
-		printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address);
-	if (page_count(mem_map + MAP_NR(page)) != 1)
-		printk("mem_map disagrees with %08lx at %08lx\n",page,address);
-	pgd = pgd_offset(tsk->mm,address);
+	if (page_count(page) != 1)
+		printk("mem_map disagrees with %p at %08lx\n", page, address);
+	pgd = pgd_offset(tsk->mm, address);
 	pmd = pmd_alloc(pgd, address);
 	if (!pmd) {
-		free_page(page);
+		__free_page(page);
 		oom(tsk);
 		return 0;
 	}
 	pte = pte_alloc(pmd, address);
 	if (!pte) {
-		free_page(page);
+		__free_page(page);
 		oom(tsk);
 		return 0;
 	}
 	if (!pte_none(*pte)) {
-		printk("put_dirty_page: pte %08lx already exists\n",
-		       pte_val(*pte));
-		free_page(page);
+		pte_ERROR(*pte);
+		__free_page(page);
 		return 0;
 	}
 	flush_page_to_ram(page);
-	set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY))));
+	set_pte(pte, pte_mkwrite(page_pte_prot(page, PAGE_COPY)));
 /* no need for flush_tlb */
 	return page;
 }
@@ -776,14 +771,14 @@
 static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
 	unsigned long address, pte_t *page_table, pte_t pte)
 {
-	unsigned long old_page, new_page;
-	struct page * page;
+	unsigned long map_nr;
+	struct page *old_page, *new_page;
 
-	old_page = pte_page(pte);
-	if (MAP_NR(old_page) >= max_mapnr)
+	map_nr = pte_pagenr(pte);
+	if (map_nr >= max_mapnr)
 		goto bad_wp_page;
 	tsk->min_flt++;
-	page = mem_map + MAP_NR(old_page);
+	old_page = mem_map + map_nr;
 	
 	/*
 	 * We can avoid the copy if:
@@ -793,13 +788,13 @@
 	 *   in which case we can remove the page
 	 *   from the swap cache.
 	 */
-	switch (page_count(page)) {
+	switch (page_count(old_page)) {
 	case 2:
-		if (!PageSwapCache(page))
+		if (!PageSwapCache(old_page))
 			break;
-		if (swap_count(page->offset) != 1)
+		if (swap_count(old_page) != 1)
 			break;
-		delete_from_swap_cache(page);
+		delete_from_swap_cache(old_page);
 		/* FallThrough */
 	case 1:
 		flush_cache_page(vma, address);
@@ -813,7 +808,7 @@
 	 * Ok, we need to copy. Oh, well..
 	 */
 	spin_unlock(&tsk->mm->page_table_lock);
-	new_page = __get_free_page(GFP_BIGUSER);
+	new_page = get_free_highpage(GFP_HIGHUSER);
 	if (!new_page)
 		return -1;
 	spin_lock(&tsk->mm->page_table_lock);
@@ -822,9 +817,9 @@
 	 * Re-check the pte - we dropped the lock
 	 */
 	if (pte_val(*page_table) == pte_val(pte)) {
-		if (PageReserved(page))
+		if (PageReserved(old_page))
 			++vma->vm_mm->rss;
-		copy_cow_page(old_page,new_page);
+		copy_cow_page(old_page, new_page);
 		flush_page_to_ram(new_page);
 		flush_cache_page(vma, address);
 		set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
@@ -834,12 +829,12 @@
 		new_page = old_page;
 	}
 	spin_unlock(&tsk->mm->page_table_lock);
-	free_page(new_page);
+	__free_page(new_page);
 	return 1;
 
 bad_wp_page:
 	spin_unlock(&tsk->mm->page_table_lock);
-	printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
+	printk("do_wp_page: bogus page at address %08lx (nr %ld)\n",address,map_nr);
 	return -1;
 }
 
@@ -848,6 +843,8 @@
  */
 static void partial_clear(struct vm_area_struct *vma, unsigned long address)
 {
+	unsigned int offset;
+	struct page *page;
 	pgd_t *page_dir;
 	pmd_t *page_middle;
 	pte_t *page_table, pte;
@@ -856,7 +853,7 @@
 	if (pgd_none(*page_dir))
 		return;
 	if (pgd_bad(*page_dir)) {
-		printk("bad page table directory entry %p:[%lx]\n", page_dir, pgd_val(*page_dir));
+		pgd_ERROR(*page_dir);
 		pgd_clear(page_dir);
 		return;
 	}
@@ -864,7 +861,7 @@
 	if (pmd_none(*page_middle))
 		return;
 	if (pmd_bad(*page_middle)) {
-		printk("bad page table directory entry %p:[%lx]\n", page_dir, pgd_val(*page_dir));
+		pmd_ERROR(*page_middle);
 		pmd_clear(page_middle);
 		return;
 	}
@@ -873,12 +870,11 @@
 	if (!pte_present(pte))
 		return;
 	flush_cache_page(vma, address);
-	address &= ~PAGE_MASK;
-	address += pte_page(pte);
-	if (MAP_NR(address) >= max_mapnr)
+	page = pte_page(pte);
+	if (page-mem_map >= max_mapnr)
 		return;
-	memset((void *) address, 0, PAGE_SIZE - (address & ~PAGE_MASK));
-	flush_page_to_ram(pte_page(pte));
+	offset = address & ~PAGE_MASK;
+	memclear_highpage_flush(page, offset, PAGE_SIZE - offset);
 }
 
 /*
@@ -939,7 +935,7 @@
  * because it doesn't cost us any seek time.  We also make sure to queue
  * the 'original' request together with the readahead ones...  
  */
-void swapin_readahead(unsigned long entry)
+void swapin_readahead(pte_t entry)
 {
 	int i;
 	struct page *new_page;
@@ -973,7 +969,7 @@
 
 static int do_swap_page(struct task_struct * tsk,
 	struct vm_area_struct * vma, unsigned long address,
-	pte_t * page_table, unsigned long entry, int write_access)
+	pte_t * page_table, pte_t entry, int write_access)
 {
 	struct page *page = lookup_swap_cache(entry);
 	pte_t pte;
@@ -986,7 +982,7 @@
 		if (!page)
 			return -1;
 
-		flush_page_to_ram(page_address(page));
+		flush_page_to_ram(page);
 	}
 
 	vma->vm_mm->rss++;
@@ -995,13 +991,13 @@
 	swap_free(entry);
 	unlock_kernel();
 
-	pte = mk_pte(page_address(page), vma->vm_page_prot);
+	pte = mk_pte(page, vma->vm_page_prot);
 
 	set_bit(PG_swap_entry, &page->flags);
 	if (write_access && !is_page_shared(page)) {
 		delete_from_swap_cache(page);
-		page = replace_with_bigmem(page);
-		pte = mk_pte(page_address(page), vma->vm_page_prot);
+		page = replace_with_highmem(page);
+		pte = mk_pte(page, vma->vm_page_prot);
 		pte = pte_mkwrite(pte_mkdirty(pte));
 	}
 	set_pte(page_table, pte);
@@ -1015,12 +1011,16 @@
  */
 static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
 {
+	int high = 0;
+	struct page *page = NULL;
 	pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
 	if (write_access) {
-		unsigned long page = __get_free_page(GFP_BIGUSER);
+		page = get_free_highpage(GFP_HIGHUSER);
 		if (!page)
 			return -1;
-		clear_bigpage(page);
+		if (PageHighMem(page))
+			high = 1;
+		clear_highpage(page);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 		vma->vm_mm->rss++;
 		tsk->min_flt++;
@@ -1047,7 +1047,7 @@
 static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
 	unsigned long address, int write_access, pte_t *page_table)
 {
-	unsigned long page;
+	struct page * new_page;
 	pte_t entry;
 
 	if (!vma->vm_ops || !vma->vm_ops->nopage)
@@ -1058,12 +1058,11 @@
 	 * to copy, not share the page even if sharing is possible.  It's
 	 * essentially an early COW detection.
 	 */
-	page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
-	if (!page)
+	new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
+	if (!new_page)
 		return 0;	/* SIGBUS - but we _really_ should know whether it is OOM or SIGBUS */
-	if (page == -1)
+	if (new_page == (struct page *)-1)
 		return -1;	/* OOM */
-
 	++tsk->maj_flt;
 	++vma->vm_mm->rss;
 	/*
@@ -1076,11 +1075,11 @@
 	 * so we can make it writable and dirty to avoid having to
 	 * handle that later.
 	 */
-	flush_page_to_ram(page);
-	entry = mk_pte(page, vma->vm_page_prot);
+	flush_page_to_ram(new_page);
+	entry = mk_pte(new_page, vma->vm_page_prot);
 	if (write_access) {
 		entry = pte_mkwrite(pte_mkdirty(entry));
-	} else if (page_count(mem_map+MAP_NR(page)) > 1 &&
+	} else if (page_count(new_page) > 1 &&
 		   !(vma->vm_flags & VM_SHARED))
 		entry = pte_wrprotect(entry);
 	set_pte(page_table, entry);
@@ -1117,7 +1116,7 @@
 	if (!pte_present(entry)) {
 		if (pte_none(entry))
 			return do_no_page(tsk, vma, address, write_access, pte);
-		return do_swap_page(tsk, vma, address, pte, pte_val(entry), write_access);
+		return do_swap_page(tsk, vma, address, pte, entry, write_access);
 	}
 
 	/*
@@ -1148,17 +1147,19 @@
 int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
 	unsigned long address, int write_access)
 {
+	int ret = -1;
 	pgd_t *pgd;
 	pmd_t *pmd;
 
 	pgd = pgd_offset(vma->vm_mm, address);
 	pmd = pmd_alloc(pgd, address);
+	
 	if (pmd) {
 		pte_t * pte = pte_alloc(pmd, address);
 		if (pte)
-			return handle_pte_fault(tsk, vma, address, write_access, pte);
+			ret = handle_pte_fault(tsk, vma, address, write_access, pte);
 	}
-	return -1;
+	return ret;
 }
 
 /*
@@ -1172,10 +1173,12 @@
 
 	vma = find_vma(tsk->mm, addr);
 	write = (vma->vm_flags & VM_WRITE) != 0;
-	while (addr < end) {
+	if (addr >= end)
+		BUG();
+	do {
 		if (handle_mm_fault(tsk, vma, addr, write) < 0)
 			return -1;
 		addr += PAGE_SIZE;
-	}
+	} while (addr < end);
 	return 0;
 }
diff -u --recursive --new-file v2.3.22/linux/mm/mlock.c linux/mm/mlock.c
--- v2.3.22/linux/mm/mlock.c	Thu Aug 26 13:05:42 1999
+++ linux/mm/mlock.c	Mon Oct 18 13:01:40 1999
@@ -13,7 +13,9 @@
 
 static inline int mlock_fixup_all(struct vm_area_struct * vma, int newflags)
 {
+	vmlist_modify_lock(vma->vm_mm);
 	vma->vm_flags = newflags;
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -26,15 +28,17 @@
 	if (!n)
 		return -EAGAIN;
 	*n = *vma;
-	vma->vm_start = end;
 	n->vm_end = end;
-	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_file)
 		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
+	vmlist_modify_lock(vma->vm_mm);
+	vma->vm_offset += end - vma->vm_start;
+	vma->vm_start = end;
 	insert_vm_struct(current->mm, n);
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -47,7 +51,6 @@
 	if (!n)
 		return -EAGAIN;
 	*n = *vma;
-	vma->vm_end = start;
 	n->vm_start = start;
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
@@ -55,7 +58,10 @@
 		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
+	vmlist_modify_lock(vma->vm_mm);
+	vma->vm_end = start;
 	insert_vm_struct(current->mm, n);
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -75,10 +81,7 @@
 	*left = *vma;
 	*right = *vma;
 	left->vm_end = start;
-	vma->vm_start = start;
-	vma->vm_end = end;
 	right->vm_start = end;
-	vma->vm_offset += vma->vm_start - left->vm_start;
 	right->vm_offset += right->vm_start - left->vm_start;
 	vma->vm_flags = newflags;
 	if (vma->vm_file)
@@ -88,8 +91,14 @@
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
 	}
+	vmlist_modify_lock(vma->vm_mm);
+	vma->vm_offset += start - vma->vm_start;
+	vma->vm_start = start;
+	vma->vm_end = end;
+	vma->vm_flags = newflags;
 	insert_vm_struct(current->mm, left);
 	insert_vm_struct(current->mm, right);
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -168,7 +177,9 @@
 			break;
 		}
 	}
+	vmlist_modify_lock(current->mm);
 	merge_segments(current->mm, start, end);
+	vmlist_modify_unlock(current->mm);
 	return error;
 }
 
@@ -240,7 +251,9 @@
 		if (error)
 			break;
 	}
+	vmlist_modify_lock(current->mm);
 	merge_segments(current->mm, 0, TASK_SIZE);
+	vmlist_modify_unlock(current->mm);
 	return error;
 }
 
diff -u --recursive --new-file v2.3.22/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.22/linux/mm/mmap.c	Fri Oct 15 15:25:14 1999
+++ linux/mm/mmap.c	Tue Oct 19 10:22:19 1999
@@ -62,7 +62,7 @@
 	if (sysctl_overcommit_memory)
 	    return 1;
 
-	free = atomic_read(&buffermem) >> PAGE_SHIFT;
+	free = atomic_read(&buffermem_pages);
 	free += atomic_read(&page_cache_size);
 	free += nr_free_pages;
 	free += nr_swap_pages;
@@ -323,8 +323,10 @@
 	 */
 	flags = vma->vm_flags;
 	addr = vma->vm_start; /* can addr have changed?? */
+	vmlist_modify_lock(mm);
 	insert_vm_struct(mm, vma);
 	merge_segments(mm, vma->vm_start, vma->vm_end);
+	vmlist_modify_unlock(mm);
 	
 	mm->total_vm += len >> PAGE_SHIFT;
 	if (flags & VM_LOCKED) {
@@ -527,11 +529,13 @@
 	}
 
 	/* Work out to one of the ends. */
-	if (end == area->vm_end)
+	if (end == area->vm_end) {
 		area->vm_end = addr;
-	else if (addr == area->vm_start) {
+		vmlist_modify_lock(current->mm);
+	} else if (addr == area->vm_start) {
 		area->vm_offset += (end - area->vm_start);
 		area->vm_start = end;
+		vmlist_modify_lock(current->mm);
 	} else {
 	/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
 		/* Add end mapping -- leave beginning for below */
@@ -552,10 +556,12 @@
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
+		vmlist_modify_lock(current->mm);
 		insert_vm_struct(current->mm, mpnt);
 	}
 
 	insert_vm_struct(current->mm, area);
+	vmlist_modify_unlock(current->mm);
 	return extra;
 }
 
@@ -655,6 +661,7 @@
 
 	npp = (prev ? &prev->vm_next : &mm->mmap);
 	free = NULL;
+	vmlist_modify_lock(mm);
 	for ( ; mpnt && mpnt->vm_start < addr+len; mpnt = *npp) {
 		*npp = mpnt->vm_next;
 		mpnt->vm_next = free;
@@ -662,6 +669,8 @@
 		if (mm->mmap_avl)
 			avl_remove(mpnt, &mm->mmap_avl);
 	}
+	mm->mmap_cache = NULL;	/* Kill the cache. */
+	vmlist_modify_unlock(mm);
 
 	/* Ok - we have the memory areas we should free on the 'free' list,
 	 * so release them, and unmap the page range..
@@ -678,6 +687,11 @@
 		end = end > mpnt->vm_end ? mpnt->vm_end : end;
 		size = end - st;
 
+		/*
+		 * The lock_kernel interlocks with kswapd try_to_swap_out
+		 * invoking a driver swapout() method, and being able to
+		 * guarantee vma existance.
+		 */
 		lock_kernel();
 		if (mpnt->vm_ops && mpnt->vm_ops->unmap)
 			mpnt->vm_ops->unmap(mpnt, st, size);
@@ -702,7 +716,6 @@
 
 	free_pgtables(mm, prev, addr, addr+len);
 
-	mm->mmap_cache = NULL;	/* Kill the cache. */
 	return 0;
 }
 
@@ -786,8 +799,10 @@
 	flags = vma->vm_flags;
 	addr = vma->vm_start;
 
+	vmlist_modify_lock(mm);
 	insert_vm_struct(mm, vma);
 	merge_segments(mm, vma->vm_start, vma->vm_end);
+	vmlist_modify_unlock(mm);
 	
 	mm->total_vm += len >> PAGE_SHIFT;
 	if (flags & VM_LOCKED) {
@@ -814,7 +829,9 @@
 
 	release_segments(mm);
 	mpnt = mm->mmap;
+	vmlist_modify_lock(mm);
 	mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
+	vmlist_modify_unlock(mm);
 	mm->rss = 0;
 	mm->total_vm = 0;
 	mm->locked_vm = 0;
@@ -910,6 +927,7 @@
 		prev = mpnt;
 		mpnt = mpnt->vm_next;
 	}
+	mm->mmap_cache = NULL;		/* Kill the cache. */
 
 	/* prev and mpnt cycle through the list, as long as
 	 * start_addr < mpnt->vm_end && prev->vm_start < end_addr
@@ -946,7 +964,9 @@
 		if (mpnt->vm_ops && mpnt->vm_ops->close) {
 			mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
 			mpnt->vm_start = mpnt->vm_end;
+			vmlist_modify_unlock(mm);
 			mpnt->vm_ops->close(mpnt);
+			vmlist_modify_lock(mm);
 		}
 		mm->map_count--;
 		remove_shared_vm_struct(mpnt);
@@ -955,7 +975,6 @@
 		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = prev;
 	}
-	mm->mmap_cache = NULL;		/* Kill the cache. */
 }
 
 void __init vma_init(void)
diff -u --recursive --new-file v2.3.22/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.3.22/linux/mm/mprotect.c	Thu Aug 26 13:05:42 1999
+++ linux/mm/mprotect.c	Tue Oct 19 10:22:19 1999
@@ -20,7 +20,7 @@
 	if (pmd_none(*pmd))
 		return;
 	if (pmd_bad(*pmd)) {
-		printk("change_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		return;
 	}
@@ -35,7 +35,7 @@
 			set_pte(pte, pte_modify(entry, newprot));
 		address += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static inline void change_pmd_range(pgd_t * pgd, unsigned long address,
@@ -47,7 +47,7 @@
 	if (pgd_none(*pgd))
 		return;
 	if (pgd_bad(*pgd)) {
-		printk("change_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
+		pgd_ERROR(*pgd);
 		pgd_clear(pgd);
 		return;
 	}
@@ -60,7 +60,7 @@
 		change_pte_range(pmd, address, end - address, newprot);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
@@ -70,11 +70,13 @@
 
 	dir = pgd_offset(current->mm, start);
 	flush_cache_range(current->mm, beg, end);
-	while (start < end) {
+	if (start >= end)
+		BUG();
+	do {
 		change_pmd_range(dir, start, end - start, newprot);
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (start && (start < end));
 	flush_tlb_range(current->mm, beg, end);
 	return;
 }
@@ -82,8 +84,10 @@
 static inline int mprotect_fixup_all(struct vm_area_struct * vma,
 	int newflags, pgprot_t prot)
 {
+	vmlist_modify_lock(vma->vm_mm);
 	vma->vm_flags = newflags;
 	vma->vm_page_prot = prot;
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -97,16 +101,18 @@
 	if (!n)
 		return -ENOMEM;
 	*n = *vma;
-	vma->vm_start = end;
 	n->vm_end = end;
-	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_file)
 		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
+	vmlist_modify_lock(vma->vm_mm);
+	vma->vm_offset += end - vma->vm_start;
+	vma->vm_start = end;
 	insert_vm_struct(current->mm, n);
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -120,7 +126,6 @@
 	if (!n)
 		return -ENOMEM;
 	*n = *vma;
-	vma->vm_end = start;
 	n->vm_start = start;
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
@@ -129,7 +134,10 @@
 		get_file(n->vm_file);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
+	vmlist_modify_lock(vma->vm_mm);
+	vma->vm_end = start;
 	insert_vm_struct(current->mm, n);
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -150,21 +158,23 @@
 	*left = *vma;
 	*right = *vma;
 	left->vm_end = start;
-	vma->vm_start = start;
-	vma->vm_end = end;
 	right->vm_start = end;
-	vma->vm_offset += vma->vm_start - left->vm_start;
 	right->vm_offset += right->vm_start - left->vm_start;
-	vma->vm_flags = newflags;
-	vma->vm_page_prot = prot;
 	if (vma->vm_file)
 		atomic_add(2,&vma->vm_file->f_count);
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
 	}
+	vmlist_modify_lock(vma->vm_mm);
+	vma->vm_offset += start - vma->vm_start;
+	vma->vm_start = start;
+	vma->vm_end = end;
+	vma->vm_flags = newflags;
+	vma->vm_page_prot = prot;
 	insert_vm_struct(current->mm, left);
 	insert_vm_struct(current->mm, right);
+	vmlist_modify_unlock(vma->vm_mm);
 	return 0;
 }
 
@@ -246,7 +256,9 @@
 			break;
 		}
 	}
+	vmlist_modify_lock(current->mm);
 	merge_segments(current->mm, start, end);
+	vmlist_modify_unlock(current->mm);
 out:
 	up(&current->mm->mmap_sem);
 	return error;
diff -u --recursive --new-file v2.3.22/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.22/linux/mm/mremap.c	Mon Jul 12 07:51:42 1999
+++ linux/mm/mremap.c	Tue Oct 19 10:22:19 1999
@@ -25,7 +25,7 @@
 	if (pgd_none(*pgd))
 		goto end;
 	if (pgd_bad(*pgd)) {
-		printk("move_one_page: bad source pgd (%08lx)\n", pgd_val(*pgd));
+		pgd_ERROR(*pgd);
 		pgd_clear(pgd);
 		goto end;
 	}
@@ -34,7 +34,7 @@
 	if (pmd_none(*pmd))
 		goto end;
 	if (pmd_bad(*pmd)) {
-		printk("move_one_page: bad source pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		goto end;
 	}
@@ -141,8 +141,10 @@
 				get_file(new_vma->vm_file);
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
+			vmlist_modify_lock(current->mm);
 			insert_vm_struct(current->mm, new_vma);
 			merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
+			vmlist_modify_unlock(vma->vm_mm);
 			do_munmap(addr, old_len);
 			current->mm->total_vm += new_len >> PAGE_SHIFT;
 			if (new_vma->vm_flags & VM_LOCKED) {
@@ -220,7 +222,9 @@
 		/* can we just expand the current mapping? */
 		if (max_addr - addr >= new_len) {
 			int pages = (new_len - old_len) >> PAGE_SHIFT;
+			vmlist_modify_lock(vma->vm_mm);
 			vma->vm_end = addr + new_len;
+			vmlist_modify_unlock(vma->vm_mm);
 			current->mm->total_vm += pages;
 			if (vma->vm_flags & VM_LOCKED) {
 				current->mm->locked_vm += pages;
diff -u --recursive --new-file v2.3.22/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.22/linux/mm/page_alloc.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/page_alloc.c	Wed Oct 20 16:46:42 1999
@@ -14,7 +14,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
-#include <linux/bigmem.h> /* export bigmem vars */
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
 
 #include <asm/dma.h>
 #include <asm/uaccess.h> /* for copy_to/from_user */
@@ -40,45 +41,25 @@
 #define NR_MEM_LISTS 10
 #endif
 
-/* The start of this MUST match the start of "struct page" */
 struct free_area_struct {
-	struct page *next;
-	struct page *prev;
+	struct list_head free_list;
 	unsigned int * map;
+	unsigned long count;
 };
 
-#define memory_head(x) ((struct page *)(x))
+#define MEM_TYPE_DMA		0
+#define MEM_TYPE_NORMAL		1
+#define MEM_TYPE_HIGH		2
 
-#ifdef CONFIG_BIGMEM
-#define BIGMEM_LISTS_OFFSET	NR_MEM_LISTS
-static struct free_area_struct free_area[NR_MEM_LISTS*2];
+static const char *mem_type_strs[] = {"DMA", "Normal", "High"};
+
+#ifdef CONFIG_HIGHMEM
+#define NR_MEM_TYPES		3
 #else
-static struct free_area_struct free_area[NR_MEM_LISTS];
+#define NR_MEM_TYPES		2
 #endif
 
-static inline void init_mem_queue(struct free_area_struct * head)
-{
-	head->next = memory_head(head);
-	head->prev = memory_head(head);
-}
-
-static inline void add_mem_queue(struct free_area_struct * head, struct page * entry)
-{
-	struct page * next = head->next;
-
-	entry->prev = memory_head(head);
-	entry->next = next;
-	next->prev = entry;
-	head->next = entry;
-}
-
-static inline void remove_mem_queue(struct page * entry)
-{
-	struct page * next = entry->next;
-	struct page * prev = entry->prev;
-	next->prev = prev;
-	prev->next = next;
-}
+static struct free_area_struct free_area[NR_MEM_TYPES][NR_MEM_LISTS];
 
 /*
  * Free_page() adds the page to the free lists. This is optimized for
@@ -99,41 +80,76 @@
  */
 spinlock_t page_alloc_lock = SPIN_LOCK_UNLOCKED;
 
-static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
+#define memlist_init(x) INIT_LIST_HEAD(x)
+#define memlist_add_head list_add
+#define memlist_add_tail list_add_tail
+#define memlist_del list_del
+#define memlist_entry list_entry
+#define memlist_next(x) ((x)->next)
+#define memlist_prev(x) ((x)->prev)
+
+static inline void free_pages_ok(struct page *page, unsigned long map_nr, unsigned long order)
 {
-	struct free_area_struct *area = free_area + order;
+	struct free_area_struct *area;
 	unsigned long index = map_nr >> (1 + order);
 	unsigned long mask = (~0UL) << order;
 	unsigned long flags;
+	struct page *buddy;
 
 	spin_lock_irqsave(&page_alloc_lock, flags);
 
 #define list(x) (mem_map+(x))
 
-#ifdef CONFIG_BIGMEM
-	if (map_nr >= bigmem_mapnr) {
-		area += BIGMEM_LISTS_OFFSET;
-		nr_free_bigpages -= mask;
-	}
+#ifdef CONFIG_HIGHMEM
+	if (map_nr >= highmem_mapnr) {
+		area = free_area[MEM_TYPE_HIGH];
+		nr_free_highpages -= mask;
+	} else
 #endif
+	if (PageDMA(page))
+		area = free_area[MEM_TYPE_DMA];
+	else
+		area = free_area[MEM_TYPE_NORMAL];
+
+	area += order;
+
 	map_nr &= mask;
 	nr_free_pages -= mask;
+
 	while (mask + (1 << (NR_MEM_LISTS-1))) {
 		if (!test_and_change_bit(index, area->map))
+			/*
+			 * the buddy page is still allocated.
+			 */
 			break;
-		remove_mem_queue(list(map_nr ^ -mask));
+		/*
+		 * Move the buddy up one level.
+		 */
+		buddy = list(map_nr ^ -mask);
+		page = list(map_nr);
+
+		area->count--;
+		memlist_del(&buddy->list);
 		mask <<= 1;
 		area++;
 		index >>= 1;
 		map_nr &= mask;
 	}
-	add_mem_queue(area, list(map_nr));
-
+	area->count++;
+	memlist_add_head(&(list(map_nr))->list, &area->free_list);
 #undef list
 
 	spin_unlock_irqrestore(&page_alloc_lock, flags);
 }
 
+/*
+ * Some ugly macros to speed up __get_free_pages()..
+ */
+#define MARK_USED(index, order, area) \
+	change_bit((index) >> (1+(order)), (area)->map)
+#define CAN_DMA(x) (PageDMA(x))
+#define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
+
 int __free_page(struct page *page)
 {
 	if (!PageReserved(page) && put_page_testzero(page)) {
@@ -142,7 +158,7 @@
 		if (PageLocked(page))
 			PAGE_BUG(page);
 
-		free_pages_ok(page - mem_map, 0);
+		free_pages_ok(page, page-mem_map, 0);
 		return 1;
 	}
 	return 0;
@@ -159,154 +175,155 @@
 				PAGE_BUG(map);
 			if (PageLocked(map))
 				PAGE_BUG(map);
-			free_pages_ok(map_nr, order);
+			free_pages_ok(map, map_nr, order);
 			return 1;
 		}
 	}
 	return 0;
 }
 
-/*
- * Some ugly macros to speed up __get_free_pages()..
- */
-#define MARK_USED(index, order, area) \
-	change_bit((index) >> (1+(order)), (area)->map)
-#define CAN_DMA(x) (PageDMA(x))
-#define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
+static inline unsigned long EXPAND (struct page *map, unsigned long index,
+		 int low, int high, struct free_area_struct * area)
+{
+	unsigned long size = 1 << high;
 
-#ifdef CONFIG_BIGMEM
-#define RMQUEUEBIG(order, gfp_mask) \
-if (gfp_mask & __GFP_BIGMEM) { \
-	struct free_area_struct * area = free_area+order+BIGMEM_LISTS_OFFSET; \
-	unsigned long new_order = order; \
-	do { struct page *prev = memory_head(area), *ret = prev->next; \
-		if (memory_head(area) != ret) { \
-			unsigned long map_nr; \
-			(prev->next = ret->next)->prev = prev; \
-			map_nr = ret - mem_map; \
-			MARK_USED(map_nr, new_order, area); \
-			nr_free_pages -= 1 << order; \
-			nr_free_bigpages -= 1 << order; \
-			EXPAND(ret, map_nr, order, new_order, area); \
-			spin_unlock_irqrestore(&page_alloc_lock, flags); \
-			return ADDRESS(map_nr); \
-		} \
-		new_order++; area++; \
-	} while (new_order < NR_MEM_LISTS); \
+	while (high > low) {
+		area--;
+		high--;
+		size >>= 1;
+		area->count++;
+		memlist_add_head(&(map)->list, &(area)->free_list);
+		MARK_USED(index, high, area);
+		index += size;
+		map += size;
+	}
+	set_page_count(map, 1);
+	return index;
 }
-#endif
-
-#define RMQUEUE(order, gfp_mask) \
-do { struct free_area_struct * area = free_area+order; \
-     unsigned long new_order = order; \
-	do { struct page *prev = memory_head(area), *ret = prev->next; \
-		while (memory_head(area) != ret) { \
-			if (!(gfp_mask & __GFP_DMA) || CAN_DMA(ret)) { \
-				unsigned long map_nr; \
-				(prev->next = ret->next)->prev = prev; \
-				map_nr = ret - mem_map; \
-				MARK_USED(map_nr, new_order, area); \
-				nr_free_pages -= 1 << order; \
-				EXPAND(ret, map_nr, order, new_order, area); \
-				spin_unlock_irqrestore(&page_alloc_lock,flags);\
-				return ADDRESS(map_nr); \
-			} \
-			prev = ret; \
-			ret = ret->next; \
-		} \
-		new_order++; area++; \
-	} while (new_order < NR_MEM_LISTS); \
-} while (0)
-
-#define EXPAND(map,index,low,high,area) \
-do { unsigned long size = 1 << high; \
-	while (high > low) { \
-		area--; high--; size >>= 1; \
-		add_mem_queue(area, map); \
-		MARK_USED(index, high, area); \
-		index += size; \
-		map += size; \
-	} \
-	set_page_count(map, 1); \
-} while (0)
 
-unsigned long __get_free_pages(int gfp_mask, unsigned long order)
+static inline struct page * rmqueue (int order, unsigned type)
 {
-	unsigned long flags;
+	struct free_area_struct * area = free_area[type]+order;
+	unsigned long curr_order = order, map_nr;
+	struct page *page;
+	struct list_head *head, *curr;
 
-	if (order >= NR_MEM_LISTS)
-		goto nopage;
+	do {
+		head = &area->free_list;
+		curr = memlist_next(head);
 
-#ifdef ATOMIC_MEMORY_DEBUGGING
-	if ((gfp_mask & __GFP_WAIT) && in_interrupt()) {
-		static int count = 0;
-		if (++count < 5) {
-			printk("gfp called nonatomically from interrupt %p\n",
-				__builtin_return_address(0));
+		if (curr != head) {
+			page = memlist_entry(curr, struct page, list);
+			memlist_del(curr);
+			area->count--;
+			map_nr = page - mem_map;	
+			MARK_USED(map_nr, curr_order, area);
+			nr_free_pages -= 1 << order;
+			map_nr = EXPAND(page, map_nr, order, curr_order, area);
+			page = mem_map + map_nr;
+			return page;	
+		}
+		curr_order++;
+		area++;
+	} while (curr_order < NR_MEM_LISTS);
+
+	return NULL;
+}
+
+static inline int balance_lowmemory (int gfp_mask)
+{
+	int freed;
+	static int low_on_memory = 0;
+
+#ifndef CONFIG_HIGHMEM
+	if (nr_free_pages > freepages.min) {
+		if (!low_on_memory)
+			return 1;
+		if (nr_free_pages >= freepages.high) {
+			low_on_memory = 0;
+			return 1;
 		}
-		goto nopage;
 	}
-#endif
 
-	/*
-	 * If this is a recursive call, we'd better
-	 * do our best to just allocate things without
-	 * further thought.
-	 */
-	if (!(current->flags & PF_MEMALLOC)) {
-		int freed;
-		static int low_on_memory = 0;
+	low_on_memory = 1;
+#else
+	static int low_on_highmemory = 0;
 
-#ifndef CONFIG_BIGMEM
+	if (gfp_mask & __GFP_HIGHMEM)
+	{
 		if (nr_free_pages > freepages.min) {
-			if (!low_on_memory)
-				goto ok_to_allocate;
+			if (!low_on_highmemory) {
+				return 1;
+			}
 			if (nr_free_pages >= freepages.high) {
-				low_on_memory = 0;
-				goto ok_to_allocate;
+				low_on_highmemory = 0;
+				return 1;
 			}
 		}
-
-		low_on_memory = 1;
-#else
-		static int low_on_bigmemory = 0;
-
-		if (gfp_mask & __GFP_BIGMEM)
-		{
-			if (nr_free_pages > freepages.min) {
-				if (!low_on_bigmemory)
-					goto ok_to_allocate;
-				if (nr_free_pages >= freepages.high) {
-					low_on_bigmemory = 0;
-					goto ok_to_allocate;
-				}
+		low_on_highmemory = 1;
+	} else {
+		if (nr_free_pages+nr_free_highpages > freepages.min) {
+			if (!low_on_memory) {
+				return 1;
 			}
-			low_on_bigmemory = 1;
-		} else {
-			if (nr_free_pages-nr_free_bigpages > freepages.min) {
-				if (!low_on_memory)
-					goto ok_to_allocate;
-				if (nr_free_pages-nr_free_bigpages >= freepages.high) {
-					low_on_memory = 0;
-					goto ok_to_allocate;
-				}
+			if (nr_free_pages+nr_free_highpages >= freepages.high) {
+				low_on_memory = 0;
+				return 1;
 			}
-			low_on_memory = 1;
 		}
+		low_on_memory = 1;
+	}
 #endif
-		current->flags |= PF_MEMALLOC;
-		freed = try_to_free_pages(gfp_mask);
-		current->flags &= ~PF_MEMALLOC;
+	current->flags |= PF_MEMALLOC;
+	freed = try_to_free_pages(gfp_mask);
+	current->flags &= ~PF_MEMALLOC;
+
+	if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
+		return 0;
+	return 1;
+}
+
+struct page * __get_pages(int gfp_mask, unsigned long order)
+{
+	unsigned long flags;
+	struct page *page;
+	unsigned type;
+
+	if (order >= NR_MEM_LISTS)
+		goto nopage;
+
+	/*
+	 * If anyone calls gfp from interrupts nonatomically then it
+	 * will sooner or later tripped up by a schedule().
+	 */
+
+	/*
+	 * If this is a recursive call, we'd better
+	 * do our best to just allocate things without
+	 * further thought.
+	 */
+	if (!(current->flags & PF_MEMALLOC))
+		goto lowmemory;
 
-		if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
-			goto nopage;
-	}
 ok_to_allocate:
-	spin_lock_irqsave(&page_alloc_lock, flags);
-#ifdef CONFIG_BIGMEM
-	RMQUEUEBIG(order, gfp_mask);
+#ifdef CONFIG_HIGHMEM
+	if (gfp_mask & __GFP_HIGHMEM)
+		type = MEM_TYPE_HIGH;
+	else
 #endif
-	RMQUEUE(order, gfp_mask);
+	if (gfp_mask & __GFP_DMA)
+		type = MEM_TYPE_DMA;
+	else
+		type = MEM_TYPE_NORMAL;
+
+	spin_lock_irqsave(&page_alloc_lock, flags);
+	do {
+		page = rmqueue(order, type);
+		if (page) {
+			spin_unlock_irqrestore(&page_alloc_lock, flags);
+			return page;
+		}
+	} while (type-- > 0) ;
 	spin_unlock_irqrestore(&page_alloc_lock, flags);
 
 	/*
@@ -320,7 +337,26 @@
 	}
 
 nopage:
-	return 0;
+	return NULL;
+
+lowmemory:
+	if (balance_lowmemory(gfp_mask))
+		goto ok_to_allocate;
+	goto nopage;
+}
+
+unsigned long __get_free_pages(int gfp_mask, unsigned long order)
+{
+	struct page *page;
+	page = __get_pages(gfp_mask, order);
+	if (!page)
+		return 0;
+	return page_address(page);
+}
+
+struct page * get_free_highpage(int gfp_mask)
+{
+	return __get_pages(gfp_mask, 0);
 }
 
 /*
@@ -331,36 +367,32 @@
 void show_free_areas(void)
 {
  	unsigned long order, flags;
- 	unsigned long total = 0;
+	unsigned type;
 
-	printk("Free pages:      %6dkB (%6dkB BigMem)\n ( ",
+	spin_lock_irqsave(&page_alloc_lock, flags);
+	printk("Free pages:      %6dkB (%6ldkB HighMem)\n",
 		nr_free_pages<<(PAGE_SHIFT-10),
-		nr_free_bigpages<<(PAGE_SHIFT-10));
-	printk("Free: %d, lru_cache: %d (%d %d %d)\n",
+		nr_free_highpages<<(PAGE_SHIFT-10));
+	printk("( Free: %d, lru_cache: %d (%d %d %d) )\n",
 		nr_free_pages,
 		nr_lru_pages,
 		freepages.min,
 		freepages.low,
 		freepages.high);
-	spin_lock_irqsave(&page_alloc_lock, flags);
- 	for (order=0 ; order < NR_MEM_LISTS; order++) {
-		struct page * tmp;
-		unsigned long nr = 0;
-		for (tmp = free_area[order].next ; tmp != memory_head(free_area+order) ; tmp = tmp->next) {
-			nr ++;
-		}
-#ifdef CONFIG_BIGMEM
-		for (tmp = free_area[BIGMEM_LISTS_OFFSET+order].next;
-		     tmp != memory_head(free_area+BIGMEM_LISTS_OFFSET+order);
-		     tmp = tmp->next) {
-			nr ++;
+
+	for (type = 0; type < NR_MEM_TYPES; type++) {
+ 		unsigned long total = 0;
+		printk("  %s: ", mem_type_strs[type]);
+	 	for (order = 0; order < NR_MEM_LISTS; order++) {
+			unsigned long nr = free_area[type][order].count;
+
+			total += nr * ((PAGE_SIZE>>10) << order);
+			printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
 		}
-#endif
-		total += nr * ((PAGE_SIZE>>10) << order);
-		printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
+		printk("= %lukB)\n", total);
 	}
 	spin_unlock_irqrestore(&page_alloc_lock, flags);
-	printk("= %lukB)\n", total);
+
 #ifdef SWAP_CACHE_INFO
 	show_swap_cache_info();
 #endif	
@@ -374,11 +406,12 @@
  *   - mark all memory queues empty
  *   - clear the memory bitmaps
  */
-unsigned long __init free_area_init(unsigned long start_mem, unsigned long end_mem)
+volatile int data;
+void __init free_area_init(unsigned long end_mem_pages)
 {
 	mem_map_t * p;
-	unsigned long mask = PAGE_MASK;
-	unsigned long i;
+	unsigned long i, j;
+	unsigned long map_size;
 
 	/*
 	 * Select nr of pages we try to keep free for important stuff
@@ -387,7 +420,7 @@
 	 * This is fairly arbitrary, but based on some behaviour
 	 * analysis.
 	 */
-	i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7);
+	i = end_mem_pages >> 7;
 	if (i < 10)
 		i = 10;
 	if (i > 256)
@@ -395,36 +428,43 @@
 	freepages.min = i;
 	freepages.low = i * 2;
 	freepages.high = i * 3;
-	mem_map = (mem_map_t *) LONG_ALIGN(start_mem);
-	p = mem_map + MAP_NR(end_mem);
-	start_mem = LONG_ALIGN((unsigned long) p);
-	memset(mem_map, 0, start_mem - (unsigned long) mem_map);
-	do {
-		--p;
+
+	/*
+	 * Most architectures just pick 'start_mem'. Some architectures
+	 * (with lots of mem and discontinous memory maps) have to search
+	 * for a good area.
+	 */
+	map_size = end_mem_pages*sizeof(struct page);
+	mem_map = (struct page *) alloc_bootmem(map_size);
+	memset(mem_map, 0, map_size);
+
+	/*
+	 * Initially all pages are reserved - free ones are freed
+	 * up by free_all_bootmem() once the early boot process is
+	 * done.
+	 */
+	for (p = mem_map; p < mem_map + end_mem_pages; p++) {
 		set_page_count(p, 0);
-		p->flags = (1 << PG_DMA) | (1 << PG_reserved);
+		p->flags = (1 << PG_DMA);
+		SetPageReserved(p);
 		init_waitqueue_head(&p->wait);
-	} while (p > mem_map);
-
-	for (i = 0 ; i < NR_MEM_LISTS ; i++) {
-		unsigned long bitmap_size;
-		init_mem_queue(free_area+i);
-#ifdef CONFIG_BIGMEM
-		init_mem_queue(free_area+BIGMEM_LISTS_OFFSET+i);
-#endif
-		mask += mask;
-		end_mem = (end_mem + ~mask) & mask;
-		bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i);
-		bitmap_size = (bitmap_size + 7) >> 3;
-		bitmap_size = LONG_ALIGN(bitmap_size);
-		free_area[i].map = (unsigned int *) start_mem;
-		memset((void *) start_mem, 0, bitmap_size);
-		start_mem += bitmap_size;
-#ifdef CONFIG_BIGMEM
-		free_area[BIGMEM_LISTS_OFFSET+i].map = (unsigned int *) start_mem;
-		memset((void *) start_mem, 0, bitmap_size);
-		start_mem += bitmap_size;
-#endif
+		memlist_init(&p->list);
+	}
+	
+	for (j = 0 ; j < NR_MEM_TYPES ; j++) {
+		unsigned long mask = -1;
+		for (i = 0 ; i < NR_MEM_LISTS ; i++) {
+			unsigned long bitmap_size;
+			unsigned int * map;
+			memlist_init(&free_area[j][i].free_list);
+			mask += mask;
+			end_mem_pages = (end_mem_pages + ~mask) & mask;
+			bitmap_size = end_mem_pages >> i;
+			bitmap_size = (bitmap_size + 7) >> 3;
+			bitmap_size = LONG_ALIGN(bitmap_size);
+			map = (unsigned int *) alloc_bootmem(bitmap_size);
+			free_area[j][i].map = map;
+			memset((void *) map, 0, bitmap_size);
+		}
 	}
-	return start_mem;
 }
diff -u --recursive --new-file v2.3.22/linux/mm/page_io.c linux/mm/page_io.c
--- v2.3.22/linux/mm/page_io.c	Fri Oct 15 15:25:14 1999
+++ linux/mm/page_io.c	Tue Oct 19 10:22:19 1999
@@ -33,7 +33,7 @@
  * that shared pages stay shared while being swapped.
  */
 
-static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, int wait)
+static int rw_swap_page_base(int rw, pte_t entry, struct page *page, int wait)
 {
 	unsigned long type, offset;
 	struct swap_info_struct * p;
@@ -42,17 +42,10 @@
 	kdev_t dev = 0;
 	int block_size;
 
-#ifdef DEBUG_SWAP
-	printk ("DebugVM: %s_swap_page entry %08lx, page %p (count %d), %s\n",
-		(rw == READ) ? "read" : "write", 
-		entry, (char *) page_address(page), page_count(page),
-		wait ? "wait" : "nowait");
-#endif
-
 	type = SWP_TYPE(entry);
 	if (type >= nr_swapfiles) {
 		printk("Internal error: bad swap-device\n");
-		return;
+		return 0;
 	}
 
 	/* Don't allow too many pending pages in flight.. */
@@ -63,23 +56,16 @@
 	offset = SWP_OFFSET(entry);
 	if (offset >= p->max) {
 		printk("rw_swap_page: weirdness\n");
-		return;
+		return 0;
 	}
 	if (p->swap_map && !p->swap_map[offset]) {
-		printk(KERN_ERR "rw_swap_page: "
-			"Trying to %s unallocated swap (%08lx)\n", 
-			(rw == READ) ? "read" : "write", entry);
-		return;
+		pte_ERROR(entry);
+		return 0;
 	}
 	if (!(p->flags & SWP_USED)) {
 		printk(KERN_ERR "rw_swap_page: "
 			"Trying to swap to unused swap-device\n");
-		return;
-	}
-
-	if (!PageLocked(page)) {
-		printk(KERN_ERR "VM: swap page is unlocked\n");
-		return;
+		return 0;
 	}
 
 	if (rw == READ) {
@@ -104,13 +90,13 @@
 		for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size)
 			if (!(zones[i] = bmap(swapf,block++))) {
 				printk("rw_swap_page: bad swap file\n");
-				return;
+				return 0;
 			}
 		zones_used = i;
 		dev = swapf->i_dev;
 	} else {
 		printk(KERN_ERR "rw_swap_page: no swap file or device\n");
-		return;
+		return 0;
 	}
  	if (!wait) {
  		set_bit(PG_decr_after, &page->flags);
@@ -124,20 +110,15 @@
  	 * decrementing the page count, and unlocking the page in the
  	 * swap lock map - in the IO completion handler.
  	 */
- 	if (!wait) {
- 		return;
-	}
+ 	if (!wait)
+ 		return 1;
+
  	wait_on_page(page);
 	/* This shouldn't happen, but check to be sure. */
 	if (page_count(page) == 0)
 		printk(KERN_ERR "rw_swap_page: page unused while waiting!\n");
 
-#ifdef DEBUG_SWAP
-	printk ("DebugVM: %s_swap_page finished on page %p (count %d)\n",
-		(rw == READ) ? "read" : "write", 
-		(char *) page_address(page), 
-		page_count(page));
-#endif
+	return 1;
 }
 
 /*
@@ -149,7 +130,7 @@
  */
 void rw_swap_page(int rw, struct page *page, int wait)
 {
-	unsigned long entry = page->offset;
+	pte_t entry = get_pagecache_pte(page);
 
 	if (!PageLocked(page))
 		PAGE_BUG(page);
@@ -157,7 +138,8 @@
 		PAGE_BUG(page);
 	if (page->inode != &swapper_inode)
 		PAGE_BUG(page);
-	rw_swap_page_base(rw, entry, page, wait);
+	if (!rw_swap_page_base(rw, entry, page, wait))
+		UnlockPage(page);
 }
 
 /*
@@ -165,7 +147,7 @@
  * Therefore we can't use it.  Later when we can remove the need for the
  * lock map and we can reduce the number of functions exported.
  */
-void rw_swap_page_nolock(int rw, unsigned long entry, char *buf, int wait)
+void rw_swap_page_nolock(int rw, pte_t entry, char *buf, int wait)
 {
 	struct page *page = mem_map + MAP_NR(buf);
 	
@@ -173,5 +155,6 @@
 		PAGE_BUG(page);
 	if (PageSwapCache(page))
 		PAGE_BUG(page);
-	rw_swap_page_base(rw, entry, page, wait);
+	if (!rw_swap_page_base(rw, entry, page, wait))
+		UnlockPage(page);
 }
diff -u --recursive --new-file v2.3.22/linux/mm/slab.c linux/mm/slab.c
--- v2.3.22/linux/mm/slab.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/slab.c	Tue Oct 19 10:22:19 1999
@@ -317,10 +317,10 @@
  * slab an obj belongs to.  With kmalloc(), and kfree(), these are used
  * to find the cache which an obj belongs to.
  */
-#define	SLAB_SET_PAGE_CACHE(pg, x)	((pg)->next = (struct page *)(x))
-#define	SLAB_GET_PAGE_CACHE(pg)		((kmem_cache_t *)(pg)->next)
-#define	SLAB_SET_PAGE_SLAB(pg, x)	((pg)->prev = (struct page *)(x))
-#define	SLAB_GET_PAGE_SLAB(pg)		((kmem_slab_t *)(pg)->prev)
+#define	SLAB_SET_PAGE_CACHE(pg,x)  ((pg)->list.next = (struct list_head *)(x))
+#define	SLAB_GET_PAGE_CACHE(pg)    ((kmem_cache_t *)(pg)->list.next)
+#define	SLAB_SET_PAGE_SLAB(pg,x)   ((pg)->list.prev = (struct list_head *)(x))
+#define	SLAB_GET_PAGE_SLAB(pg)     ((kmem_slab_t *)(pg)->list.prev)
 
 /* Size description struct for general caches. */
 typedef struct cache_sizes {
@@ -402,7 +402,7 @@
 static unsigned long bufctl_limit = 0;
 
 /* Initialisation - setup the `cache' cache. */
-long __init kmem_cache_init(long start, long end)
+void __init kmem_cache_init(void)
 {
 	size_t size, i;
 
@@ -450,7 +450,6 @@
 	 */
 	if (num_physpages > (32 << 20) >> PAGE_SHIFT)
 		slab_break_gfp_order = SLAB_BREAK_GFP_ORDER_HI;
-	return start;
 }
 
 /* Initialisation - setup remaining internal and general caches.
diff -u --recursive --new-file v2.3.22/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.3.22/linux/mm/swap_state.c	Fri Oct 15 15:25:14 1999
+++ linux/mm/swap_state.c	Thu Oct 21 12:32:23 1999
@@ -50,7 +50,10 @@
 	NULL				/* revalidate */
 };
 
-struct inode swapper_inode = { i_op: &swapper_inode_operations };
+struct inode swapper_inode = {
+	i_op: &swapper_inode_operations,
+	i_pages: {&swapper_inode.i_pages,&swapper_inode.i_pages}
+};
 
 #ifdef SWAP_CACHE_INFO
 unsigned long swap_cache_add_total = 0;
@@ -67,25 +70,16 @@
 }
 #endif
 
-void add_to_swap_cache(struct page *page, unsigned long entry)
+void add_to_swap_cache(struct page *page, pte_t entry)
 {
 #ifdef SWAP_CACHE_INFO
 	swap_cache_add_total++;
 #endif
-#ifdef DEBUG_SWAP
-	printk("DebugVM: add_to_swap_cache(%08lx count %d, entry %08lx)\n",
-		   page_address(page), page_count(page), entry);
-#endif
-	if (PageTestandSetSwapCache(page)) {
-		printk(KERN_ERR "swap_cache: replacing non-empty entry %08lx "
-			   "on page %08lx\n",
-			   page->offset, page_address(page));
-	}
-	if (page->inode) {
-		printk(KERN_ERR "swap_cache: replacing page-cached entry "
-			   "on page %08lx\n", page_address(page));
-	}
-	add_to_page_cache(page, &swapper_inode, entry);
+	if (PageTestandSetSwapCache(page))
+		BUG();
+	if (page->inode)
+		BUG();
+	add_to_page_cache(page, &swapper_inode, pte_val(entry));
 }
 
 /*
@@ -94,13 +88,13 @@
  * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
  * "permanent", but will be reclaimed by the next swapoff.
  */
-int swap_duplicate(unsigned long entry)
+int swap_duplicate(pte_t entry)
 {
 	struct swap_info_struct * p;
 	unsigned long offset, type;
 	int result = 0;
 
-	if (!entry)
+	if (!pte_val(entry))
 		goto out;
 	type = SWP_TYPE(entry);
 	if (type & SHM_SWP_TYPE)
@@ -121,41 +115,32 @@
 	else {
 		static int overflow = 0;
 		if (overflow++ < 5)
-			printk(KERN_WARNING
-				"swap_duplicate: entry %08lx map count=%d\n",
-				entry, p->swap_map[offset]);
+			pte_ERROR(entry);
 		p->swap_map[offset] = SWAP_MAP_MAX;
 	}
 	result = 1;
-#ifdef DEBUG_SWAP
-	printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n",
-		   entry, p->swap_map[offset]);
-#endif
 out:
 	return result;
 
 bad_file:
-	printk(KERN_ERR
-		"swap_duplicate: entry %08lx, nonexistent swap file\n", entry);
+	pte_ERROR(entry);
 	goto out;
 bad_offset:
-	printk(KERN_ERR
-		"swap_duplicate: entry %08lx, offset exceeds max\n", entry);
+	pte_ERROR(entry);
 	goto out;
 bad_unused:
-	printk(KERN_ERR
-		"swap_duplicate at %8p: entry %08lx, unused page\n", 
-		   __builtin_return_address(0), entry);
+	pte_ERROR(entry);
 	goto out;
 }
 
-int swap_count(unsigned long entry)
+int swap_count(struct page *page)
 {
 	struct swap_info_struct * p;
 	unsigned long offset, type;
+	pte_t entry = get_pagecache_pte(page);
 	int retval = 0;
 
-	if (!entry)
+	if (!pte_val(entry))
 		goto bad_entry;
 	type = SWP_TYPE(entry);
 	if (type & SHM_SWP_TYPE)
@@ -169,10 +154,6 @@
 	if (!p->swap_map[offset])
 		goto bad_unused;
 	retval = p->swap_map[offset];
-#ifdef DEBUG_SWAP
-	printk("DebugVM: swap_count(entry %08lx, count %d)\n",
-		   entry, retval);
-#endif
 out:
 	return retval;
 
@@ -180,17 +161,13 @@
 	printk(KERN_ERR "swap_count: null entry!\n");
 	goto out;
 bad_file:
-	printk(KERN_ERR
-		   "swap_count: entry %08lx, nonexistent swap file!\n", entry);
+	pte_ERROR(entry);
 	goto out;
 bad_offset:
-	printk(KERN_ERR
-		   "swap_count: entry %08lx, offset exceeds max!\n", entry);
+	pte_ERROR(entry);
 	goto out;
 bad_unused:
-	printk(KERN_ERR
-		   "swap_count at %8p: entry %08lx, unused page!\n", 
-		   __builtin_return_address(0), entry);
+	pte_ERROR(entry);
 	goto out;
 }
 
@@ -198,22 +175,13 @@
 {
 	struct inode *inode = page->inode;
 
-	if (!inode) {
-		printk ("VM: Removing swap cache page with zero inode hash "
-			"on page %08lx\n", page_address(page));
-		return;
-	}
-	if (inode != &swapper_inode) {
-		printk ("VM: Removing swap cache page with wrong inode hash "
-			"on page %08lx\n", page_address(page));
-	}
+	if (!inode)
+		BUG();
+	if (inode != &swapper_inode)
+		BUG();
 	if (!PageSwapCache(page))
 		PAGE_BUG(page);
 
-#ifdef DEBUG_SWAP
-	printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n",
-		   page_address(page), page_count(page));
-#endif
 	PageClearSwapCache(page);
 	remove_inode_page(page);
 }
@@ -224,19 +192,14 @@
  */
 void __delete_from_swap_cache(struct page *page)
 {
-	long entry = page->offset;
+	pte_t entry = get_pagecache_pte(page);
 
 #ifdef SWAP_CACHE_INFO
 	swap_cache_del_total++;
 #endif
-#ifdef DEBUG_SWAP
-	printk("DebugVM: delete_from_swap_cache(%08lx count %d, "
-		   "entry %08lx)\n",
-		   page_address(page), page_count(page), entry);
-#endif
-	remove_from_swap_cache (page);
+	remove_from_swap_cache(page);
 	lock_kernel();
-	swap_free (entry);
+	swap_free(entry);
 	unlock_kernel();
 }
 
@@ -268,10 +231,8 @@
  * this page if it is the last user of the page. 
  */
 
-void free_page_and_swap_cache(unsigned long addr)
+void free_page_and_swap_cache(struct page *page)
 {
-	struct page *page = mem_map + MAP_NR(addr);
-
 	/* 
 	 * If we are the only user, then free up the swap cache. 
 	 */
@@ -295,7 +256,7 @@
  * lock before returning.
  */
 
-struct page * lookup_swap_cache(unsigned long entry)
+struct page * lookup_swap_cache(pte_t entry)
 {
 	struct page *found;
 
@@ -303,7 +264,10 @@
 	swap_cache_find_total++;
 #endif
 	while (1) {
-		found = find_lock_page(&swapper_inode, entry);
+		/*
+		 * Right now the pagecache is 32-bit only.
+		 */
+		found = find_lock_page(&swapper_inode, pte_val(entry));
 		if (!found)
 			return 0;
 		if (found->inode != &swapper_inode || !PageSwapCache(found))
@@ -331,15 +295,11 @@
  * the swap entry is no longer in use.
  */
 
-struct page * read_swap_cache_async(unsigned long entry, int wait)
+struct page * read_swap_cache_async(pte_t entry, int wait)
 {
 	struct page *found_page = 0, *new_page;
 	unsigned long new_page_addr;
 	
-#ifdef DEBUG_SWAP
-	printk("DebugVM: read_swap_cache_async entry %08lx%s\n",
-		   entry, wait ? ", wait" : "");
-#endif
 	/*
 	 * Make sure the swap entry is still in use.
 	 */
@@ -368,11 +328,6 @@
 	 */
 	add_to_swap_cache(new_page, entry);
 	rw_swap_page(READ, new_page, wait);
-#ifdef DEBUG_SWAP
-	printk("DebugVM: read_swap_cache_async created "
-		   "entry %08lx at %p\n",
-			entry, (char *) page_address(new_page));
-#endif
 	return new_page;
 
 out_free_page:
diff -u --recursive --new-file v2.3.22/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.22/linux/mm/swapfile.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/swapfile.c	Tue Oct 19 10:22:19 1999
@@ -81,17 +81,18 @@
 	return 0;
 }
 
-unsigned long get_swap_page(void)
+pte_t get_swap_page(void)
 {
 	struct swap_info_struct * p;
-	unsigned long offset, entry;
+	unsigned long offset;
+	pte_t entry = __pte(0);
 	int type, wrapped = 0;
 
 	type = swap_list.next;
 	if (type < 0)
-		return 0;
+		goto out;
 	if (nr_swap_pages == 0)
-		return 0;
+		goto out;
 
 	while (1) {
 		p = &swap_info[type];
@@ -106,7 +107,7 @@
 				} else {
 					swap_list.next = type;
 				}
-				return entry;
+				goto out;
 			}
 		}
 		type = p->next;
@@ -115,19 +116,21 @@
 				type = swap_list.head;
 				wrapped = 1;
 			}
-		} else if (type < 0) {
-			return 0;	/* out of swap space */
-		}
+		} else
+			if (type < 0)
+				goto out;	/* out of swap space */
 	}
+out:
+	return entry;
 }
 
 
-void swap_free(unsigned long entry)
+void swap_free(pte_t entry)
 {
 	struct swap_info_struct * p;
 	unsigned long offset, type;
 
-	if (!entry)
+	if (!pte_val(entry))
 		goto out;
 
 	type = SWP_TYPE(entry);
@@ -154,10 +157,6 @@
 			nr_swap_pages++;
 		}
 	}
-#ifdef DEBUG_SWAP
-	printk("DebugVM: swap_free(entry %08lx, count now %d)\n",
-	       entry, p->swap_map[offset]);
-#endif
 out:
 	return;
 
@@ -171,24 +170,24 @@
 	printk("swap_free: offset exceeds max\n");
 	goto out;
 bad_free:
-	printk("swap_free: swap-space map bad (entry %08lx)\n",entry);
+	pte_ERROR(entry);
 	goto out;
 }
 
 /* needs the big kernel lock */
-unsigned long acquire_swap_entry(struct page *page)
+pte_t acquire_swap_entry(struct page *page)
 {
 	struct swap_info_struct * p;
 	unsigned long offset, type;
-	unsigned long entry;
+	pte_t entry;
 
 	if (!test_bit(PG_swap_entry, &page->flags))
 		goto new_swap_entry;
 
 	/* We have the old entry in the page offset still */
-	entry = page->offset;
-	if (!entry)
+	if (!page->offset)
 		goto new_swap_entry;
+	entry = get_pagecache_pte(page);
 	type = SWP_TYPE(entry);
 	if (type & SHM_SWP_TYPE)
 		goto new_swap_entry;
@@ -223,7 +222,7 @@
  * what to do if a write is requested later.
  */
 static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
-	pte_t *dir, unsigned long entry, unsigned long page)
+	pte_t *dir, pte_t entry, struct page* page)
 {
 	pte_t pte = *dir;
 
@@ -239,7 +238,7 @@
 		set_pte(dir, pte_mkdirty(pte));
 		return;
 	}
-	if (pte_val(pte) != entry)
+	if (pte_val(pte) != pte_val(entry))
 		return;
 	set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	swap_free(entry);
@@ -249,7 +248,7 @@
 
 static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
 	unsigned long address, unsigned long size, unsigned long offset,
-	unsigned long entry, unsigned long page)
+	pte_t entry, struct page* page)
 {
 	pte_t * pte;
 	unsigned long end;
@@ -257,7 +256,7 @@
 	if (pmd_none(*dir))
 		return;
 	if (pmd_bad(*dir)) {
-		printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
+		pmd_ERROR(*dir);
 		pmd_clear(dir);
 		return;
 	}
@@ -271,12 +270,12 @@
 		unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page);
 		address += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
 	unsigned long address, unsigned long size,
-	unsigned long entry, unsigned long page)
+	pte_t entry, struct page* page)
 {
 	pmd_t * pmd;
 	unsigned long offset, end;
@@ -284,7 +283,7 @@
 	if (pgd_none(*dir))
 		return;
 	if (pgd_bad(*dir)) {
-		printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
+		pgd_ERROR(*dir);
 		pgd_clear(dir);
 		return;
 	}
@@ -294,28 +293,32 @@
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
+	if (address >= end)
+		BUG();
 	do {
 		unuse_pmd(vma, pmd, address, end - address, offset, entry,
 			  page);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 }
 
 static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
-			unsigned long entry, unsigned long page)
+			pte_t entry, struct page* page)
 {
 	unsigned long start = vma->vm_start, end = vma->vm_end;
 
-	while (start < end) {
+	if (start >= end)
+		BUG();
+	do {
 		unuse_pgd(vma, pgdir, start, end - start, entry, page);
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		pgdir++;
-	}
+	} while (start && (start < end));
 }
 
-static void unuse_process(struct mm_struct * mm, unsigned long entry, 
-			unsigned long page)
+static void unuse_process(struct mm_struct * mm,
+			pte_t entry, struct page* page)
 {
 	struct vm_area_struct* vma;
 
@@ -340,8 +343,8 @@
 {
 	struct swap_info_struct * si = &swap_info[type];
 	struct task_struct *p;
-	struct page *page_map;
-	unsigned long entry, page;
+	struct page *page;
+	pte_t entry;
 	int i;
 
 	while (1) {
@@ -361,8 +364,8 @@
 		/* Get a page for the entry, using the existing swap
                    cache page if there is one.  Otherwise, get a clean
                    page and read the swap into it. */
-		page_map = read_swap_cache(entry);
-		if (!page_map) {
+		page = read_swap_cache(entry);
+		if (!page) {
 			/*
 			 * Continue searching if the entry became unused.
 			 */
@@ -370,7 +373,6 @@
 				continue;
   			return -ENOMEM;
 		}
-		page = page_address(page_map);
 		read_lock(&tasklist_lock);
 		for_each_task(p)
 			unuse_process(p->mm, entry, page);
@@ -378,17 +380,15 @@
 		shm_unuse(entry, page);
 		/* Now get rid of the extra reference to the temporary
                    page we've been using. */
-		if (PageSwapCache(page_map))
-			delete_from_swap_cache(page_map);
-		__free_page(page_map);
+		if (PageSwapCache(page))
+			delete_from_swap_cache(page);
+		__free_page(page);
 		/*
 		 * Check for and clear any overflowed swap map counts.
 		 */
 		if (si->swap_map[i] != 0) {
 			if (si->swap_map[i] != SWAP_MAP_MAX)
-				printk(KERN_ERR
-					"try_to_unuse: entry %08lx count=%d\n",
-					entry, si->swap_map[i]);
+				pte_ERROR(entry);
 			si->swap_map[i] = 0;
 			nr_swap_pages++;
 		}
diff -u --recursive --new-file v2.3.22/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v2.3.22/linux/mm/vmalloc.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/vmalloc.c	Fri Oct 22 11:29:54 1999
@@ -20,7 +20,7 @@
 	if (pmd_none(*pmd))
 		return;
 	if (pmd_bad(*pmd)) {
-		printk("free_area_pte: bad pmd (%08lx)\n", pmd_val(*pmd));
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
 		return;
 	}
@@ -29,7 +29,7 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
-	while (address < end) {
+	do {
 		pte_t page = *pte;
 		pte_clear(pte);
 		address += PAGE_SIZE;
@@ -37,11 +37,13 @@
 		if (pte_none(page))
 			continue;
 		if (pte_present(page)) {
-			free_page(pte_page(page));
+			unsigned long map_nr = pte_pagenr(page);
+			if (map_nr < max_mapnr)
+				__free_page(mem_map + map_nr);
 			continue;
 		}
 		printk("Whee.. Swapped out page in kernel page table\n");
-	}
+	} while (address < end);
 }
 
 static inline void free_area_pmd(pgd_t * dir, unsigned long address, unsigned long size)
@@ -52,7 +54,7 @@
 	if (pgd_none(*dir))
 		return;
 	if (pgd_bad(*dir)) {
-		printk("free_area_pmd: bad pgd (%08lx)\n", pgd_val(*dir));
+		pgd_ERROR(*dir);
 		pgd_clear(dir);
 		return;
 	}
@@ -61,11 +63,11 @@
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
-	while (address < end) {
+	do {
 		free_area_pte(pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	}
+	} while (address < end);
 }
 
 void vmfree_area_pages(unsigned long address, unsigned long size)
@@ -75,11 +77,11 @@
 
 	dir = pgd_offset_k(address);
 	flush_cache_all();
-	while (address < end) {
+	do {
 		free_area_pmd(dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
 	flush_tlb_all();
 }
 
@@ -91,17 +93,17 @@
 	end = address + size;
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
-	while (address < end) {
-		unsigned long page;
+	do {
+		struct page * page;
 		if (!pte_none(*pte))
 			printk("alloc_area_pte: page already exists\n");
-		page = __get_free_page(GFP_KERNEL|GFP_BIGMEM);
+		page = get_free_highpage(GFP_KERNEL|__GFP_HIGHMEM);
 		if (!page)
 			return -ENOMEM;
 		set_pte(pte, mk_pte(page, PAGE_KERNEL));
 		address += PAGE_SIZE;
 		pte++;
-	}
+	} while (address < end);
 	return 0;
 }
 
@@ -113,7 +115,7 @@
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
-	while (address < end) {
+	do {
 		pte_t * pte = pte_alloc_kernel(pmd, address);
 		if (!pte)
 			return -ENOMEM;
@@ -121,7 +123,7 @@
 			return -ENOMEM;
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	}
+	} while (address < end);
 	return 0;
 }
 
@@ -132,7 +134,7 @@
 
 	dir = pgd_offset_k(address);
 	flush_cache_all();
-	while (address < end) {
+	do {
 		pmd_t *pmd;
 		pgd_t olddir = *dir;
 		
@@ -145,7 +147,7 @@
 			set_pgdir(address, *dir);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
-	}
+	} while (address && (address < end));
 	flush_tlb_all();
 	return 0;
 }
@@ -202,14 +204,19 @@
 	struct vm_struct *area;
 
 	size = PAGE_ALIGN(size);
-	if (!size || size > (max_mapnr << PAGE_SHIFT))
+	if (!size || size > (max_mapnr << PAGE_SHIFT)) {
+		BUG();
 		return NULL;
+	}
 	area = get_vm_area(size);
-	if (!area)
+	if (!area) {
+		BUG();
 		return NULL;
+	}
 	addr = area->addr;
 	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) {
 		vfree(addr);
+		BUG();
 		return NULL;
 	}
 	return addr;
diff -u --recursive --new-file v2.3.22/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.22/linux/mm/vmscan.c	Sat Oct  9 11:47:50 1999
+++ linux/mm/vmscan.c	Tue Oct 19 10:22:19 1999
@@ -17,7 +17,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
-#include <linux/bigmem.h>
+#include <linux/highmem.h>
 
 #include <asm/pgtable.h>
 
@@ -34,23 +34,16 @@
  */
 static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask)
 {
-	pte_t pte;
-	unsigned long entry;
-	unsigned long page_addr;
+	pte_t pte, entry;
 	struct page * page;
 
 	pte = *page_table;
 	if (!pte_present(pte))
 		goto out_failed;
-	page_addr = pte_page(pte);
-	if (MAP_NR(page_addr) >= max_mapnr)
+	page = pte_page(pte);
+	if (page-mem_map >= max_mapnr)
 		goto out_failed;
 
-	page = mem_map + MAP_NR(page_addr);
-	spin_lock(&vma->vm_mm->page_table_lock);
-	if (pte_val(pte) != pte_val(*page_table))
-		goto out_failed_unlock;
-
 	/* Don't look at this pte if it's been accessed recently. */
 	if (pte_young(pte)) {
 		/*
@@ -59,14 +52,14 @@
 		 */
 		set_pte(page_table, pte_mkold(pte));
 		set_bit(PG_referenced, &page->flags);
-		goto out_failed_unlock;
+		goto out_failed;
 	}
 
 	if (PageReserved(page)
 	    || PageLocked(page)
 	    || ((gfp_mask & __GFP_DMA) && !PageDMA(page))
-	    || (!(gfp_mask & __GFP_BIGMEM) && PageBIGMEM(page)))
-		goto out_failed_unlock;
+	    || (!(gfp_mask & __GFP_HIGHMEM) && PageHighMem(page)))
+		goto out_failed;
 
 	/*
 	 * Is the page already in the swap cache? If so, then
@@ -77,14 +70,14 @@
 	 * memory, and we should just continue our scan.
 	 */
 	if (PageSwapCache(page)) {
-		entry = page->offset;
+		entry = get_pagecache_pte(page);
 		swap_duplicate(entry);
-		set_pte(page_table, __pte(entry));
+		set_pte(page_table, entry);
 drop_pte:
 		vma->vm_mm->rss--;
 		flush_tlb_page(vma, address);
 		__free_page(page);
-		goto out_failed_unlock;
+		goto out_failed;
 	}
 
 	/*
@@ -111,7 +104,7 @@
 	 * locks etc.
 	 */
 	if (!(gfp_mask & __GFP_IO))
-		goto out_failed_unlock;
+		goto out_failed;
 
 	/*
 	 * Ok, it's really dirty. That means that
@@ -136,9 +129,9 @@
 	if (vma->vm_ops && vma->vm_ops->swapout) {
 		int error;
 		pte_clear(page_table);
-		spin_unlock(&vma->vm_mm->page_table_lock);
-		flush_tlb_page(vma, address);
 		vma->vm_mm->rss--;
+		flush_tlb_page(vma, address);
+		vmlist_access_unlock(vma->vm_mm);
 		error = vma->vm_ops->swapout(vma, page);
 		if (!error)
 			goto out_free_success;
@@ -153,15 +146,15 @@
 	 * page with that swap entry.
 	 */
 	entry = acquire_swap_entry(page);
-	if (!entry)
-		goto out_failed_unlock; /* No swap space left */
+	if (!pte_val(entry))
+		goto out_failed; /* No swap space left */
 		
-	if (!(page = prepare_bigmem_swapout(page)))
-		goto out_swap_free_unlock;
+	if (!(page = prepare_highmem_swapout(page)))
+		goto out_swap_free;
 
 	vma->vm_mm->rss--;
-	set_pte(page_table, __pte(entry));
-	spin_unlock(&vma->vm_mm->page_table_lock);
+	set_pte(page_table, entry);
+	vmlist_access_unlock(vma->vm_mm);
 
 	flush_tlb_page(vma, address);
 	swap_duplicate(entry);	/* One for the process, one for the swap cache */
@@ -175,13 +168,9 @@
 out_free_success:
 	__free_page(page);
 	return 1;
-out_failed_unlock:
-	spin_unlock(&vma->vm_mm->page_table_lock);
-out_failed:
-	return 0;
-out_swap_free_unlock:
+out_swap_free:
 	swap_free(entry);
-	spin_unlock(&vma->vm_mm->page_table_lock);
+out_failed:
 	return 0;
 
 }
@@ -208,7 +197,7 @@
 	if (pmd_none(*dir))
 		return 0;
 	if (pmd_bad(*dir)) {
-		printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
+		pmd_ERROR(*dir);
 		pmd_clear(dir);
 		return 0;
 	}
@@ -227,7 +216,7 @@
 			return result;
 		address += PAGE_SIZE;
 		pte++;
-	} while (address < end);
+	} while (address && (address < end));
 	return 0;
 }
 
@@ -239,7 +228,7 @@
 	if (pgd_none(*dir))
 		return 0;
 	if (pgd_bad(*dir)) {
-		printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
+		pgd_ERROR(*dir);
 		pgd_clear(dir);
 		return 0;
 	}
@@ -247,7 +236,7 @@
 	pmd = pmd_offset(dir, address);
 
 	pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK;	
-	if (end > pgd_end)
+	if (pgd_end && (end > pgd_end))
 		end = pgd_end;
 	
 	do {
@@ -256,7 +245,7 @@
 			return result;
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
-	} while (address < end);
+	} while (address && (address < end));
 	return 0;
 }
 
@@ -272,13 +261,15 @@
 	pgdir = pgd_offset(vma->vm_mm, address);
 
 	end = vma->vm_end;
-	while (address < end) {
+	if (address >= end)
+		BUG();
+	do {
 		int result = swap_out_pgd(vma, pgdir, address, end, gfp_mask);
 		if (result)
 			return result;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		pgdir++;
-	}
+	} while (address && (address < end));
 	return 0;
 }
 
@@ -293,8 +284,10 @@
 	address = mm->swap_address;
 
 	/*
-	 * Find the proper vm-area
+	 * Find the proper vm-area after freezing the vma chain 
+	 * and ptes.
 	 */
+	vmlist_access_lock(mm);
 	vma = find_vma(mm, address);
 	if (vma) {
 		if (address < vma->vm_start)
@@ -310,6 +303,7 @@
 			address = vma->vm_start;
 		}
 	}
+	vmlist_access_unlock(mm);
 
 	/* We didn't find anything for the process */
 	mm->swap_cnt = 0;
@@ -502,8 +496,8 @@
 		 */
 		do {
 			/* kswapd is critical to provide GFP_ATOMIC
-			   allocations (not GFP_BIGMEM ones). */
-			if (nr_free_pages - nr_free_bigpages >= freepages.high)
+			   allocations (not GFP_HIGHMEM ones). */
+			if (nr_free_pages - nr_free_highpages >= freepages.high)
 				break;
 
 			if (!do_try_to_free_pages(GFP_KSWAPD))
diff -u --recursive --new-file v2.3.22/linux/net/core/dst.c linux/net/core/dst.c
--- v2.3.22/linux/net/core/dst.c	Tue Aug 31 17:29:15 1999
+++ linux/net/core/dst.c	Mon Oct 18 11:15:47 1999
@@ -5,7 +5,6 @@
  *
  */
 
-#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.3.22/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.3.22/linux/net/core/skbuff.c	Thu Aug 26 13:05:45 1999
+++ linux/net/core/skbuff.c	Mon Oct 18 11:26:37 1999
@@ -237,8 +237,10 @@
 	dst_release(skb->dst);
 	if(skb->destructor)
 		skb->destructor(skb);
+#ifdef CONFIG_NET		
 	if(skb->rx_dev)
 		dev_put(skb->rx_dev);
+#endif		
 	skb_headerinit(skb, NULL, 0);  /* clean state */
 	kfree_skbmem(skb);
 }
diff -u --recursive --new-file v2.3.22/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.22/linux/net/ipv4/tcp_ipv4.c	Fri Sep 10 23:57:38 1999
+++ linux/net/ipv4/tcp_ipv4.c	Mon Oct 18 11:15:47 1999
@@ -59,8 +59,6 @@
 #include <net/ipv6.h>
 #include <net/inet_common.h>
 
-#include <asm/segment.h>
-
 #include <linux/inet.h>
 #include <linux/stddef.h>
 
diff -u --recursive --new-file v2.3.22/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- v2.3.22/linux/net/sunrpc/clnt.c	Tue May 11 14:37:40 1999
+++ linux/net/sunrpc/clnt.c	Mon Oct 18 11:26:37 1999
@@ -459,6 +459,7 @@
 	req->rq_rvec[0].iov_len  = bufsiz;
 	req->rq_rlen		 = bufsiz;
 	req->rq_rnr		 = 1;
+	req->rq_damaged		 = 0;
 
 	if (task->tk_proc > clnt->cl_maxproc) {
 		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
@@ -466,6 +467,9 @@
 		rpc_exit(task, -EIO);
 		return;
 	}
+
+	/* Zero buffer so we have automatic zero-padding of opaque & string */
+	memset(task->tk_buffer, 0, bufsiz);
 
 	/* Encode header and provided arguments */
 	encode = rpcproc_encode(clnt, task->tk_proc);
diff -u --recursive --new-file v2.3.22/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.3.22/linux/net/sunrpc/sched.c	Fri Oct 15 15:25:14 1999
+++ linux/net/sunrpc/sched.c	Mon Oct 18 11:26:37 1999
@@ -75,6 +75,18 @@
 static int			swap_buffer_used = 0;
 
 /*
+ * Make allocation of the swap_buffer SMP-safe
+ */
+static __inline__ int rpc_lock_swapbuf(void)
+{
+	return !test_and_set_bit(1, &swap_buffer_used);
+}
+static __inline__ void rpc_unlock_swapbuf(void)
+{
+	clear_bit(1, &swap_buffer_used);
+}
+
+/*
  * Spinlock for wait queues. Access to the latter also has to be
  * interrupt-safe in order to allow timers to wake up sleeping tasks.
  */
@@ -614,7 +626,8 @@
 			dprintk("RPC:      allocated buffer %p\n", buffer);
 			return buffer;
 		}
-		if ((flags & RPC_TASK_SWAPPER) && !swap_buffer_used++) {
+		if ((flags & RPC_TASK_SWAPPER) && size <= sizeof(swap_buffer)
+		    && rpc_lock_swapbuf()) {
 			dprintk("RPC:      used last-ditch swap buffer\n");
 			return swap_buffer;
 		}
@@ -634,7 +647,7 @@
 		kfree(buffer);
 		return;
 	}
-	swap_buffer_used = 0;
+	rpc_unlock_swapbuf();
 }
 
 /*
