diff -u --recursive --new-file v2.3.12/linux/CREDITS linux/CREDITS
--- v2.3.12/linux/CREDITS	Wed Jul 21 15:46:48 1999
+++ linux/CREDITS	Fri Aug  6 13:22:22 1999
@@ -814,12 +814,15 @@
 
 N: Andre Hedrick
 E: hedrick@astro.dyer.vanderbilt.edu
+D: Random SMP kernel hacker...
 D: Uniform Multi-Platform E-IDE driver
-D: Aladdin 1533/1543(C) chipset IDE
-D: HighPoint HPT343/5 chipset IDE
-D: PIIX chipset IDE
-D: Promise Ultra/33 chipset IDE
-D: Promise Ultra/66 chipset IDE
+D: Aladdin 1533/1543(C) chipset
+D: Active-Chipset maddness..........
+D: HighPoint HPT343/5 Ultra/33 & HPT366 Ultra/66 chipsets
+D: Intel PIIX chipset
+D: Promise PDC20246/20247 & PDC20262 chipsets
+D: SiS5513 Ultra/66/33 chipsets
+D: VIA 82C586/596/686 chipsets
 S: Nashville, TN
 S: USA
 
@@ -2091,7 +2094,7 @@
 S: Australia
 
 N: Jeffrey A. Uphoff
-E: juphoff@nrao.edu
+E: juphoff@transmeta.com
 E: jeff.uphoff@linux.org
 P: 1024/9ED505C5 D7 BB CA AA 10 45 40 1B  16 19 0A C0 38 A0 3E CB
 D: Linux Security/Alert mailing lists' moderator/maintainer.
@@ -2099,9 +2102,9 @@
 D: PAM S/Key module developer.
 D: 'dip' contributor.
 D: AIPS port, astronomical community support.
-S: National Radio Astronomy Observatory
-S: 520 Edgemont Road
-S: Charlottesville, Virginia 22903
+S: Transmeta Corporation
+S: 2540 Mission College Blvd.
+S: Santa Clara, CA 95054
 S: USA
 
 N: Matthias Urlichs
@@ -2187,16 +2190,19 @@
 D: Miscellaneous MCA-support
 
 N: Matt Welsh
-E: mdw@sunsite.unc.edu
-D: Linux Documentation Project coordinator
-D: Author, _Running_Linux_ and I&GS guide
-D: Linuxdoc-SGML formatting system
+E: mdw@metalab.unc.edu
+W: http://www.cs.berkeley.edu/~mdw
+D: Original Linux Documentation Project coordinator
+D: Author, "Running Linux" (O'Reilly)
+D: Author, "Linux Installation and Getting Started" (LDP) and several HOWTOs
+D: Linuxdoc-SGML formatting system (now SGML-Tools)
+D: Device drivers for various high-speed network interfaces (Myrinet, ATM)
 D: Keithley DAS1200 device driver
-D: Maintainer of sunsite WWW and FTP, moderator c.o.l.answers
-S: Cornell University Computer Science Department
-S: Robotics and Vision Laboratory
-S: 4130 Upson Hall
-S: Ithaca, New York 14850
+D: Original maintainer of sunsite WWW and FTP sites
+D: Original moderator of c.o.l.announce and c.o.l.answers
+S: Computer Science Division
+S: UC Berkeley
+S: Berkeley, CA 94720-1776
 S: USA
 
 N: Greg Wettstein
@@ -2284,6 +2290,7 @@
 E: R.E.Wolff@BitWizard.nl
 D: Written kmalloc/kfree
 D: Written Specialix IO8+ driver
+D: Written Specialix SX driver
 S: van Bronckhorststraat 12
 S: 2612 XV Delft
 S: The Netherlands
diff -u --recursive --new-file v2.3.12/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.12/linux/Documentation/Changes	Thu Jul  8 15:42:19 1999
+++ linux/Documentation/Changes	Fri Aug  6 10:44:11 1999
@@ -61,7 +61,7 @@
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
 - Pcmcia-cs              3.0.7                   ; cardmgr -V
-- PPP                    2.3.5                   ; pppd --version
+- PPP                    2.3.9                   ; pppd --version
 - Util-linux             2.9i                    ; chsh -v
 
 Upgrade notes
@@ -390,8 +390,8 @@
 PPP
 ===
 
-   Due to changes in the routing code, those of you using PPP
-networking will need to upgrade your pppd.
+   Due to changes in the PPP driver and routing code, those of you
+using PPP networking will need to upgrade your pppd.
 
 iBCS
 ====
@@ -689,8 +689,8 @@
 PPP
 ===
 
-The 2.3.5 release:
-ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz
+The 2.3.9 release:
+ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.9.tar.gz
 
 IP Chains
 =========
diff -u --recursive --new-file v2.3.12/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.12/linux/Documentation/Configure.help	Wed Jul 28 14:47:42 1999
+++ linux/Documentation/Configure.help	Mon Aug  9 12:28:00 1999
@@ -546,6 +546,20 @@
 
   It is safe to say Y to this question.
 
+Use DMA by default when available
+CONFIG_IDEDMA_PCI_AUTO
+  Prior to kernel version 2.1.112, Linux used to automatically use
+  DMA for IDE drives and chipsets which support it. Due to concerns
+  about a couple of cases where buggy hardware may have caused damage,
+  the default is now to NOT use DMA automatically. To revert to the
+  previous behaviour, say Y to this question.
+
+  If you suspect your hardware is at all flakey, say N here.
+  Do NOT email the IDE kernel people regarding this issue!
+
+  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.
+
 Good-Bad DMA Model-Firmware (EXPERIMENTAL)
 IDEDMA_NEW_DRIVE_LISTINGS
   This test compares both the model and firmware revision for buggy drives
@@ -555,23 +569,6 @@
 
   If in doubt, say N.
 
-Generic ATA-66 support (DANGEROUS)
-CONFIG_IDEDMA_ULTRA_66
-  This allows for your Generic IDE control to attempt support for
-  using ATA-66 or UDMA-66 transfer modes 3/4.  If you are not sure what you
-  are attempting, "DO NOT" even think about this option, unless your
-  mainboard's chipset is verified.  Do not complain to anyone if you
-  do not know what you are doing and are just playing around.
-  This option has no known success cases to date.
-
-  Say N, or beware.........
-
-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
@@ -590,96 +587,31 @@
 
   If in doubt, say N.
 
-Use DMA by default when available
-CONFIG_IDEDMA_PCI_AUTO
-  Prior to kernel version 2.1.112, Linux used to automatically use
-  DMA for IDE drives and chipsets which support it. Due to concerns
-  about a couple of cases where buggy hardware may have caused damage,
-  the default is now to NOT use DMA automatically. To revert to the
-  previous behaviour, say Y to this question.
-
-  If you suspect your hardware is at all flakey, say N here.
-  Do NOT email the IDE kernel people regarding this issue!
-
-  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.
+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 include this driver.
 
-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.
+  This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless.
 
-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 1533, 1543 and 1543C
+  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.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
-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 like this.
 
 CY82C693 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_CY82C693
@@ -691,37 +623,67 @@
 
   Please read the comments at the top of drivers/block/cy82c693.c
 
-VIA82C586 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_VIA82C586
-  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 and
-  set DISPLAY_APOLLO_TIMINGS in via82c586.c
+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 or
+  HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers.
+  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/hpt34x.c
+
+HPT34X DMA support (DANGEROUS)
+CONFIG_BLK_DEV_HPT34X_DMA
   This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
-  If unsure, say N.
+  Please read the comments at the top of drivers/block/hpt34x.c
 
-CMD646 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_CMD646
-  Say Y here if you have an IDE controller like this.
+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.
 
-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/hpt366.c
 
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+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/alim15x3.c
+  Please read the comments at the top of drivers/block/piix.c
+
+  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 setup
+  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 to perform this task at INIT.
 
   If unsure, say N.
 
+NS87415 support (EXPERIMENTAL)
+CONFIG_BLK_DEV_NS87415
+  This driver adds detection and support for the NS87415 chip
+  (used in SPARC64, among others).
+
+  Please read the comments at the top of drivers/block/ns87415.c.
+
+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.
+
 PROMISE PDC20246/PDC20262 support
 CONFIG_BLK_DEV_PDC202XX
   Promise Ultra33 or PDC20246.
@@ -764,54 +726,127 @@
 
   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 include this driver.
+SiS5513 chipset support
+CONFIG_BLK_DEV_SIS5513
+  This driver ensures (U)DMA support for SIS5513 chipset based mainboards.
+  SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all other DMA mode 2
+  limited chipsets are unsupported to date.
 
-  This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
-  Please read the comments at the top of drivers/block/aec6210.c
+  Please read the comments at the top of drivers/block/sis5513.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'.
+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/piix.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.
+
+VIA82C586 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_VIA82C586
+  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 and
+  set DISPLAY_APOLLO_TIMINGS in via82c586.c
+
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   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 setup
-  the device/adapter combination and speed limits, It has become a necessity
-  to back/forward speed devices as needed.
+Support for PowerMac IDE devices (must also enable IDE)
+CONFIG_BLK_DEV_IDE_PMAC
+  No help for CONFIG_BLK_DEV_IDE_PMAC
 
-  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2
-  if the BIOS can to perform this task at INIT.
+PowerMac IDE DMA support
+CONFIG_BLK_DEV_IDEDMA_PMAC
+  No help for CONFIG_BLK_DEV_IDEDMA_PMAC
 
-  If unsure, say N.
+Use DMA by default
+CONFIG_IDEDMA_PMAC_AUTO
+  No help for CONFIG_IDEDMA_PMAC_AUTO
 
-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 or
-  HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers.
-  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.
+ICS IDE interface support
+CONFIG_BLK_DEV_IDE_ICSIDE
+  No help for CONFIG_BLK_DEV_IDE_ICSIDE
 
-  Please read the comments at the top of drivers/block/hpt343.c
+ICS DMA support
+CONFIG_BLK_DEV_IDEDMA_ICS
+  No help for CONFIG_BLK_DEV_IDEDMA_ICS
 
-HPT34X DMA support (DANGEROUS)
-CONFIG_BLK_DEV_HPT34X_DMA
-  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+Use ICS DMA by default
+CONFIG_IDEDMA_ICS_AUTO
+  No help for CONFIG_IDEDMA_ICS_AUTO
+
+RapIDE interface support
+CONFIG_BLK_DEV_IDE_RAPIDE
+  No help for CONFIG_BLK_DEV_IDE_RAPIDE
+
+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.
+
+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.
+
+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.
 
-  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
@@ -828,14 +863,6 @@
   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.
-
 Amiga builtin Gayle IDE interface support
 CONFIG_BLK_DEV_GAYLE
   This is the IDE driver for the builtin IDE interface on some Amiga
@@ -845,21 +872,6 @@
   (hard disks, CD-ROM drives, etc.) that are connected to the builtin
   IDE interface.
 
-Falcon IDE interface support
-CONFIG_BLK_DEV_FALCON_IDE
-  This is the IDE driver for the builtin IDE interface on the Atari Falcon.
-  Say Y if you have a Falcon and want to use IDE devices (hard disks,
-  CD-ROM drives, etc.) that are connected to the builtin IDE interface.
-
-Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL)
-CONFIG_BLK_DEV_BUDDHA
-  This is the IDE driver for the IDE interfaces on the Buddha and
-  Catweasel expansion boards.  It supports up to two interfaces on the
-  Buddha and three on the Catweasel.
-  Say Y if you have a Buddha or Catweasel expansion board and want to
-  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
-  to one of its IDE interfaces.
-
 Amiga IDE Doubler support (EXPERIMENTAL)
 CONFIG_BLK_DEV_IDEDOUBLER
   This driver provides support for the so called `IDE doublers' (made by
@@ -872,17 +884,20 @@
   Say Y if you have an IDE doubler.  The driver is enabled at kernel
   runtime using the "ide=doubler" kernel boot parameter.
 
-Support for PowerMac IDE devices (must also enable IDE)
-CONFIG_BLK_DEV_IDE_PMAC
-  No help for CONFIG_BLK_DEV_IDE_PMAC
-
-PowerMac IDE DMA support
-CONFIG_BLK_DEV_IDEDMA_PMAC
-  No help for CONFIG_BLK_DEV_IDEDMA_PMAC
+Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL)
+CONFIG_BLK_DEV_BUDDHA
+  This is the IDE driver for the IDE interfaces on the Buddha and
+  Catweasel expansion boards.  It supports up to two interfaces on the
+  Buddha and three on the Catweasel.
+  Say Y if you have a Buddha or Catweasel expansion board and want to
+  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
+  to one of its IDE interfaces.
 
-Use DMA by default
-CONFIG_IDEDMA_PMAC_AUTO
-  No help for CONFIG_IDEDMA_PMAC_AUTO
+Falcon IDE interface support
+CONFIG_BLK_DEV_FALCON_IDE
+  This is the IDE driver for the builtin IDE interface on the Atari Falcon.
+  Say Y if you have a Falcon and want to use IDE devices (hard disks,
+  CD-ROM drives, etc.) that are connected to the builtin IDE interface.
 
 Macintosh Quadra/Powerbook IDE interface support
 CONFIG_BLK_DEV_MAC_IDE
@@ -894,21 +909,15 @@
   (hard disks, CD-ROM drives, etc.) that are connected to the builtin
   IDE interface.
 
-ICS IDE interface support
-CONFIG_BLK_DEV_IDE_ICSIDE
-  No help for CONFIG_BLK_DEV_IDE_ICSIDE
-
-ICS DMA support
-CONFIG_BLK_DEV_IDEDMA_ICS
-  No help for CONFIG_BLK_DEV_IDEDMA_ICS
-
-Use ICS DMA by default
-CONFIG_IDEDMA_ICS_AUTO
-  No help for CONFIG_IDEDMA_ICS_AUTO
-
-RapIDE interface support
-CONFIG_BLK_DEV_IDE_RAPIDE
-  No help for CONFIG_BLK_DEV_IDE_RAPIDE
+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.
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
@@ -3529,6 +3538,13 @@
 ### Don't know what's going on here.
 ###
 #
+YAM driver for AX.25
+CONFIG_YAM
+  Support for the YAM modem on serial port. If you want to compile this
+  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.
+
 BAYCOM picpar and par96 driver for AX.25
 CONFIG_BAYCOM_PAR
   This is a driver for Baycom style simple amateur radio modems that
@@ -5173,23 +5189,11 @@
   end of the link as well. It's good enough, for example, to run IP
   over the async ports of a Camtec JNT Pad. If unsure, say N.
 
-PPP (point-to-point) support
+PPP (point-to-point protocol) support
 CONFIG_PPP
   PPP (Point to Point Protocol) is a newer and better SLIP. It serves
   the same purpose: sending Internet traffic over telephone (and other
-  serial) lines. Ask your access provider if they support it, because
-  otherwise you can't use it (not quite true any more: the free
-  program SLiRP can emulate a PPP line if you just have a regular dial
-  up shell account on some UNIX computer; get it via FTP (user:
-  anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/system/network/serial/). Note that
-  you don't need "PPP support" if you just want to run term (term is a
-  program which gives you almost full Internet connectivity if you
-  have a regular dial up shell account on some Internet connected UNIX
-  computer. Read
-  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html (to browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape)).
+  serial) lines.  Most ISPs these days support PPP rather than SLIP.
 
   To use PPP, you need an additional program called pppd as described
   in Documentation/networking/ppp.txt and in the PPP-HOWTO, available
@@ -5197,19 +5201,55 @@
   from an older kernel, you might need to upgrade pppd as well. The
   PPP option enlarges your kernel by about 16 KB.
 
+  Almost always, if you answer Y or M to this question, you should
+  give the same answer to the next question, about PPP support for
+  async serial ports.
+
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   If you said Y to "Version information on all symbols" above, then
   you cannot compile the PPP driver into the kernel; you can then only
-  compile it as a module. The module will be called ppp.o. If you want
-  to compile it as a module, say M here and read
+  compile it as a module. The module will be called ppp_generic.o.  If
+  you want to compile it as a module, say M here and read
   Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. Note that, no matter what
-  you do, the BSD compression code (used to compress the IP packets
-  sent over the serial line; has to be supported at the other end as
-  well) will always be compiled as a module; it is called bsd_comp.o
-  and will show up in the directory modules once you have said "make
-  modules". If unsure, say N.
+  Documentation/networking/net-modules.txt.
+
+PPP support for async serial ports
+CONFIG_PPP_ASYNC
+  Say Y (or M) here if you want to be able to use PPP over standard
+  asynchronous serial ports, such as COM1 or COM2 on a PC.  If you use
+  a modem (not a synchronous or ISDN modem) to contact your ISP, you
+  need this option.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
+PPP Deflate compression
+CONFIG_PPP_DEFLATE
+  Support for the Deflate compression method for PPP, which uses the
+  Deflate algorithm (the same algorithm that gzip uses) to compress
+  each PPP packet before it is sent over the wire.  The peer (the
+  machine at the other end of the PPP link, usually your ISP) has to
+  support the Deflate compression method as well for this to be
+  useful.
+
+  This code is also available as a module (code which can be inserted
+  into and removed from the running kernel).  If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
+PPP BSD-Compress compression
+CONFIG_PPP_BSDCOMP
+  Support for the BSD-Compress compression method for PPP, which uses
+  the LZW compression method to compress each PPP packet before it is
+  sent over the wire.  The peer (the other end of the PPP link) has to
+  support the BSD-Compress compression method as well for this to be
+  useful.  The PPP Deflate compression method is preferable to
+  BSD-Compress, because it compresses better and is patent-free.
+
+  Note that the BSD compression code will always be compiled as a
+  module; it is called bsd_comp.o and will show up in the directory
+  modules once you have said "make modules". If unsure, say N.
 
 Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
@@ -5312,26 +5352,6 @@
   say M here and read Documentation/modules.txt. The module will be
   called x25_asy.o. If unsure, say N.
 
-Shortwave radio modem driver
-CONFIG_HFMODEM
-  This experimental driver is used by a package (to be released)
-  that implements the shortwave radio protocols RTTY, Sitor (Amtor),
-  Pactor 1 and GTOR using a standard PC sound card. If unsure,
-  say N.
-
-Shortwave radio modem driver support for Sound Blaster and compatible cards
-CONFIG_HFMODEM_SBC
-  This option enables the hfmodem driver to use Sound Blaster and
-  compatible cards. It requires a 16bit capable card, i.e.
-  SB16 or better, or ESS1688 or newer.
-
-Shortwave radio modem driver support for WSS and Crystal cards
-CONFIG_HFMODEM_WSS
-  This option enables the hfmodem driver to use WindowsSoundSystem
-  compatible cards. These cards feature a codec chip from either
-  Analog Devices (such as AD1848, AD1845) or Crystal Semiconductors
-  (such as CS4248, CS423x).
-
 PLIP (parallel port) support
 CONFIG_PLIP
   PLIP (Parallel Line Internet Protocol) is used to create a
@@ -5534,7 +5554,7 @@
   section (except for CONFIG_IP_ROUTE_TOS and CONFIG_IP_ROUTE_FWMARK).
   At the moment, few devices support fast switching (tulip is one of
   them, modified 8390 can be found at
-  ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz).
+  ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz).
 
   If unsure, say N.
 
@@ -5544,8 +5564,8 @@
   during periods of extremal congestion. At the moment only a couple
   of device drivers support it (really only one -- tulip, modified
   8390 can be found at
-  ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). Really, this
-  option is applicable to any machine attached to a fast enough
+  ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz).
+  Really, this option is applicable to any machine attached to a fast enough
   network, and even a 10 Mb NIC is able to kill a not very slow box,
   such as a 120MHz Pentium.
 
@@ -9397,7 +9417,7 @@
 
   If you run Linux on a multiprocessor machine and said Y to
   "Symmetric Multi Processing" above, you should say Y here to read
-  and set the RTC clock in an SMP compatible fashion.
+  and set the RTC in an SMP compatible fashion.
 
   If you think you have a use for such a device (such as periodic data
   sampling), then say Y here, and read Documentation/rtc.txt for
@@ -11938,10 +11958,20 @@
   This driver will eventually handle audio devices, such 
   as USB speakers.
 
-USB Abstract Control Model support (Preliminary)
+USB Communications Device Class (ACM) support (Preliminary)
 CONFIG_USB_ACM
-  This driver allows for devices which support the Abstract Control Model,
-  including many USB-based modems, ISDN adapters, and network adapters.
+  This driver handles devices which support the Abstract Control Model,
+  a subtype of the USB Communications Device Class. This includes many
+  USB-based modems and ISDN adapters. Add special files with:
+  mknod /dev/ttyACM0 c 166 0 
+  mknod /dev/ttyACM1 c 166 1
+  mknod /dev/ttyACM2 c 166 2
+  mknod /dev/ttyACM3 c 166 3
+
+USS720 parport driver
+CONFIG_USB_USS720
+  This driver is for USB parallel port adapters that use the USS-720
+  chip.
 
 USB /proc filesystem entry support (Preliminary)
 CONFIG_USB_PROC
@@ -12102,7 +12132,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:  HFMODEM shortwave Sitor Amtor Pactor GTOR hfmodem hayes TX TMOUT
+# LocalWords:  hayes TX TMOUT
 # 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.12/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.3.12/linux/Documentation/devices.tex	Thu May 13 11:00:08 1999
+++ linux/Documentation/devices.tex	Thu Aug  5 18:48:45 1999
@@ -1784,11 +1784,31 @@
 \end{devicelist}
 
 \begin{devicelist}
+\major{  }{}{block}{Eighth IDE hard disk/CD-ROM interface}
+	\minor{0}{/dev/hdq}{Master: whole disk (or CD-ROM)}
+	\minor{64}{/dev/hdr}{Slave: whole disk (or CD-ROM)}
+\end{devicelist}
+
+\noindent
+Partitions are handled the same way as for the first interface (see
+major number 3).
+
+\begin{devicelist}
 \major{91}{}{char }{CAN-Bus controller}
 	\minor{0}{/dev/can0}{First CAN-Bus controller}
 	\minor{1}{/dev/can1}{Second CAN-Bus controller}
 	\minordots
 \end{devicelist}
+
+\begin{devicelist}
+\major{  }{}{block}{Ninth IDE hard disk/CD-ROM interface}
+	\minor{0}{/dev/hds}{Master: whole disk (or CD-ROM)}
+	\minor{64}{/dev/hdt}{Slave: whole disk (or CD-ROM)}
+\end{devicelist}
+
+\noindent
+Partitions are handled the same way as for the first interface (see
+major number 3).
 
 \begin{devicelist}
 \major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card}
diff -u --recursive --new-file v2.3.12/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.3.12/linux/Documentation/devices.txt	Thu May 13 11:00:08 1999
+++ linux/Documentation/devices.txt	Thu Aug  5 18:48:45 1999
@@ -1241,10 +1241,24 @@
 		 30 = /dev/mtd15	16th MTD (rw)
 		 31 = /dev/mtdr15	16th MTD (ro)
 
+    block	Eighth IDE hard disk/CD-ROM interface
+		  0 = /dev/hdq		Master: whole disk (or CD-ROM)
+		 64 = /dev/hdr		Slave: whole disk (or CD-ROM)
+
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
  91 char	CAN-Bus devices
 		  0 = /dev/can0		First CAN-Bus controller
 		  1 = /dev/can1		Second CAN-Bus controller
 		    ...
+
+    block	Ninth IDE hard disk/CD-ROM interface
+		  0 = /dev/hds		Master: whole disk (or CD-ROM)
+		 64 = /dev/hdt		Slave: whole disk (or CD-ROM)
+
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
 
  92 char	Reserved for ith Kommunikationstechnik MIC ISDN card
 
diff -u --recursive --new-file v2.3.12/linux/Documentation/joystick-api.txt linux/Documentation/joystick-api.txt
--- v2.3.12/linux/Documentation/joystick-api.txt	Wed Oct 21 08:43:33 1998
+++ linux/Documentation/joystick-api.txt	Wed Aug  4 21:08:36 1999
@@ -1,7 +1,7 @@
 		      Joystick API Documentation                -*-Text-*-
 
 		       Ragnar Hojland Espinosa
-		     <ragnar@lightside.ddns.org>
+		     <ragnar@lightside.dhis.org>
 
 			      7 Aug 1998
 
@@ -74,9 +74,10 @@
 	2nd Axis Y	3
 	...and so on
 
-Hats vary from one joystick type to another. Some can be moved in 8
-directions, some only in 4, however, the driver always reports a hat as two
-independent axis, even if the hardware doesn't allow independent movement.
+Hats vary from one joystick type to another.  Some can be moved in 8
+directions, some only in 4.  The driver, however, always reports a hat
+as two independent axis, even if the hardware doesn't allow independent
+movement. 
 
 
 2.3 js_event.value
@@ -85,7 +86,7 @@
 For an axis, ``value'' is a signed integer between -32767 and +32767
 representing the position of the joystick along that axis. If you
 don't read a 0 when the joystick is `dead', or if it doesn't span the
-full range, you should recalibrate (with, for example, jscal).
+full range, you should recalibrate it (with, for example, jscal).
 
 For a button, ``value'' for a press button event is 1 and for a release
 button event is 0.
@@ -93,16 +94,16 @@
 Though this
 
 	if (js_event.type == JS_EVENT_BUTTON) {
-	   buttons_state ^= (1 << js_event.number);
+		buttons_state ^= (1 << js_event.number);
 	}
 
 may work well if you handle JS_EVENT_INIT events separately,
 
 	if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
-	   if (js_event.value)
-	      buttons_state |= (1 << js_event.number);
-	   else
-	      buttons_state &= ~(1 << js_event.number);
+		if (js_event.value)
+	        	buttons_state |= (1 << js_event.number);
+	   	else
+	      		buttons_state &= ~(1 << js_event.number);
 	}
 
 is much safer since it can't lose sync with the driver. As you would
@@ -112,6 +113,7 @@
 
 2.4 js_event.time
 ~~~~~~~~~~~~~~~~~
+
 The time an event was generated is stored in ``js_event.time''. It's a time
 in miliseconds since ... well, since sometime in the past.  This eases the
 task of detecting double clicks, figuring out if movement of axis and button
@@ -144,14 +146,14 @@
 For example,
 
 	while (1) {
-	   while (read (fd, &e, sizeof(struct js_event)) > 0) {
-	      process_event (e);
-	   }
-	   /* EAGAIN is returned when the queue is empty */
-	   if (errno != EAGAIN) {
-	      /* error */
-	   }
-	   /* do something interesting with processed events */
+		while (read (fd, &e, sizeof(struct js_event)) > 0) {
+	        	process_event (e);
+	   	}
+	   	/* EAGAIN is returned when the queue is empty */
+	   	if (errno != EAGAIN) {
+	      		/* error */
+	   	}
+	   	/* do something interesting with processed events */
 	}
 
 One reason for emptying the queue is that if it gets full you'll start
@@ -219,6 +221,7 @@
 	#ifdef JS_VERSION
 	#if JS_VERSION > 0xsomething
 
+
 4.2 JSIOCGNAME
 ~~~~~~~~~~~~~~
 
@@ -232,6 +235,7 @@
 		strncpy(name, "Unknown", sizeof(name));
 	printf("Name: %s\n", name);
 
+
 4.3 JSIOC[SG]CORR
 ~~~~~~~~~~~~~~~~~
 
@@ -266,10 +270,10 @@
 
 	struct JS_DATA_TYPE js;
 	while (1) {
-	   if (read (fd, &js, JS_RETURN) != JS_RETURN) {
-	      /* error */
-	   }
-	   usleep (1000);
+		if (read (fd, &js, JS_RETURN) != JS_RETURN) {
+	      		/* error */
+	   	}
+	   	usleep (1000);
 	}
 
 As you can figure out from the example, the read returns immediately,
@@ -298,6 +302,7 @@
 The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
 called Multisystem joystick in this driver), under /dev/djsX. This driver
 doesn't try to be compatible with that interface.
+
 
 6. Final Notes
 ~~~~~~~~~~~~~~
diff -u --recursive --new-file v2.3.12/linux/Documentation/modules.txt linux/Documentation/modules.txt
--- v2.3.12/linux/Documentation/modules.txt	Tue Mar 10 14:43:13 1998
+++ linux/Documentation/modules.txt	Thu Aug  5 14:34:01 1999
@@ -59,7 +59,7 @@
 	Most low-level SCSI drivers: (i.e. aha1542, in2000)
 	All SCSI high-level drivers: disk, tape, cdrom, generic.
 
-	Most ethernet drivers: (too many to list, please see the file
+	Most Ethernet drivers: (too many to list, please see the file
 				./Documentation/networking/net-modules.txt)
 
 	Most CDROM drivers:
diff -u --recursive --new-file v2.3.12/linux/Documentation/mtrr.txt linux/Documentation/mtrr.txt
--- v2.3.12/linux/Documentation/mtrr.txt	Thu Jun  3 08:17:28 1999
+++ linux/Documentation/mtrr.txt	Thu Aug  5 14:34:01 1999
@@ -52,7 +52,7 @@
 reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
 reg02: base=0xf8000000 (3968MB), size=   4MB: write-combining, count=1
 
-This is for videoram at base address 0xf8000000 and size 4 MBytes. To
+This is for video RAM at base address 0xf8000000 and size 4 megabytes. To
 find out your base address, you need to look at the output of your X
 server, which tells you where the linear framebuffer address is. A
 typical line that you may get is:
@@ -68,7 +68,7 @@
 
 (--) S3: videoram:  4096k
 
-That's 4 MBytes, which is 0x400000 bytes (in hexadecimal).
+That's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
 A patch is being written for XFree86 which will make this automatic:
 in other words the X server will manipulate /proc/mtrr using the
 ioctl() interface, so users won't have to do anything. If you use a
diff -u --recursive --new-file v2.3.12/linux/Documentation/nbd.txt linux/Documentation/nbd.txt
--- v2.3.12/linux/Documentation/nbd.txt	Thu Feb 26 11:01:24 1998
+++ linux/Documentation/nbd.txt	Thu Aug  5 14:34:01 1999
@@ -4,11 +4,11 @@
    means, that it works on my computer, and it worked on one of school
    computers.
    
-   What is it: With this compiled in the kernel, linux can use a remote
+   What is it: With this compiled in the kernel, Linux can use a remote
    server as one of its block devices. So every time the client computer
    wants to read /dev/nd0, it sends a request over TCP to the server, which
    will reply with the data read. This can be used for stations with
-   low-disk space (or even diskless - if you boot from floppy) to
+   low disk space (or even diskless - if you boot from floppy) to
    borrow disk space from another computer. Unlike NFS, it is possible to
    put any filesystem on it etc. It is impossible to use NBD as a root
    filesystem, since it requires a user-level program to start. It also
diff -u --recursive --new-file v2.3.12/linux/Documentation/networking/00-INDEX linux/Documentation/networking/00-INDEX
--- v2.3.12/linux/Documentation/networking/00-INDEX	Wed May 20 18:54:34 1998
+++ linux/Documentation/networking/00-INDEX	Thu Aug  5 14:34:01 1999
@@ -13,9 +13,9 @@
 alias.txt
 	- info on using alias network devices 
 arcnet-hardware.txt
-	- tons of info on arcnet, hubs, arcnet card jumper settings, etc.
+	- tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc.
 arcnet.txt
-	- info on the using the arcnet driver itself.
+	- info on the using the ARCnet driver itself.
 ax25.txt
 	- info on using AX.25 and NET/ROM code for Linux
 baycom.txt
@@ -69,13 +69,13 @@
 smc9.txt
 	- the driver for SMC's 9000 series of Ethernet cards
 soundmodem.txt
-	- Linux driver for soundcards as AX.25 modems
+	- Linux driver for sound cards as AX.25 modems
 tcp.txt
 	- short blurb on how TCP output takes place.
 tulip.txt
 	- info on using DEC 21040/21041/21140 based PCI Ethernet cards.
 vortex.txt
-	- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards.
+	- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
 wan-router.txt
 	- Wan router documentation
 wanpipe.txt
diff -u --recursive --new-file v2.3.12/linux/Documentation/networking/Configurable linux/Documentation/networking/Configurable
--- v2.3.12/linux/Documentation/networking/Configurable	Thu Sep  4 13:25:28 1997
+++ linux/Documentation/networking/Configurable	Thu Aug  5 14:34:01 1999
@@ -20,11 +20,11 @@
 	7000
 
 Others are already accessible via the related user space programs.
-For example, MAX_WINDOW has a default of 32k which is a good choice for
-modern hardware, but if you have a slow (8 bit) ethercard and/or a slow
+For example, MAX_WINDOW has a default of 32 k which is a good choice for
+modern hardware, but if you have a slow (8 bit) Ethernet card and/or a slow
 machine, then this will be far too big for the card to keep up with fast 
-Tx'ing machines on the same net, resulting in overruns and receive errors.
-A value of about 4k would be more appropriate, which can be set via:
+machines transmitting on the same net, resulting in overruns and receive errors.
+A value of about 4 k would be more appropriate, which can be set via:
 
 	# route add -net 192.168.3.0 window 4096
 
diff -u --recursive --new-file v2.3.12/linux/Documentation/networking/DLINK.txt linux/Documentation/networking/DLINK.txt
--- v2.3.12/linux/Documentation/networking/DLINK.txt	Wed May 20 18:54:34 1998
+++ linux/Documentation/networking/DLINK.txt	Thu Aug  5 14:34:01 1999
@@ -18,8 +18,8 @@
 	pocket adapters, for the parallel port on a Linux based machine.
 	Some adapter "clones" will also work.  Xircom is _not_ a clone...
 	These drivers _can_ be used as loadable modules,
-	and were developed for use on Linux v1.1.13 and above.
-	For use on Linux v1.0.X, or earlier releases, see below.
+	and were developed for use on Linux 1.1.13 and above.
+	For use on Linux 1.0.X, or earlier releases, see below.
 
 	I have used these drivers for NFS, ftp, telnet and X-clients on
 	remote machines. Transmissions with ftp seems to work as
@@ -57,7 +57,7 @@
 	de620.h       Macros for de620.c
 
 	If you are upgrading from the d-link tar release, there will
-	also be a "dlink-patches" file that will patch Linux v1.1.18:
+	also be a "dlink-patches" file that will patch Linux 1.1.18:
 		linux/drivers/net/Makefile
 		linux/drivers/net/CONFIG
 		linux/drivers/net/MODULES
@@ -162,10 +162,10 @@
 
 	6. USING THE DRIVERS WITH EARLIER RELEASES.
 
-	The later v1.1.X releases of the Linux kernel include some
+	The later 1.1.X releases of the Linux kernel include some
 	changes in the networking layer (a.k.a. NET3). This affects
 	these drivers in a few places.  The hints that follow are
-	_not_ tested by me, since I don't have the diskspace to keep
+	_not_ tested by me, since I don't have the disk space to keep
 	all releases on-line.
 	Known needed changes to date:
 	- release patchfile: some patches will fail, but they should
diff -u --recursive --new-file v2.3.12/linux/Documentation/networking/dgrs.txt linux/Documentation/networking/dgrs.txt
--- v2.3.12/linux/Documentation/networking/dgrs.txt	Wed May 20 18:54:34 1998
+++ linux/Documentation/networking/dgrs.txt	Thu Aug  5 14:34:01 1999
@@ -1,4 +1,4 @@
-	The Digi Intl. RightSwitch SE-X (dgrs) Device Driver
+    The Digi International RightSwitch SE-X (dgrs) Device Driver
 
 This is a Linux driver for the Digi International RightSwitch SE-X
 EISA and PCI boards.  These are 4 (EISA) or 6 (PCI) port Ethernet
diff -u --recursive --new-file v2.3.12/linux/Documentation/networking/multicast.txt linux/Documentation/networking/multicast.txt
--- v2.3.12/linux/Documentation/networking/multicast.txt	Thu Jun  4 22:53:50 1998
+++ linux/Documentation/networking/multicast.txt	Mon Aug  9 10:23:09 1999
@@ -1,11 +1,13 @@
-Behaviour of cards under Multicast. This is how they currently 
-behave not what the hardware can do - i.e. the lance driver doesn't
-use its filter, even though the code for loading it is in the DEC
-lance based driver.
+Behaviour of Cards Under Multicast
+==================================
 
-The following multicast requirements are needed
+This is how they currently behave, not what the hardware can do--for example,
+the Lance driver doesn't use its filter, even though the code for loading
+it is in the DEC Lance-based driver.
+
+The following are requirements for multicasting 
 -----------------------------------------------
-Appletalk	Multicast	hardware filtering not important but
+AppleTalk	Multicast	hardware filtering not important but
 				 avoid cards only doing promisc
 IP-Multicast	Multicast	hardware filters really help
 IP-MRoute	AllMulti	hardware filters are of no help
diff -u --recursive --new-file v2.3.12/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt
--- v2.3.12/linux/Documentation/scsi-generic.txt	Sat Apr 24 17:49:37 1999
+++ linux/Documentation/scsi-generic.txt	Thu Aug  5 14:34:01 1999
@@ -1,34 +1,38 @@
-            Notes on Linux's SG driver version 2.1.30
+            Notes on Linux's SG driver version 2.1.34
             -----------------------------------------
-                                                        990328
+                                                        990606
 
 Introduction
 ============
+Sg is one of the four "high level" SCSI device drivers along with
+sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized
+(but lower level) than its siblings and tends to be used on SCSI devices
+that don't fit into the already serviced categories. Thus sg is used for
+scanners, cd writers and reading audio cds digitally amongst other things.
+
 These are notes on the Linux SCSI generic packet device driver (sg)
-describing version 2.1.30 . The original driver was written by Lawrence
-Foard and has remained in place with minimal changes since circa 1992.
+describing version 2.1.34 . The original driver was written by Lawrence
+Foard and remained in place with minimal changes since circa 1992.
 Version 2 of this driver remains backward compatible (binary and
 source **) with the original. It adds scatter gather, command queuing,
 per file descriptor sequencing, asynchronous notification and better
 error reporting.
 
-Sg is one of the four "high level" SCSI device drivers along with
-sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized
-(but lower level) than its sibling and tends to be used on SCSI devices
-that don't fit into the already serviced categories. Thus sg is used for
-scanners, cd writers and reading audio cds amongst other things.
+This is an abridged version of the sg documentation that is targeted
+at the linux/Documentation directory. The full document can be found
+at http://www.torque.net/sg/p/scsi-generic_long.txt .
 
-The interface and usage of the original sg driver has been documented
+The interface and usage of the original sg driver have been documented
 by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
 of the document is version 1.5 dated 7th May 1996. It can found at
-ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO .
-Amongst other things it has a lot of tables from the SCSI-2 standard
-that are very useful for programming this interface.
+ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO .
+A copy of this document can be found at:
+http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO .
 
 ** It is possible to write applications that perform differently
 depending on whether they are using the original or this version of
-the sg device driver. The author is not aware of any useful applications
-that have problems with version 2 (yet).
+the sg device driver. The author is not aware of any useful 
+pre-existing applications that have problems with version 2 (yet).
 
 
 Architecture
@@ -38,9 +42,11 @@
 the others are sd (for direct-access devices - disks), st (for tapes)
 and sr (for data cdroms). The other three devices are block devices.
 
-The unifying layer of the SCSI sub-system in the so-called mid-level.
-Below that are all the drivers for the various adapters supported by
-Linux.
+The unifying layer of the SCSI sub-system is the so-called mid-level.
+Below that are the "low level" drivers which are the drivers for the
+various adapters supported by Linux. Also at this level are pseudo
+adapter drivers such as ide-scsi which converts the SCSI protocol to
+ATAPI (which are similar to one another) for use by IDE devices.
 
 Since sg is a character device it supports the traditional Unix
 system calls of open(), close(), read(), write() and ioctl(). Two other
@@ -85,8 +91,9 @@
     unsigned char sense_buffer[16];
 }; /* this structure is 36 bytes long */
 
-The 'pack_len' is bizzare and ends up having the 'reply_len' put in it
-(perhaps it had a use at some stage). 
+The 'pack_len' is bizarre and ends up having the 'reply_len' put in it
+(perhaps it had a use at some stage). Even though it looks like an
+input variable, it is not read by sg internally (only written).
 
 The 'reply_len' is the length of the data the corresponding read()
 will/should request (including the sg_header). 
@@ -95,14 +102,14 @@
 back to the corresponding read() so it can be used for sequencing by an
 application. 
 
-The 'result' is also bizzare, turning certain types of host codes it 0 (no
+The 'result' is also bizarre, turning certain types of host codes to 0 (no
 error), EBUSY or EIO. With better error reporting now available, the
 'result' is best ignored.
 
-The 'twelve_byte' field overrides the internal SCSI command length "guessing"
+The 'twelve_byte' field overrides the internal SCSI command length detection
 algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
-a command lenth of 12 bytes.
-The command length "guessing" algorithm is as follows:
+a command length of 12 bytes.
+The command length detection algorithm is as follows:
 Group:  0    1    2    3    4    5    6    7
 Length: 6   10   10   12   12   12   10   10
 
@@ -115,6 +122,7 @@
 buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
 this is unlikely to happen in the 2.2.x series of kernels.
 
+
 The new sg_header offered in this driver is:
 #define SG_MAX_SENSE 16
 struct sg_header
@@ -122,15 +130,17 @@
     int pack_len;    /* [o] reply_len (ie useless) ignored as input */
     int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
     int pack_id;     /* [io] id number of packet (use ints >= 0) */
-    int result;      /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */
+    int result;      /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
     unsigned int twelve_byte:1;
         /* [i] Force 12 byte command length for group 6 & 7 commands  */
     unsigned int target_status:5;   /* [o] scsi status from target */
     unsigned int host_status:8;     /* [o] host status (see "DID" codes) */
     unsigned int driver_status:8;   /* [o] driver status+suggestion */
     unsigned int other_flags:10;    /* unused */
-    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is
-               CHECK_CONDITION or COMMAND_TERMINATED this is output. */
+    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
+           when target_status is CHECK_CONDITION or 
+           when target_status is COMMAND_TERMINATED or
+           when (driver_status & DRIVER_SENSE) is true. */
 };      /* This structure is 36 bytes long on i386 */
 
 Firstly the new header is binary compatible with the original. This is
@@ -146,6 +156,9 @@
 the value of 'pack_id' available after a read() is the value given to that
 variable in the prior, corresponding write().
 
+The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN
+ioctl().
+
 The 'target_status' field is always output and is the (masked and shifted
 1 bit right) SCSI status code from the target device. The allowable
 values are (found in <scsi/scsi.h>):
@@ -162,28 +175,28 @@
 When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
 'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
 is true then the 'sense_buffer' is also output (this seems to occur when
-the scsi ide emulation is used). When the 'sense_buffer' is output the 
+the ide-scsi emulation is used). When the 'sense_buffer' is output the 
 SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
 
 The 'host_status' field is always output and has the following values
-whose "defines" are not visible outside the kernel (unfortunately):
+whose "defines" are not visible outside the kernel. A copy of these
+defines can be found in sg_err.h (see the utilities section):
 #define DID_OK          0x00 /* NO error                                */
 #define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
 #define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
 #define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
-#define DID_BAD_TARGET  0x04 /* BAD target.                             */
+#define DID_BAD_TARGET  0x04 /* BAD target, device not responding?      */
 #define DID_ABORT       0x05 /* Told to abort for some other reason     */
 #define DID_PARITY      0x06 /* Parity error                            */
-#define DID_ERROR       0x07 /* Internal error                          */
+#define DID_ERROR       0x07 /* Internal error [DMA underrun on aic7xxx]*/
 #define DID_RESET       0x08 /* Reset by somebody.                      */
 #define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */
 #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
-#define DID_SOFT_ERROR  0x0b /* The low level driver just wish a retry  */
+#define DID_SOFT_ERROR  0x0b /* The low level driver wants a retry      */
 
 The 'driver_status' field is always output. When ('driver_status' &
-DRIVER_SENSE) is true the 'sense_buffer' is also output. The following
-values whose "defines" are not visible outside the kernel (unfortunately)
-can occur:
+DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these
+defines can be found in sg_err.h (see the utilities section):
 #define DRIVER_OK           0x00 /* Typically no suggestion */
 #define DRIVER_BUSY         0x01
 #define DRIVER_SOFT         0x02
@@ -192,7 +205,7 @@
 #define DRIVER_INVALID      0x05
 #define DRIVER_TIMEOUT      0x06
 #define DRIVER_HARD         0x07
-#define DRIVER_SENSE        0x08
+#define DRIVER_SENSE        0x08 /* Implies sense_buffer output */
 /* above status 'or'ed with one of the following suggestions */
 #define SUGGEST_RETRY       0x10
 #define SUGGEST_ABORT       0x20
@@ -200,55 +213,8 @@
 #define SUGGEST_DIE         0x40
 #define SUGGEST_SENSE       0x80
 
-'other_flags' still remains as a 10 bit field, so code that places 0 in it
-will still be happy. It is not used.
-
-
-memory
-======
-Memory is a scarce resource in any computer. Sg needs to reserve memory
-suitable for DMA roughly equal in size to the maximum of the write and
-read data buffers for each packet. This DMA memory is obtained at the time
-of a write() and released when the corresponding read() is called (although
-if memory is tight it may be using the buffer reserved by the open() ).
-
-Linux obtaining memory a challenge for several reasons. The memory pool
-that sg uses is in common with all other device drivers and all user
-processes. In this environment the only way to 99.9% guarantee a driver
-will have memory in Linux is to build it into the kernel (ie not as a
-module) and then reserve it on initialization before user processes get
-a chance. [Of course, another driver initialized before sg could take
-all available memory ...] Another problem is the biggest contiguous
-chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE
-(which is 128KBytes on i386). As memory gets "splintered" there is a good
-chance that buffers won't be available (my machine has 64 MBytes of RAM
-and has 3 available at the moment).
-
-The original sg driver used the following technique: grab a SG_BIG_BUFF
-sized buffer at driver initialization and use it for all requests greater
-than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to
-32 KBytes in the origianl driver but many applications suggest that the
-user increases this number. Linux limits the biggest single buffer of
-this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the
-sg driver is a module then there is a high chance a contiguous block of
-that large size will not be available at module initialization.
-
-The author has found no "silver bullet" solution but uses multiple
-techniques hoping that at least one is able provide memory at the critical
-time. Listed below are some of these techniques:
-        - use scatter gather: then instead of one large buffer needing to
-          be found, multiple smaller buffer can be used
-        - use memory above the 16MByte level: the original driver limited
-          itself to obtaining memory below the 16MByte level (on the i386)
-          due to the shortcomings of DMA on ISA adapters. Yet more and more
-          people use PCI adapters that don't have this problem. So make
-          the decision based on the capabilities of the host adpater
-          associated with the current SCSI device
-        - reserve some memory at open() for emergencies but otherwise
-          fetch and release it on a per packet basis
-        - if the kernel is short of memory then dip into the SCSI DMA
-          pool (maintained by the mid-level driver) to a limited amount
-
+'other_flags' still remains as a 10 bit field (reduced from 31 bits), so
+code that places 0 in it will still be happy. It is not used.
 
 
 System Calls
@@ -257,16 +223,16 @@
 Unix operating system calls when applied to a SCSI generic device
 using this version of the device driver.
 
-open
-----
+open(const char * filename, int flags)
+--------------------------------------
 The filename should be an 'sg' device such as
 /dev/sg[a-z]
 /dev/sg[0,1,2,...]
 or a symbolic link to one of these. [Devfs has its own sub-directory for
-sg devices.] It seems as though SCSI devices are allocated to sg minor
-numbers in the same order as they appear in 'cat /proc/scsi/scsi'.
-Sg is a "character" based Linux device driver. This means it has an
-open/close/read/write/ioctl type interface.
+sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI
+devices are allocated to sg minor numbers in the same order as they appear
+in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver.
+This means it has an open/close/read/write/ioctl type interface.
 
 Flags can be either O_RDONLY or O_RDWR or-ed with either
 O_EXCL          waits for other opens on sg device to be closed before
@@ -279,7 +245,7 @@
 The original version of sg did not allow the O_RDONLY (yielding a EACCES
 error). This version allows it for accessing ioctls (e.g. doing an sg
 device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
-allowed.
+allowed. These flags are found in <fcntl.h> .
 
 By default, sequencing is per file descriptor in this version of sg. This
 means, for example that 2 processes can independently manipulate the same
@@ -290,32 +256,38 @@
 previous version of sg supported only per device sequencing and this can
 still be selected with the SG_SET_MERGE_FD,1 ioctl().
 
-The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the
-current sg.h) on open() for "emergency" situations. If this is unavailable
-it will halve its request and try again. It gives up if PAGE_SIZE bytes
-(4096 bytes on i386) cannot be obtained so no memory is reserved. In this
-case open() will still return successfully. The actual amount of memory
-reserved can be found with the SG_GET_RESERVED_SIZE ioctl().
+The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in
+the current sg.h) on open(). The size of this reserved buffer can
+subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both
+cases these are requests subject to various dynamic constraints. The actual
+amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl().
+The reserved buffer will be used if:
+    -  it is not already in use (eg when command queuing is in use)
+    -  a write() does not call for a buffer size larger than the
+       reserved size.
 
 Returns a file descriptor if >= 0 , otherwise -1 implies an error.
 
 Error codes (value in 'errno' after -1 returned):
-ENODEV          sg not compiled into kernel or the kernel cannot find the
-                sg module (or it can't initialize itself (low memory??))
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
+EACCES          Either the user doesn't have appropriate permissions on 
+                'filename' or attempted to use both O_RDONLY and O_EXCL
 EBUSY           O_NONBLOCK set and some user of this sg device has O_EXCL
                 set while someone is already using this device
 EINTR           while waiting for an "exclusive" lock to clear, a signal
                 is received, just try again ...        
+ENODEV          sg not compiled into kernel or the kernel cannot find the
+                sg module (or it can't initialize itself (low memory??))
+ENOENT          given filename not found
 ENOMEM          An attempt to get memory to store this open's context
                 failed (this was _not_ a request to reserve DMA memory)
-EACCES          An attempt to use both O_RDONLY and O_EXCL
+ENXIO           either there is no attached device corresponding to given
+                filename or scsi sub-system is currently processing some
+                error (eg doing a device reset) or the sg driver/module
+                removed or corrupted
 
 
-write
------
+write(int sg_fd, const void * buffer, size_t count)
+---------------------------------------------------
 Even though sg is a character-based device driver it sends and receives
 packets to/from the associated scsi device. Write() is used to send a
 packet containing 2 mandatory parts and 1 optional part. The mandatory
@@ -343,32 +315,33 @@
 Returns number of bytes written if > 0 , otherwise -1 implies an error.
 
 Error codes (value in 'errno' after -1 returned):
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
 EACCES          opened with RD_ONLY flag
-EIO             incoming buffer too short. It should be at least (6 +
-                sizeof(struct sg_header))==42 bytes long
-EDOM            a) command queuing off: a packet is already queued
-                b) command queuing on: too many packets queued 
-                   (SG_MAX_QUEUE exceeded)
 EAGAIN          SCSI mid-level out of command blocks (rare), try again.
                 This is more likely to happen when queuing commands,
                 so wait a bit (eg usleep(10000) ) before trying again
+EDOM            a) command queuing off: a packet is already queued
+                b) command queuing on: too many packets queued 
+                   (SG_MAX_QUEUE exceeded)
+                c) SCSI command length given in SG_NEXT_CMD_LEN too long
+EFAULT          'buffer' for 'count' bytes is an invalid memory range
+EIO             incoming buffer too short. It should be at least (6 +
+                sizeof(struct sg_header))==42 bytes long
 ENOMEM          can't get memory for DMA. Take evasive action ...
-                (see section on memory)
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
 
 
-read
-----
+read(int sg_fd, void * buffer, size_t count)
+--------------------------------------------
 Read() is used to receive a packet containing 1 mandatory part and 1 
 optional part. The mandatory part is:
   - a control block (an instance of struct sg_header)
 The optional part is:
   - incoming data (eg if a SCSI read command was sent by earlier write() )
 The buffer given to a read() and its corresponding count should be
-sufficient to accommodate this packet to avoid truncation. Truncation has
-occurred if count < sg_header::replylen .
+sufficient to accommodate this packet to avoid truncation. Truncation occurs
+if count < sg_header::replylen .
 
 By default, read() will return the oldest packet queued up. If the 
 SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
@@ -377,7 +350,6 @@
 wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
 to read() will match the oldest packet.
 
-
 Returns number of bytes read if > 0 , otherwise -1 implies an error.
 Unfortunately the return value in the non-error case is simply the
 same as the count argument. It is not the actual number of bytes
@@ -385,25 +357,26 @@
 such an underrun indication.
 
 Error codes (value in 'errno' after -1 returned):
-ENXIO           either scsi sub-system is currently processing some error
-                (eg doing a device reset) or the sg driver/module removed
-                or corrupted
 EAGAIN          either no waiting packet or requested packet is not
                 available while O_NONBLOCK flag was set
+EFAULT          'buffer' for 'count' bytes is an invalid memory range
 EINTR           while waiting for a packet, a signal is received, just
                 try again ...        
 EIO             if the 'count' given to read() is < sizeof(struct sg_header)
                 and the 'result' element in sg_header is non-zero. Not a
                 recommended error reporting technique
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
 
 
-close
------
+close(int sg_fd)
+----------------
 Preferably a close() should be done after all issued write()s have had
 their corresponding read() calls completed. Unfortunately this is not
 always possible. The semantics of close() in Unix are to return more
 or less immediately (ie not wait on any event) so the driver needs to
-arrange to an orderly cleanup of those packets that are still "in
+arrange for an orderly cleanup of those packets that are still "in
 flight".
 
 A process that has an open file descriptor to an sg device may be aborted
@@ -411,22 +384,22 @@
 (which is called 'sg_release()' in the version 2 driver) to facilitate
 the cleanup mentioned above.
 
-A problem persists in version 2.1.8 if the sg driver is a module and is
-removed while packets are still "in flight". Hopefully this will be soon
-fixed.
+A problem persists in version 2.1.34 if the sg driver is a module and is
+removed while packets are still "in flight".
 
 Returns 0 if successful, otherwise -1 implies an error.
 
 Error codes (value in 'errno' after -1 returned):
 ENXIO           sg driver/module removed or corrupted
 
-ioctl (sg specific)
--------------------
+ioctl(int sg_fd, int command, ...)  [sg specific]
+-------------------------------------------------
 Ken Thompson (or perhaps some other Unix luminary) described ioctl() as 
 the "garbage bin of Unix". This driver compounds the situation by adding
-around 18 more commands. These commands either yield state information (10
-of them), change the driver's characteristics (8 of them) or allow direct
-communication with the common SCSI mid-level driver.
+more ...
+If a ioctl command is not recognized by sg (and the various lower levels
+that it may pass the command on to) then the error EINVAL occurs. If an
+invalid address is given (in the 3rd argument) then the error EFAULT occurs.
 
 Those commands with an appended "+" are new in version 2.
 
@@ -442,15 +415,38 @@
 SG_SET_TIMEOUT:
 Assumes 3rd argument points to an int containing the new timeout value
 for this file descriptor. The unit is a "jiffy". Packets that are
-already "in flight" will not be effected. The default value is set
-on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h).
+already "in flight" will not be affected. The default value is set
+on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is
+currently 1 minute and may not be long enough for formats.
 
 SG_EMULATED_HOST:
 Assumes 3rd argument points to an int and outputs a flag indicating
-whether the host (adapter) is connected to a real SCSI bus or is
+whether the host (adapter) is connected to a real SCSI bus or is an
 emulated one (eg ide-scsi device driver). A value of 1 means emulated
 while 0 is not.
 
+SG_SET_TRANSFORM  W:
+Third argument is ignored. Only is meaningful when SG_EMULATED host has
+yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
+an EINVAL error occurs. The default state is to _not_ transform SCSI
+commands to the corresponding ATAPI commands but pass them straight
+through as is. [Only certain classes of SCSI commands need to be
+transformed to their ATAPI equivalents.] Making this ioctl command causes
+transforms to occur thereafter. Subsequent calls to this ioctl command
+have no additional effect. Beware, this state will affect all devices
+(and hence all related sg file descriptors) associated with this ide-scsi
+"bus".
+The author of ide-scsi has pointed out that this is not the intended
+behaviour which is a 3rd argument of 0 to disable transforms and 1 to
+enable transforms. Note the 3rd argument is an 'int' not a 'int *'.
+Perhaps the intended behaviour will be implemented soon.
+
+SG_GET_TRANSFORM:
+Third argument is ignored. Only is meaningful when SG_EMULATED host has
+yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
+an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI
+to ATAPI commands (default). Returns 1 when it is transforming.
+
 SG_SET_FORCE_LOW_DMA +:
 Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
 means sg decides whether to use memory above 16 Mbyte level (on i386)
@@ -459,10 +455,10 @@
 space. 
 If 1 is given then the host adapter is overridden and only memory below
 the 16MB level is used for DMA. A requirement for this should be
-extremely rare. If the "reserve" buffer allocated on open() is not in
+extremely rare. If the "reserved" buffer allocated on open() is not in
 use then it will be de-allocated and re-allocated under the 16MB level
 (and the latter operation could fail yielding ENOMEM).
-Only the current file descriptor is effected.
+Only the current file descriptor is affected.
 
 SG_GET_LOW_DMA +:
 Assumes 3rd argument points to an int and places 0 or 1 in it. 0
@@ -472,11 +468,11 @@
 adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
 
 SG_GET_SCSI_ID +:
-Assumes 3rd argument is pointing to an object of type Sg_scsi_id and
-populates it. That structure contains ints for host_no, channel,
-scsi_id, lun and scsi_type. Most of this information is available from
-other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER)
-but tends to be awkward to collect.
+Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see
+sg.h) and populates it. That structure contains ints for host_no, 
+channel, scsi_id, lun and scsi_type. Most of this information is 
+available from other sources (eg SCSI_IOCTL_GET_IDLUN and 
+SCSI_IOCTL_GET_BUS_NUMBER) but tends to be awkward to collect.
 
 SG_SET_FORCE_PACK_ID +:
 Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
@@ -486,9 +482,9 @@
 oldest packet matching that pack_id or wait until it arrives (or yield
 EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
 given to read() in the mode will match the oldest packet.
-Only the current file descriptor is effected by this command.
+Only the current file descriptor is affected by this command.
 
-SG_GET_LOW_DMA +:
+SG_GET_PACK_ID +:
 Assumes 3rd argument points to an int and places the pack_id of the
 oldest (written) packet in it. If no packet is waiting to be read then
 yields -1.
@@ -503,30 +499,33 @@
 the adapter does support scatter gather.
 
 SG_SET_RESERVED_SIZE +W:
-This is not currently implemented. It is intended for reserving either a
-large buffer or scatter gather list that will be available until the
-current file descriptor is closed. The requested amount of memory may
-not be available so SG_GET_RESERVED_SIZE should be used after this call
-to see how much was reserved. (EBUSY error possible)
+Assumes 3rd argument is pointing to an int. That value will be used to
+request a new reserved buffer of that size. The previous reserved buffer
+is freed (if it is not in use; if it was in use -EBUSY is returned).
+A new reserved buffer is then allocated and its actual size can be found by
+calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used
+for DMA purposes by subsequent write() commands if it is not already in
+use and if the write() is not calling for a buffer size larger than that
+reserved. The reserved buffer may well be a series of kernel buffers if the
+adapter supports scatter-gather. Large buffers can be requested (eg 1 MB).
 
 SG_GET_RESERVED_SIZE +:
 Assumes 3rd argument points to an int and places the size in bytes of
-the DMA buffer reserved on open() for emergencies. If this is 0 then it
-is probably not wise to attempt on operation like burning a CD on this
-file descriptor.
+the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE
+ioctl() call on this fd.  The result can be 0 if memory is very tight. In
+this case it may not be wise to attempt something like burning a CD on
+this file descriptor.
 
 SG_SET_MERGE_FD +W:
 Assumes 3rd argument is pointing to an int. 0 (the default) causes all
 subsequent sequencing to be per file descriptor. 1 causes all subsequent
 sequencing to be per device. If this command tries to change the current
-state and the is one or more _other_ file descriptors using this sg
-device then an EBUSY error occurs. Also if this file descriptor was not
-open()ed with the O_RDWR flag then an EACCES error occurs.
-Per device sequencing was the original semantics and allowed, for example
-different processes to "share" the device, one perhaps write()ing with
-the other one read()ing. This command is supplied if anyone needs those
-semantics. Per file descriptor sequencing, perhaps with the usage of
-the O_EXCL flag, seems more sensible.
+state and there is one or more _other_ file descriptors using this sg
+device then an EBUSY error occurs. Per device sequencing was the original
+semantics and allowed, for example different processes to "share" the
+device, one perhaps write()ing with the other one read()ing. This command
+is supplied if anyone needs those semantics. Per file descriptor 
+sequencing, perhaps with the use of the O_EXCL flag, seems more sensible.
 
 SG_GET_MERGE_FD +:
 Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
@@ -538,14 +537,42 @@
 SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
 a packet while one is already queued will result in a EDOM error.
 1 turns command queuing on.
-Changing the queuing state only effects write()s done after the change.
-Only the current file descriptor is effected by this command.
+Changing the queuing state only affects write()s done after the change.
+Only the current file descriptor is affected by this command.
 
 SG_GET_COMMAND_Q +:
 Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
 that command queuing is off on this file descriptor. 1 implies command
 queuing is on.
 
+SG_SET_UNDERRUN_FLAG +:
+Assumes 3rd argument is pointing to an int. 0 (current default, set by
+SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests
+that underruns be flagged. [The only low level driver that acts on this 
+at the moment is the aic7xxx which yields a DID_ERROR error on underrun.]
+Only the current file descriptor is affected by this command (unless
+"per device" sequencing has been selected).
+
+SG_GET_UNDERRUN_FLAG +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+that underruns are not being reported. 1 implies that underruns are being
+reported (see SG_SET_UNDERRUN_FLAG for more details).
+
+SG_NEXT_CMD_LEN +:
+Assumes 3rd argument is pointing to an int. The value of the int (if > 0)
+will be used as the SCSI command length of the next SCSI command sent to
+a write() on this fd. After that write() the SCSI command length logic is
+reset to use automatic length detection (ie depending on SCSI command group
+and the 'twelve_byte' field). If the current SCSI command length maximum of
+12 is exceeded then the affected write() will yield an EDOM error.
+Giving this ioctl() a value of 0 will set automatic length detection for
+the next write(). N.B. Only the following write() on this fd is affected by
+this ioctl().
+
+SG_GET_VERSION_NUM +:
+Assumes 3rd argument points to an int. The version number is then placed
+in that int. A sg version such as 2.1.34 will yield "20134" from this ioctl.
+
 SG_SET_DEBUG +:
 Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
 off. Values > 0 cause the SCSI sense buffer to be decoded and output
@@ -556,73 +583,53 @@
 the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
 debug will appear in your console/log.
 
-ioctl (in common with sd, st + sr)
-----------------------------------
-The following ioctl()s can be called from any high-level scsi device
-driver (ie sd, st, sr + sg). Access permissions may differ a bit from
-one device to another, the access information given below is specific to
-the sg device driver.
-
-SCSI_IOCTL_GET_IDLUN:
-SCSI_IOCTL_GET_BUS_NUMBER:
-
-SCSI_IOCTL_SEND_COMMAND:  W
-If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
-the SCSI mid-level driver for processing.
-Don't know much about this one but it looks pretty powerful and
-dangerous. Some comments says it is also deprecated.
-
-<any_command_not matching_above>:  W
-If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
-the SCSI mid-level driver for processing.
-
 
-poll
-----
+poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms)
+--------------------------------------------------------------
 This is a native call in Linux 2.2 but most of its capabilities are available
 through the older select() call. Given a choice poll() should probably be
 used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
-for polling; or alternatively with asynchronous notification using the
-fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
+for polling; and optionally with asynchronous notification as well using
+the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
 Only if something drastically is wrong (eg file handle gone stale) will
 POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
 POLLIN is set when there is one or more packets waiting to be read.
-When POLLIN is set it implies that a read() will not block (or yield
+When POLLIN is set it implies that a read() will not block (nor yield
 EAGAIN in non-blocking mode) but return a packet immediately.
 POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
-(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected
+(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected
 by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
 set until the number of queued packets reaches SG_MAX_QUEUE, if the
 state is off then POLLOUT is only set when no packets are queued.
 Note that a packet can be queued after write()ing but not available to be
 read(); this typically happens when a SCSI read command is issued while
-the data is being retreaved.
+the data is being retrieved.
 Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
 it is per device.
 
 
-fcntl
------
+fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg)
+----------------------------------------------------------------
 There are several uses for this system call in association with a sg
-file descriptor. The first pseudo code shows code that is useful for
+file descriptor. The following pseudo code shows code that is useful for
 scanning the sg devices, taking care not to be caught in a wait for
 an O_EXCL lock by another process, and when the appropriate device is
-found switching to normal blocked io. A working example of this logic
-is in the sg_scan.c utility program.
+found, switching to normal blocked io. A working example of this logic
+is in the sg_scan utility program.
 
 open("/dev/sga", O_RDONLY | O_NONBLOCK)
 /* check device, EBUSY means some other process has O_EXCL lock on it */
-/* one the device you want is found then ... */
+/* when the device you want is found then ... */
 flags = fcntl(sg_fd, F_GETFL)
 fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
-/* for simple apps is is easier to use normal blocked io */
+/* since, for simple apps, it is easier to use normal blocked io */
 
 
 Some work has to be done in Linux to set up for asynchronous notification.
-This is a non-blocking mode of operation in which when the driver receives
+This is a non-blocking mode of operation in which, when the driver receives
 data back from a device so that a read() can be done, it sends a SIGPOLL
 (aka SIGIO) signal to the owning process. A working example of this logic
-is in the sg_poll.c test program.
+is in the sg_poll test program.
 
 sigemptyset(&sig_set)
 sigaddset(&sig_set, SIGPOLL)
@@ -634,3 +641,91 @@
 
 Utility and Test Programs
 =========================
+See the README file in the sg_utils<date>.tgz tarball. At the time of
+writing this was sg_utils990527.tgz .
+
+Briefly, that tarball contains the following utilities:
+sg_dd512        'dd' like program that assumes 512 byte blocks size
+sg_dd2048       'dd' like program that assumes 2048 byte blocks size
+sgq_dd512       like 'sg_dd512' but does command queuing on "if"
+sg_scan         outputs information (optionally Inquiry) on SCSI devices
+sg_rbuf         tests SCSI bus transfer speed (without physical IO)
+sg_whoami       outputs info (optionally capacity) of given SCSI device
+sginfo          outputs "mode" information about SCSI devices (it is a
+                  re-port of the scsiinfo program onto the sg interface)
+
+It also contains the following test programs:
+sg_debug        outputs sg driver state to console/log file
+sg_poll         tests asynchronous notification
+sg_inquiry      does a SCSI Inquiry command (from original HOWTO)
+sg_tst_med      checks presence of media (from original HOWTO)
+
+There are also 2 source files (sg_err.[hc]) for outputting and categorizing
+SCSI 2 errors and warnings. This code is used by most of the above
+utility and test programs.
+
+The following programs: sg_dd512, sg_dd2048, sg_scan, sg_rbuf, sg_tst_med, 
+sg_inquiry and sginfo, can be compiled either for this new sg driver _or_
+the original sg driver.
+
+
+Header files
+============
+User applications need to find the correct "sg.h" header file matching
+their kernel in order to write code using the sg device driver. This is 
+sometimes more difficult than it should be. The correct "sg.h" will usually
+be found at /usr/src/linux/include/scsi/sg.h . Another important header 
+file is "scsi.h" which will be in the same directory.
+
+Several distributions have taken their own copies of these files and placed
+them in /usr/include/scsi which is where "#include <scsi/sg.h>" would go
+looking. The directory /usr/include/scsi _should_ be a symbolic link to
+/usr/src/linux/include/scsi/ . It was is Redhat 5.1 and 5.2 but it is
+not is Redhat 6.0 . Some other distributions have the same problem. To
+solve this (as root) do the following:
+
+# cd /usr/include
+# mv scsi scsi_orig
+# ln -s ../src/linux/include/scsi scsi
+
+This doesn't seem to be a problem with /usr/include/linux (at least in
+Redhat where it is a symbolic link) so it is hard to understand why
+/usr/include/scsi is defined the way it is. The fact the
+/usr/include/linux is a symbolic link opens up the following solution
+proposed by the author of cdparanoia (Monty):
+#include <linux/../scsi/sg.h>
+
+
+Extra information in scsi-generic_long.txt
+==========================================
+This document is an abridged form of a more comprehensive document called
+scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt).
+
+The longer document contains additional sections on:
+   - memory issues
+   - ioctl()s in common with sd, st + sr
+   - distinguishing the original from the new driver
+   - SG_BIG_BUFF and friends
+   - shortcomings
+   - future directions
+   - an appendix with some SCSI 2 information in it
+
+
+Conclusion
+==========
+The SCSI generic packet device driver attempts to make as few assumptions
+as possible about the device it is connected to while giving applications
+using it as much flexibility as possible on the SCSI command level. Sg
+needs to hide the "messy" kernel related details while protecting
+the integrity of the kernel against sg "abuse". Some of these aims are
+contradictory and some compromises need to be made. For example: should
+a sg based application be able to reset a SCSI bus when that could cause
+collateral damage to a disk holding the root file system? There is no
+easy answer to this and many other related questions.
+
+If you have any suggestion about sg (or improving (the accuracy of) this
+document) please contact me.
+
+
+Douglas Gilbert
+dgilbert@interlog.com
diff -u --recursive --new-file v2.3.12/linux/Documentation/sx.txt linux/Documentation/sx.txt
--- v2.3.12/linux/Documentation/sx.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sx.txt	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,289 @@
+
+      sx.txt  -- specialix SX/SI multiport serial driver readme.
+
+
+
+      Copyright (C) 1997  Roger Wolff (R.E.Wolff@BitWizard.nl)
+
+      Specialix pays for the development and support of this driver.
+      Please DO contact support@specialix.co.uk if you require
+      support.
+
+      This driver was developed in the BitWizard linux device
+      driver service. If you require a linux device driver for your
+      product, please contact devices@BitWizard.nl for a quote.
+
+      (History)
+      There used to be an SI driver by Simon Allan. This is a complete 
+      rewrite  from scratch. Just a few lines-of-code have been snatched.
+
+      (Sources)
+      Specialix document number 6210028: SX Host Card and Download Code
+      Software Functional Specification.
+
+      (Copying)
+      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.
+      
+      (Addendum)
+      I'd appreciate it that if you have fixes, that you send them
+      to me first. 
+
+
+Introduction
+============
+
+This file contains some random information, that I like to have online
+instead of in a manual that can get lost. Ever misplace your Linux
+kernel sources?  And the manual of one of the boards in your computer?
+
+
+Theory of operation
+===================
+
+An important thing to know is that the driver itself doesn't have the
+firmware for the card. This means that you need the separate package
+"sx_firmware". For now you can get the source at
+
+	ftp://ftp.bitwizard.nl/specialix/sx_firmware_<version>.tgz
+
+The firmware load needs a "misc" device, so you'll need to enable the
+"Support for user misc device modules" in your kernel configuration.
+The misc device needs to be called "/dev/specialix_sxctl". It needs
+misc major 10, and minor number 167 (assigned by HPA). The section
+on creating device files below also creates this device. 
+
+After loading the sx.o module into your kernel, the driver will report
+the number of cards detected, but because it doesn't have any
+firmware, it will not be able to determine the number of ports. Only
+when you then run "sx_firmware" will the firmware be downloaded and
+the rest of the driver initialized. At that time the sx_firmware
+program will report the number of ports installed.
+
+In contrast with many other multi port serial cards, some of the data
+structures are only allocated when the card knows the number of ports
+that are connected. This means we won't waste memory for 120 port
+descriptor structures when you only have 8 ports. If you experience
+problems due to this, please report them: I haven't seen any.
+
+
+Interrupts
+==========
+
+A multi port serial card, would generate a horrendous amount of
+interrupts if it would interrupt the CPU for every received
+character. Even more than 10 years ago, the trick not to use
+interrupts but to poll the serial cards was invented.
+
+The SX card allow us to do this two ways. First the card limits its
+own interrupt rate to a rate that won't overwhelm the CPU. Secondly,
+we could forget about the cards interrupt completely and use the
+internal timer for this purpose.
+
+Polling the card can take up to a few percent of your CPU. Using the
+interrupts would be better if you have most of the ports idle. Using
+timer-based polling is better if your card almost always has work to
+do. You save the separate interrupt in that case.
+
+In any case, it doesn't really matter all that much. 
+
+The most common problem with interrupts is that for ISA cards in a PCI
+system the BIOS has to be told to configure that interrupt as "legacy
+ISA". Otherwise the card can pull on the interrupt line all it wants
+but the CPU won't see this.
+
+If you can't get the interrupt to work, remember that polling mode is
+more efficient (provided you actually use the card intensively).
+
+
+Allowed Configurations
+======================
+
+Some configurations are disallowed. Even though at a glance they might
+seem to work, they are known to lockup the bus between the host card
+and the device concentrators. You should respect the drivers decision
+not to support certain configurations. It's there for a reason.
+
+Warning: Seriously technical stuff ahead. Executive summary: Don't use
+SX cards except configured at a 64k boundary. Skip the next paragraph.
+
+The SX cards can theoretically be placed at a 32k boundary. So for
+instance you can put an SX card at 0xc8000-0xd7fff. This is not a
+"recommended configuration". ISA cards have to tell the bus controller
+how they like their timing. Due to timing issues they have to do this
+based on which 64k window the address falls into. This means that the
+32k window below and above the SX card have to use exactly the same
+timing as the SX card. That reportedly works for other SX cards. But
+you're still left with two useless 32k windows that should not be used
+by anybody else.
+
+
+Configuring the driver
+======================
+
+PCI cards are always detected. The driver auto-probes for ISA cards at
+some sensible addresses. Please report if the auto-probe causes trouble
+in your system, or when a card isn't detected.
+
+I'm afraid I haven't implemented "kernel command line parameters" yet.
+This means that if the default doesn't work for you, you shouldn't use
+the compiled-into-the-kernel version of the driver. Use a module
+instead.  If you convince me that you need this, I'll make it for
+you. Deal?
+
+I'm afraid that the module parameters are a bit clumsy. If you have a
+better idea, please tell me.
+
+You can specify several parameters:
+
+	sx_poll: number of jiffies between timer-based polls.
+
+		Set this to "0" to disable timer based polls. 
+                Initialization of cards without a working interrupt
+                will fail.
+
+		Set this to "1" if you want a polling driver. 
+		(on Intel: 100 polls per second). If you don't use
+                fast baud rates, you might consider a value like "5". 
+                (If you don't know how to do the math, use 1).
+
+	sx_slowpoll: Number of jiffies between timer-based polls. 
+ 		Set this to "100" to poll once a second. 
+		This should get the card out of a stall if the driver
+                ever misses an interrupt. I've never seen this happen,
+                and if it does, that's a bug. Tell me. 
+
+	sx_maxints: Number of interrupts to request from the card. 
+		The card normally limits interrupts to about 100 per
+		second to offload the host CPU. You can increase this
+		number to reduce latency on the card a little.
+		Note that if you give a very high number you can overload
+		your CPU as well as the CPU on the host card. This setting 
+		is inaccurate and not recommended for SI cards (But it 
+		works). 
+
+	sx_irqmask: The mask of allowable IRQs to use. I suggest you set 
+                this to 0 (disable IRQs all together) and use polling if 
+		the assignment of IRQs becomes problematic.
+
+	sx_debug: You can enable different sorts of debug traces with this. 
+		At "-1" all debugging traces are active. You'll get several
+		times more debugging output than you'll get characters 
+		transmitted. 
+
+
+Baud rates
+==========
+
+Theoretically new SXDCs should be capable of more than 460k
+baud. However the line drivers usually give up before that.  Also the
+CPU on the card may not be able to handle 8 channels going at full
+blast at that speed. Moreover, the buffers are not large enough to
+allow operation with 100 interrupts per second. You'll have to realize
+that the card has a 256 byte buffer, so you'll have to increase the
+number of interrupts per second if you have more than 256*100 bytes
+per second to transmit.  If you do any performance testing in this
+area, I'd be glad to hear from you...
+
+(Psst Linux users..... I think the Linux driver is more efficient than
+the driver for other OSes. If you can and want to benchmark them
+against each other, be my guest, and report your findings...... :-)
+
+
+Ports and devices
+=================
+
+Port 0 is the top connector on the module closest to the host
+card. Oh, the ports on the SXDCs and TAs are labelled from 1 to 8
+instead of from 0 to 7, as they are numbered by linux. I'm stubborn in
+this: I know for sure that I wouldn't be able to calculate which port
+is which anymore if I would change that....
+
+
+Devices:
+
+You should make the device files as follows:
+
+#!/bin/sh
+# (I recommend that you cut-and-paste this into a file and run that)
+cd /dev
+t=0
+mknod specialix_sxctl c 10 167
+while [ $t -lt 64 ]
+  do 
+  echo -n "$t "
+  mknod ttyX$t c 32 $t
+  mknod cux$t  c 33 $t
+  t=`expr $t + 1`
+done
+echo ""
+rm /etc/psdevtab
+ps > /dev/null
+
+
+This creates 64 devices. If you have more, increase the constant on
+the line with "while". The devices start at 0, as is customary on
+Linux. Specialix seems to like starting the numbering at 1. 
+
+If your system doesn't come with these devices pre-installed, bug your
+linux-vendor about this. They should have these devices
+"pre-installed" before the new millennium. The "ps" stuff at the end
+is to "tell" ps that the new devices exist.
+
+Officially the maximum number of cards per computer is 4. This driver
+however supports as many cards in one machine as you want. You'll run
+out of interrupts after a few, but you can switch to polled operation
+then. At about 256 ports (More than 8 cards), we run out of minor
+device numbers. Sorry. I suggest you buy a second computer.... (Or
+switch to RIO).
+
+------------------------------------------------------------------------
+
+
+  Fixed bugs and restrictions:
+	- Hangup processing.  
+	  -- Done.
+
+	- the write path in generic_serial (lockup / oops). 
+	  -- Done (Ugly: not the way I want it. Copied from serial.c).
+
+        - write buffer isn't flushed at close.
+	  -- Done. I still seem to loose a few chars at close. 
+	     Sorry. I think that this is a firmware issue. (-> Specialix)
+
+	- drain hardware before  changing termios
+	- Change debug on the fly. 
+	- ISA free irq -1. (no firmware loaded).
+	- adding c8000 as a probe address. Added warning. 
+	- Add a RAMtest for the RAM on the card.c
+        - Crash when opening a port "way" of the number of allowed ports. 
+          (for example opening port 60 when there are only 24 ports attached)
+	- Sometimes the use-count strays a bit. After a few hours of
+          testing the use count is sometimes "3". If you are not like
+          me and can remember what you did to get it that way, I'd
+          appreciate an Email. Possibly fixed. Tell me if anyone still
+          sees this.
+	- TAs don't work right if you don't connect all the modem control
+	  signals. SXDCs do. T225 firmware problem -> Specialix. 
+	  (Mostly fixed now, I think. Tell me if you encounter this!)
+
+  Bugs & restrictions:
+
+	- Arbitrary baud rates. Requires firmware update. (-> Specialix)
+
+	- Low latency (mostly firmware, -> Specialix)
+
+
+
diff -u --recursive --new-file v2.3.12/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt
--- v2.3.12/linux/Documentation/sysrq.txt	Wed Jun 24 14:30:07 1998
+++ linux/Documentation/sysrq.txt	Mon Aug  9 10:23:09 1999
@@ -9,8 +9,8 @@
 
 *  How do I enable the magic SysRQ key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You need to say yes to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
-configuring the kernel. This option is only available it 2.1.x or later
+You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
+configuring the kernel. This option is only available in 2.1.x or later
 kernels.
 
 *  How do I use the magic SysRQ key?
diff -u --recursive --new-file v2.3.12/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.12/linux/MAINTAINERS	Thu Jul  8 15:42:19 1999
+++ linux/MAINTAINERS	Mon Aug  9 10:23:09 1999
@@ -706,11 +706,6 @@
 W:	http://www.torque.net/sg
 S:	Maintained
 
-SCSI GENERIC
-L:	linux-scsi@vger.rutgers.edu
-M:	douglas.gilbert@rbcds.com
-S:	Maintained
-
 SCSI SUBSYSTEM
 L:	linux-scsi@vger.rutgers.edu
 S:	Unmaintained
diff -u --recursive --new-file v2.3.12/linux/Makefile linux/Makefile
--- v2.3.12/linux/Makefile	Wed Jul 28 14:47:42 1999
+++ linux/Makefile	Tue Aug  3 10:10:23 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 12
+SUBLEVEL = 13
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -110,7 +110,7 @@
 FILESYSTEMS	=fs/filesystems.a
 NETWORKS	=net/network.a
 DRIVERS		=drivers/block/block.a \
-		 drivers/char/char.a \
+		 drivers/char/char.o \
 	         drivers/parport/parport.a
 LIBS		=$(TOPDIR)/lib/lib.a
 SUBDIRS		=kernel drivers mm fs net ipc lib
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.3.12/linux/arch/alpha/kernel/alpha_ksyms.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Wed Aug  4 15:48:00 1999
@@ -105,7 +105,7 @@
 EXPORT_SYMBOL(alpha_write_fp_reg);
 
 /* In-kernel system calls.  */
-EXPORT_SYMBOL(__kernel_thread);
+EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(sys_open);
 EXPORT_SYMBOL(sys_dup);
 EXPORT_SYMBOL(sys_exit);
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.3.12/linux/arch/alpha/kernel/bios32.c	Tue Dec  1 09:33:59 1998
+++ linux/arch/alpha/kernel/bios32.c	Fri Aug  6 10:41:47 1999
@@ -26,7 +26,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
@@ -456,27 +456,23 @@
 	 * HACK: the PCI-to-EISA bridge does not seem to identify
 	 *       itself as a bridge... :-(
 	 */
-	if (dev->vendor == PCI_VENDOR_ID_INTEL &&
-	    dev->device == PCI_DEVICE_ID_INTEL_82375) {
+	if (dev->vendor == PCI_VENDOR_ID_INTEL
+	    && dev->device == PCI_DEVICE_ID_INTEL_82375) {
 		dev->class = PCI_CLASS_BRIDGE_EISA;
 		DBG_DEVS(("layout_dev: ignoring PCEB...\n"));
 		return;
 	}
 
-	if (dev->vendor == PCI_VENDOR_ID_INTEL &&
-	    dev->device == PCI_DEVICE_ID_INTEL_82378) {
+	if (dev->vendor == PCI_VENDOR_ID_INTEL
+	    && dev->device == PCI_DEVICE_ID_INTEL_82378) {
 		dev->class = PCI_CLASS_BRIDGE_ISA;
 		DBG_DEVS(("layout_dev: ignoring SIO...\n"));
 		return;
 	}
 
-	/*
-	 * We don't have code that will init the CYPRESS bridge correctly
-	 * so we do the next best thing, and depend on the previous
-	 * console code to do the right thing, and ignore it here... :-\
-	 */
-	if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
-	    dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
+	if (dev->vendor == PCI_VENDOR_ID_CONTAQ
+	    && dev->device == PCI_DEVICE_ID_CONTAQ_82C693
+	    && dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
 		DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n"));
 		return;
 	}
@@ -496,8 +492,10 @@
 					   0xffffffff);
 		pcibios_read_config_dword(bus->number, dev->devfn, off, &base);
 		if (!base) {
-			/* this base-address register is unused */
-			dev->base_address[idx] = 0;
+			/* This base-address register is unused.  */
+			dev->resource[idx].start = 0;
+			dev->resource[idx].end = 0;
+			dev->resource[idx].flags = 0;
 			continue;
 		}
 
@@ -518,6 +516,17 @@
 			base &= PCI_BASE_ADDRESS_IO_MASK;
 			mask = (~base << 1) | 0x1;
 			size = (mask & base) & 0xffffffff;
+
+			/* We don't want to disturb normal IDE functions, so
+			   we don't touch the first two I/O ports on the
+			   Cypress.  */
+			if (dev->vendor == PCI_VENDOR_ID_CONTAQ
+			    && dev->device == PCI_DEVICE_ID_CONTAQ_82C693
+			    && dev->class >> 8 == PCI_CLASS_BRIDGE_ISA
+			    && idx < 2) {
+				continue;
+			}
+
 			/*
 			 * Aligning to 0x800 rather than the minimum base of
 			 * 0x400 is an attempt to avoid having devices in 
@@ -535,7 +544,12 @@
 			new_io_reset(dev, off, orig_base);
 
 			handle = PCI_HANDLE(bus->number) | base | 1;
-			dev->base_address[idx] = handle;
+			dev->resource[idx].start
+			  = handle & PCI_BASE_ADDRESS_IO_MASK;
+			dev->resource[idx].end
+			  = dev->resource[idx].start + size - 1;
+			dev->resource[idx].flags
+			  = handle & ~PCI_BASE_ADDRESS_IO_MASK;
 
 			DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%lx (0x%x)\n",
 				  dev->device, handle, size));
@@ -615,7 +629,12 @@
 			new_io_reset(dev, off, orig_base);
 
 			handle = PCI_HANDLE(bus->number) | base;
-			dev->base_address[idx] = handle;
+			dev->resource[idx].start
+			  = handle & PCI_BASE_ADDRESS_MEM_MASK;
+			dev->resource[idx].end
+			  = dev->resource[idx].start + size - 1;
+			dev->resource[idx].flags
+			  = handle & ~PCI_BASE_ADDRESS_MEM_MASK;
 
 			/*
 			 * Currently for 64-bit cards, we simply do the usual
@@ -637,7 +656,9 @@
 					new_io_reset (dev, off+4, orig_base2);
 				}
 				/* Bypass hi reg in the loop.  */
-				dev->base_address[++idx] = 0;
+				dev->resource[++idx].start = 0;
+				dev->resource[idx].end = 0;
+				dev->resource[idx].flags = 0;
 
 				printk("bios32 WARNING: "
 				       "handling 64-bit device in "
@@ -655,8 +676,7 @@
 	if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
 	    dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
 	    dev->class >> 8 == PCI_CLASS_STORAGE_IDE ||
-	    dev->class >> 16 == PCI_BASE_CLASS_DISPLAY)
-	{
+	    dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) {
 		/*
 		 * All of these (may) have I/O scattered all around
 		 * and may not use i/o-base address registers at all.
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.3.12/linux/arch/alpha/kernel/entry.S	Mon May 10 09:55:21 1999
+++ linux/arch/alpha/kernel/entry.S	Wed Aug  4 15:48:00 1999
@@ -38,6 +38,8 @@
  */
 #define	PF_PTRACED	0x00000010
 
+#define CLONE_VM        0x00000100 
+
 /*
  * This defines the normal kernel pt-regs layout.
  *
@@ -225,21 +227,23 @@
 .end	kernel_clone
 
 /*
- * __kernel_thread(clone_flags, fn, arg)
+ * kernel_thread(fn, arg, clone_flags)
  */
 .align 3
-.globl	__kernel_thread
-.ent	__kernel_thread
-__kernel_thread:
+.globl	kernel_thread
+.ent	kernel_thread
+kernel_thread:
 	ldgp	$29,0($27)	/* we can be called from a module */
 	.frame $30, 4*8, $26
 	subq	$30,4*8,$30
 	stq	$10,16($30)
 	stq	$9,8($30)
+	lda	$0,CLONE_VM
 	stq	$26,0($30)
 	.prologue 1
-	mov	$17,$9		/* save fn */		
-	mov	$18,$10		/* save arg */
+	mov	$16,$9		/* save fn */		
+	mov	$17,$10		/* save arg */
+	or	$18,$0,$16	/* shuffle flags to front; add CLONE_VM.  */
 	bsr	$26,kernel_clone
 	bne	$20,1f		/* $20 is non-zero in child */
 	ldq	$26,0($30)
@@ -257,7 +261,7 @@
 	mov	$0,$16
 	mov	$31,$26
 	jsr	$31,sys_exit
-.end	__kernel_thread
+.end	kernel_thread
 
 /*
  * __kernel_execve(path, argv, envp, regs)
@@ -1092,7 +1096,7 @@
 	.quad sys_munlockall
 	.quad sys_sysinfo
 	.quad sys_sysctl
-	.quad sys_idle				/* 320 */
+	.quad sys_ni_syscall			/* 320 */
 	.quad sys_oldumount
 	.quad sys_swapon
 	.quad sys_times
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/machvec.h linux/arch/alpha/kernel/machvec.h
--- v2.3.12/linux/arch/alpha/kernel/machvec.h	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/machvec.h	Thu Jul 29 13:37:22 1999
@@ -8,14 +8,10 @@
 
 #include <linux/config.h>
 
-/* Whee.  TSUNAMI doesn't have an HAE.  Fix things up for the GENERIC
-   kernel by defining the HAE address to be that of the cache.  Now
-   we can read and write it as we like.  ;-)  */
+/* Whee.  Both TSUNAMI and POLARIS don't have an HAE.  Fix things up for
+   the GENERIC kernel by defining the HAE address to be that of the cache.
+   Now we can read and write it as we like.  ;-)  */
 #define TSUNAMI_HAE_ADDRESS	(&alpha_mv.hae_cache)
-
-/* Whee.  POLARIS doesn't have an HAE.  Fix things up for the GENERIC
-   kernel by defining the HAE address to be that of the cache.  Now
-   we can read and write it as we like.  ;-)  */
 #define POLARIS_HAE_ADDRESS	(&alpha_mv.hae_cache)
 
 /* Only a few systems don't define IACK_SC, handling all interrupts through
@@ -36,21 +32,24 @@
 
 #define DO_EV4_MMU							\
 	max_asn:			EV4_MAX_ASN,			\
-	mv_get_mmu_context:		ev4_get_mmu_context,		\
+	mv_switch_mm:			ev4_switch_mm,			\
+	mv_activate_mm:			ev4_activate_mm,		\
 	mv_flush_tlb_current:		ev4_flush_tlb_current,		\
 	mv_flush_tlb_other:		ev4_flush_tlb_other,		\
 	mv_flush_tlb_current_page:	ev4_flush_tlb_current_page
 
 #define DO_EV5_MMU							\
 	max_asn:			EV5_MAX_ASN,			\
-	mv_get_mmu_context:		ev5_get_mmu_context,		\
+	mv_switch_mm:			ev5_switch_mm,			\
+	mv_activate_mm:			ev5_activate_mm,		\
 	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
 	mv_flush_tlb_other:		ev5_flush_tlb_other,		\
 	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
 
 #define DO_EV6_MMU							\
 	max_asn:			EV6_MAX_ASN,			\
-	mv_get_mmu_context:		ev5_get_mmu_context,		\
+	mv_switch_mm:			ev5_switch_mm,			\
+	mv_activate_mm:			ev5_activate_mm,		\
 	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
 	mv_flush_tlb_other:		ev5_flush_tlb_other,		\
 	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.12/linux/arch/alpha/kernel/osf_sys.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Jul 29 13:37:22 1999
@@ -895,11 +895,12 @@
 			w = ieee_fpcr_to_swcr(fpcr);
 			if (!(fpcr & FPCR_UNDZ)) {
 				w &= ~IEEE_TRAP_ENABLE_UNF;
-				w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF;
+				w |= (current->thread.flags
+				      & IEEE_TRAP_ENABLE_UNF);
 			}
 		} else {
 			/* Otherwise we are forced to do everything in sw.  */
-			w = current->tss.flags & IEEE_SW_MASK;
+			w = current->thread.flags & IEEE_SW_MASK;
 		}
 
 		if (put_user(w, (unsigned long *) buffer))
@@ -917,7 +918,7 @@
  	case GSI_UACPROC:
 		if (nbytes < sizeof(unsigned int))
 			return -EINVAL;
- 		w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
+ 		w = (current->thread.flags >> UAC_SHIFT) & UAC_BITMASK;
  		if (put_user(w, (unsigned int *)buffer))
  			return -EFAULT;
  		return 1;
@@ -964,8 +965,8 @@
 		/* Update softare trap enable bits.  */
 		if (get_user(swcr, (unsigned long *)buffer))
 			return -EFAULT;
-		current->tss.flags &= ~IEEE_SW_MASK;
-		current->tss.flags |= swcr & IEEE_SW_MASK;
+		current->thread.flags &= ~IEEE_SW_MASK;
+		current->thread.flags |= swcr & IEEE_SW_MASK;
 
 		/* Update the real fpcr.  Keep UNFD off if not UNDZ.  */
 		fpcr = rdfpcr();
@@ -997,9 +998,9 @@
  				return -EFAULT;
  			switch (v) {
  			case SSIN_UACPROC:
- 				current->tss.flags &=
+ 				current->thread.flags &=
  					~(UAC_BITMASK << UAC_SHIFT);
- 				current->tss.flags |=
+ 				current->thread.flags |=
  					(w & UAC_BITMASK) << UAC_SHIFT;
  				break;
  
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.3.12/linux/arch/alpha/kernel/process.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/alpha/kernel/process.c	Tue Aug  3 08:20:45 1999
@@ -74,9 +74,8 @@
 	return 0;
 }
 
-#ifdef __SMP__
-int
-cpu_idle(void *unused)
+void
+cpu_idle(void)
 {
 	/* An endless idle loop with no priority at all.  */
 	current->priority = 0;
@@ -94,27 +93,6 @@
 		}
 	}
 }
-#endif
-
-asmlinkage int
-sys_idle(void)
-{
-	if (current->pid != 0)
-		return -EPERM;
-
-	/* An endless idle loop with no priority at all.  */
-	current->priority = 0;
-	current->counter = -100;
-	init_idle();
-
-	while (1) {
-		/* FIXME -- EV6 and LCA45 know how to power down
-		   the CPU.  */
-
-		schedule();
-		check_pgt_cache();
-	}
-}
 
 void
 generic_kill_arch (int mode, char *restart_cmd)
@@ -254,7 +232,7 @@
            that EV6 defines UNFD valid only with UNDZ, which we don't want
 	   for IEEE conformance -- so that disabled bit remains in software.  */
 
-	current->tss.flags &= ~IEEE_SW_MASK;
+	current->thread.flags &= ~IEEE_SW_MASK;
 	wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
 }
 
@@ -324,10 +302,10 @@
 #else
 	childstack->r26 = (unsigned long) ret_from_sys_call;
 #endif
-	p->tss.usp = usp;
-	p->tss.ksp = (unsigned long) childstack;
-	p->tss.pal_flags = 1;	/* set FEN, clear everything else */
-	p->tss.flags = current->tss.flags;
+	p->thread.usp = usp;
+	p->thread.ksp = (unsigned long) childstack;
+	p->thread.pal_flags = 1;	/* set FEN, clear everything else */
+	p->thread.flags = current->thread.flags;
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.3.12/linux/arch/alpha/kernel/proto.h	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/proto.h	Tue Aug  3 08:20:45 1999
@@ -162,6 +162,7 @@
 extern void rtc_init_pit(void);
 extern void generic_init_pit(void);
 extern unsigned long est_cycle_freq;
+extern struct resource timer_resource;
 
 /* smc37c93x.c */
 extern void SMC93x_Init(void);
@@ -193,7 +194,7 @@
 
 /* process.c */
 extern void generic_kill_arch (int mode, char *reboot_cmd);
-extern int cpu_idle(void *) __attribute__((noreturn));
+extern void cpu_idle(void) __attribute__((noreturn));
 
 /* ptrace.c */
 extern int ptrace_set_bpt (struct task_struct *child);
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.3.12/linux/arch/alpha/kernel/ptrace.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/ptrace.c	Thu Jul 29 13:37:22 1999
@@ -106,7 +106,7 @@
 	long *addr;
 
 	if (regno == 30) {
-		addr = &task->tss.usp;
+		addr = &task->thread.usp;
 	} else if (regno == 31 || regno > 64) {
 		zero = 0;
 		addr = &zero;
@@ -175,31 +175,31 @@
 		 * branch (emulation can be tricky for fp branches).
 		 */
 		displ = ((s32)(insn << 11)) >> 9;
-		child->tss.bpt_addr[nsaved++] = pc + 4;
+		child->thread.bpt_addr[nsaved++] = pc + 4;
 		if (displ)		/* guard against unoptimized code */
-			child->tss.bpt_addr[nsaved++] = pc + 4 + displ;
+			child->thread.bpt_addr[nsaved++] = pc + 4 + displ;
 		DBG(DBG_BPT, ("execing branch\n"));
 	} else if (op_code == 0x1a) {
 		reg_b = (insn >> 16) & 0x1f;
-		child->tss.bpt_addr[nsaved++] = get_reg(child, reg_b);
+		child->thread.bpt_addr[nsaved++] = get_reg(child, reg_b);
 		DBG(DBG_BPT, ("execing jump\n"));
 	} else {
-		child->tss.bpt_addr[nsaved++] = pc + 4;
+		child->thread.bpt_addr[nsaved++] = pc + 4;
 		DBG(DBG_BPT, ("execing normal insn\n"));
 	}
 
 	/* install breakpoints: */
 	for (i = 0; i < nsaved; ++i) {
-		res = read_int(child, child->tss.bpt_addr[i], &insn);
+		res = read_int(child, child->thread.bpt_addr[i], &insn);
 		if (res < 0)
 			return res;
-		child->tss.bpt_insn[i] = insn;
-		DBG(DBG_BPT, ("    -> next_pc=%lx\n", child->tss.bpt_addr[i]));
-		res = write_int(child, child->tss.bpt_addr[i], BREAKINST);
+		child->thread.bpt_insn[i] = insn;
+		DBG(DBG_BPT, ("    -> next_pc=%lx\n", child->thread.bpt_addr[i]));
+		res = write_int(child, child->thread.bpt_addr[i], BREAKINST);
 		if (res < 0)
 			return res;
 	}
-	child->tss.bpt_nsaved = nsaved;
+	child->thread.bpt_nsaved = nsaved;
 	return 0;
 }
 
@@ -210,9 +210,9 @@
 int
 ptrace_cancel_bpt(struct task_struct * child)
 {
-	int i, nsaved = child->tss.bpt_nsaved;
+	int i, nsaved = child->thread.bpt_nsaved;
 
-	child->tss.bpt_nsaved = 0;
+	child->thread.bpt_nsaved = 0;
 
 	if (nsaved > 2) {
 		printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
@@ -220,8 +220,8 @@
 	}
 
 	for (i = 0; i < nsaved; ++i) {
-		write_int(child, child->tss.bpt_addr[i],
-			  child->tss.bpt_insn[i]);
+		write_int(child, child->thread.bpt_addr[i],
+			  child->thread.bpt_insn[i]);
 	}
 	return (nsaved != 0);
 }
@@ -365,7 +365,7 @@
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out;
-		child->tss.bpt_nsaved = -1;	/* mark single-stepping */
+		child->thread.bpt_nsaved = -1;	/* mark single-stepping */
 		child->flags &= ~PF_TRACESYS;
 		wake_up_process(child);
 		child->exit_code = data;
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.3.12/linux/arch/alpha/kernel/smp.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/smp.c	Fri Aug  6 10:41:47 1999
@@ -75,18 +75,23 @@
 extern asmlinkage void entInt(void);
 
 
-/*
- * Process bootcommand SMP options, like "nosmp" and "maxcpus=".
- */
-void __init
-smp_setup(char *str, int *ints)
+static int __init nosmp(char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
 {
-	if (ints && ints[0] > 0)
-		max_cpus = ints[1];
-	else
-		max_cpus = 0;
+	get_option(&str, &max_cpus);
+	return 1;
 }
 
+__setup("maxcpus", maxcpus);
+
+
 /*
  * Called by both boot and secondaries to move global data into
  *  per-processor storage.
@@ -133,6 +138,10 @@
 	/* Setup the scheduler for this processor.  */
 	init_idle();
 
+	/* ??? This should be in init_idle.  */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer(cpuid);
 
@@ -153,7 +162,7 @@
 	      cpuid, current));
 
 	/* Do nothing.  */
-	cpu_idle(NULL);
+	cpu_idle();
 }
 
 
@@ -335,21 +344,21 @@
 
 	/* Initialize the CPU's HWPCB to something just good enough for
 	   us to get started.  Immediately after starting, we'll swpctx
-	   to the target idle task's tss.  Reuse the stack in the mean
+	   to the target idle task's ptb.  Reuse the stack in the mean
 	   time.  Precalculate the target PCBB.  */
 	hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16;
 	hwpcb->usp = 0;
-	hwpcb->ptbr = idle->tss.ptbr;
+	hwpcb->ptbr = idle->thread.ptbr;
 	hwpcb->pcc = 0;
 	hwpcb->asn = 0;
-	hwpcb->unique = virt_to_phys(&idle->tss);
-	hwpcb->flags = idle->tss.pal_flags;
+	hwpcb->unique = virt_to_phys(&idle->thread);
+	hwpcb->flags = idle->thread.pal_flags;
 	hwpcb->res1 = hwpcb->res2 = 0;
 
 	DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n",
 	      hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique));
 	DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
-	      cpuid, idle->state, idle->tss.pal_flags));
+	      cpuid, idle->state, idle->thread.pal_flags));
 
 	/* Setup HWRPB fields that SRM uses to activate secondary CPU */
 	hwrpb->CPU_restart = __smp_callin;
@@ -399,10 +408,13 @@
 	   HWRPB.CPU_restart says to start.  But this gets all the other
 	   task-y sort of data structures set up like we wish.  */
 	kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM);
-	idle = task[cpunum];
-	if (!idle)
-		panic("No idle process for CPU %d", cpuid);
-	idle->processor = cpuid;
+
+        idle = init_task.prev_task;
+        if (!idle)
+                panic("No idle process for CPU %d", cpunum);
+        del_from_runqueue(idle);
+        init_tasks[cpunum] = idle;
+        idle->processor = cpuid;
 
 	/* Schedule the first task manually.  */
 	/* ??? Ingo, what is this?  */
@@ -512,6 +524,10 @@
 
 	init_idle();
 
+	/* ??? This should be in init_idle.  */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+
 	/* Nothing to do on a UP box, or when told not to.  */
 	if (smp_num_probed == 1 || max_cpus == 0) {
 	        printk(KERN_INFO "SMP mode deactivated.\n");
@@ -859,16 +875,16 @@
 ipi_flush_tlb_mm(void *x)
 {
 	struct mm_struct *mm = (struct mm_struct *) x;
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		flush_tlb_current(mm);
 }
 
 void
 flush_tlb_mm(struct mm_struct *mm)
 {
-	if (mm == current->mm) {
+	if (mm == current->active_mm) {
 		flush_tlb_current(mm);
-		if (atomic_read(&mm->count) == 1)
+		if (atomic_read(&mm->mm_users) <= 1)
 			return;
 	} else
 		flush_tlb_other(mm);
@@ -888,7 +904,7 @@
 ipi_flush_tlb_page(void *x)
 {
 	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
-	if (data->mm == current->mm)
+	if (data->mm == current->active_mm)
 		flush_tlb_current_page(data->mm, data->vma, data->addr);
 }
 
@@ -898,9 +914,9 @@
 	struct flush_tlb_page_struct data;
 	struct mm_struct *mm = vma->vm_mm;
 
-	if (mm == current->mm) {
+	if (mm == current->active_mm) {
 		flush_tlb_current_page(mm, vma, addr);
-		if (atomic_read(&mm->count) == 1)
+		if (atomic_read(&mm->mm_users) <= 1)
 			return;
 	} else
 		flush_tlb_other(mm);
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c
--- v2.3.12/linux/arch/alpha/kernel/sys_ruffian.c	Sat Jan  9 19:08:27 1999
+++ linux/arch/alpha/kernel/sys_ruffian.c	Tue Aug  3 08:20:45 1999
@@ -220,19 +220,25 @@
 {
 	/* FIXME: What do we do with ruffian_get_bank_size above?  */
 
+#if 1
+	pyxis_init_arch(mem_start, mem_end);
+#else
 	pyxis_enable_errors();
 	if (!pyxis_srm_window_setup()) {
 		printk("ruffian_init_arch: Skipping window register rewrites."
 		       "\n... Trust DeskStation firmware!\n");
 	}
 	pyxis_finish_init_arch();
+#endif
 }
 
 static void
 ruffian_init_pit (void)
 {
 	/* Ruffian depends on the system timer established in MILO! */
-	request_region(0x70, 0x10, "timer");
+        timer_resource.start = 0x70;
+        timer_resource.end = 0x70 + 0x10;
+        request_resource(&ioport_resource, &timer_resource);
 
 	outb(0xb6, 0x43);       /* pit counter 2: speaker */
 	outb(0x31, 0x42);
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.3.12/linux/arch/alpha/kernel/time.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/time.c	Thu Jul 29 13:37:22 1999
@@ -47,6 +47,12 @@
 
 static int set_rtc_mmss(unsigned long);
 
+#ifdef CONFIG_RTC
+struct resource timer_resource = { "pit", 0x40, 0x40+0x20 };
+#else
+struct resource timer_resource = { "rtc", 0, 0 };
+#endif
+
 
 /*
  * Shift amount by which scaled_ticks_per_cycle is scaled.  Shifting
@@ -184,7 +190,7 @@
 	CMOS_WRITE(control, RTC_CONTROL);
 	(void) CMOS_READ(RTC_INTR_FLAGS);
 
-	request_region(0x40, 0x20, "timer"); /* reserve pit */
+	request_resource(&ioport_resource, &timer_resource);
 
 	/* Setup interval timer.  */
 	outb(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
@@ -219,7 +225,9 @@
 	}
 	(void) CMOS_READ(RTC_INTR_FLAGS);
 
-	request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */
+	timer_resource.start = RTC_PORT(0);
+	timer_resource.end = RTC_PORT(0) + 0x10;
+	request_resource(&ioport_resource, &timer_resource);
 
 	outb(0x36, 0x43);	/* pit counter 0: system timer */
 	outb(0x00, 0x40);
@@ -323,7 +331,7 @@
 
 	/* setup timer */ 
 	irq_handler = timer_interrupt;
-	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
+	if (request_irq(TIMER_IRQ, irq_handler, 0, timer_resource.name, NULL))
 		panic("Could not allocate timer IRQ!");
 }
 
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.3.12/linux/arch/alpha/kernel/traps.c	Fri May 14 12:41:23 1999
+++ linux/arch/alpha/kernel/traps.c	Thu Jul 29 13:37:22 1999
@@ -103,12 +103,12 @@
 	dik_show_code((unsigned int *)regs->pc);
 	dik_show_trace((unsigned long *)(regs+1));
 
-	if (current->tss.flags & (1UL << 63)) {
+	if (current->thread.flags & (1UL << 63)) {
 		printk("die_if_kernel recursion detected.\n");
 		sti();
 		while (1);
 	}
-	current->tss.flags |= (1UL << 63);
+	current->thread.flags |= (1UL << 63);
 	do_exit(SIGSEGV);
 }
 
@@ -154,7 +154,9 @@
 	 unsigned long a2, unsigned long a3, unsigned long a4,
 	 unsigned long a5, struct pt_regs regs)
 {
-	die_if_kernel("Instruction fault", &regs, type, 0);
+	die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
+		      &regs, type, 0);
+
 	switch (type) {
 	      case 0: /* breakpoint */
 		if (ptrace_cancel_bpt(current)) {
@@ -494,12 +496,12 @@
 	dik_show_code((unsigned int *)pc);
 	dik_show_trace((unsigned long *)(&regs+1));
 
-	if (current->tss.flags & (1UL << 63)) {
+	if (current->thread.flags & (1UL << 63)) {
 		printk("die_if_kernel recursion detected.\n");
 		sti();
 		while (1);
 	}
-	current->tss.flags |= (1UL << 63);
+	current->thread.flags |= (1UL << 63);
 	do_exit(SIGSEGV);
 }
 
@@ -601,7 +603,7 @@
 	/* Check the UAC bits to decide what the user wants us to do
 	   with the unaliged access.  */
 
-	uac_bits = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
+	uac_bits = (current->thread.flags >> UAC_SHIFT) & UAC_BITMASK;
 	if (!(uac_bits & UAC_NOPRINT)) {
 		if (cnt >= 5 && jiffies - last_time > 5*HZ) {
 			cnt = 0;
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile
--- v2.3.12/linux/arch/alpha/lib/Makefile	Sat Jan 16 17:02:51 1999
+++ linux/arch/alpha/lib/Makefile	Fri Aug  6 10:41:47 1999
@@ -5,7 +5,7 @@
 OBJS  = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \
 	checksum.o csum_partial_copy.o strlen.o \
 	strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \
-	strchr.o strrchr.o \
+	strchr.o strrchr.o memchr.o \
 	copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \
 	csum_ipv6_magic.o strcasecmp.o semaphore.o \
 	srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/lib/memchr.S linux/arch/alpha/lib/memchr.S
--- v2.3.12/linux/arch/alpha/lib/memchr.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/lib/memchr.S	Fri Aug  6 10:41:47 1999
@@ -0,0 +1,164 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by David Mosberger (davidm@cs.arizona.edu).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Finds characters in a memory area.  Optimized for the Alpha:
+
+      - memory accessed as aligned quadwords only
+      - uses cmpbge to compare 8 bytes in parallel
+      - does binary search to find 0 byte in last
+        quadword (HAKMEM needed 12 instructions to
+        do this instead of the 9 instructions that
+        binary search needs).
+
+For correctness consider that:
+
+      - only minimum number of quadwords may be accessed
+      - the third argument is an unsigned long
+*/
+
+        .set noreorder
+        .set noat
+
+	.globl memchr
+	.ent memchr
+memchr:
+	.frame $30,0,$26,0
+	.prologue 0
+
+	# Hack -- if someone passes in (size_t)-1, hoping to just
+	# search til the end of the address space, we will overflow
+	# below when we find the address of the last byte.  Given
+	# that we will never have a 56-bit address space, cropping
+	# the length is the easiest way to avoid trouble.
+	zap	$18, 0x80, $5	#-e0	:
+
+	beq	$18, $not_found	# .. e1 :
+        ldq_u   $1, 0($16)	# e1	: load first quadword
+	insbl	$17, 1, $2	# .. e0 : $2 = 000000000000ch00
+	and	$17, 0xff, $17	#-e0    : $17 = 00000000000000ch
+	cmpult	$18, 9, $4	# .. e1 :
+	or	$2, $17, $17	# e0    : $17 = 000000000000chch
+        lda     $3, -1($31)	# .. e1 :
+	sll	$17, 16, $2	#-e0    : $2 = 00000000chch0000
+	addq	$16, $5, $5	# .. e1 :
+	or	$2, $17, $17	# e1    : $17 = 00000000chchchch
+	unop			#	:
+	sll	$17, 32, $2	#-e0    : $2 = chchchch00000000
+	or	$2, $17, $17	# e1	: $17 = chchchchchchchch
+	extql	$1, $16, $7	# e0    : 
+	beq	$4, $first_quad	# .. e1 :
+
+	ldq_u	$6, -1($5)	#-e1	: eight or less bytes to search
+	extqh	$6, $16, $6	# .. e0 :
+	mov	$16, $0		# e0	:
+	or	$7, $6, $1	# .. e1 : $1 = quadword starting at $16
+
+	# Deal with the case where at most 8 bytes remain to be searched
+	# in $1.  E.g.:
+	#	$18 = 6
+	#	$1 = ????c6c5c4c3c2c1
+$last_quad:
+	negq	$18, $6		#-e0	:
+        xor	$17, $1, $1	# .. e1 :
+	srl	$3, $6, $6	# e0    : $6 = mask of $18 bits set
+        cmpbge  $31, $1, $2	# .. e1 :
+	and	$2, $6, $2	#-e0	:
+        beq     $2, $not_found	# .. e1 :
+
+$found_it:
+	# Now, determine which byte matched:
+        negq    $2, $3		# e0	:
+        and     $2, $3, $2	# e1	:
+
+        and     $2, 0x0f, $1	#-e0	:
+        addq    $0, 4, $3	# .. e1 :
+        cmoveq  $1, $3, $0	# e0	:
+
+        addq    $0, 2, $3	# .. e1 :
+        and     $2, 0x33, $1	#-e0	:
+        cmoveq  $1, $3, $0	# .. e1 :
+
+        and     $2, 0x55, $1	# e0	:
+        addq    $0, 1, $3	# .. e1 :
+        cmoveq  $1, $3, $0	#-e0	:
+
+$done:	ret			# .. e1 :
+
+	# Deal with the case where $18 > 8 bytes remain to be
+	# searched.  $16 may not be aligned.
+	.align 4
+$first_quad:
+	andnot	$16, 0x7, $0	#-e1	:
+        insqh   $3, $16, $2	# .. e0	: $2 = 0000ffffffffffff ($16<0:2> ff)
+        xor	$1, $17, $1	# e0	:
+	or	$1, $2, $1	# e1	: $1 = ====ffffffffffff
+        cmpbge  $31, $1, $2	#-e0	:
+        bne     $2, $found_it	# .. e1 :
+
+	# At least one byte left to process.
+
+	ldq	$1, 8($0)	# e0	:
+	subq	$5, 1, $18	# .. e1 :
+	addq	$0, 8, $0	#-e0	:
+
+	# Make $18 point to last quad to be accessed (the
+	# last quad may or may not be partial).
+
+	andnot	$18, 0x7, $18	# .. e1 :
+	cmpult	$0, $18, $2	# e0	:
+	beq	$2, $final	# .. e1 :
+
+	# At least two quads remain to be accessed.
+
+	subq	$18, $0, $4	#-e0	: $4 <- nr quads to be processed
+	and	$4, 8, $4	# e1	: odd number of quads?
+	bne	$4, $odd_quad_count # e1 :
+
+	# At least three quads remain to be accessed
+
+	mov	$1, $4		# e0	: move prefetched value to correct reg
+
+	.align	4
+$unrolled_loop:
+	ldq	$1, 8($0)	#-e0	: prefetch $1
+	xor	$17, $4, $2	# .. e1 :
+	cmpbge	$31, $2, $2	# e0	:
+	bne	$2, $found_it	# .. e1 :
+
+	addq	$0, 8, $0	#-e0	:
+$odd_quad_count:
+	xor	$17, $1, $2	# .. e1 :
+	ldq	$4, 8($0)	# e0	: prefetch $4
+	cmpbge	$31, $2, $2	# .. e1 :
+	addq	$0, 8, $6	#-e0	:
+	bne	$2, $found_it	# .. e1	:
+
+	cmpult	$6, $18, $6	# e0	:
+	addq	$0, 8, $0	# .. e1 :
+	bne	$6, $unrolled_loop #-e1 :
+
+	mov	$4, $1		# e0	: move prefetched value into $1
+$final:	subq	$5, $0, $18	# .. e1	: $18 <- number of bytes left to do
+	bne	$18, $last_quad	# e1	:
+
+$not_found:
+	mov	$31, $0		#-e0	:
+	ret			# .. e1 :
+
+        .end memchr
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c
--- v2.3.12/linux/arch/alpha/math-emu/fp-emul.c	Mon May 10 09:55:21 1999
+++ linux/arch/alpha/math-emu/fp-emul.c	Thu Jul 29 13:37:22 1999
@@ -107,7 +107,7 @@
 alpha_fp_emul (unsigned long pc)
 {
 	unsigned long op_fun, fa, fb, fc, func, mode;
-	unsigned long fpcw = current->tss.flags;
+	unsigned long fpcw = current->thread.flags;
 	unsigned long va, vb, vc, res, fpcr;
 	__u32 insn;
 
@@ -255,7 +255,7 @@
 	 */
 	if (res) {
 		/* Record exceptions in software control word.  */
-		current->tss.flags = fpcw |= res >> 35;
+		current->thread.flags = fpcw |= res >> 35;
 
 		/* Update hardware control register */
 		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.3.12/linux/arch/alpha/mm/fault.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/mm/fault.c	Fri Aug  6 10:41:47 1999
@@ -37,12 +37,9 @@
 unsigned long last_asn = ASN_FIRST_VERSION;
 #endif
 
-void
-get_new_mmu_context(struct task_struct *p, struct mm_struct *mm)
+void ev5_flush_tlb_current(struct mm_struct *mm)
 {
-	unsigned long new = __get_new_mmu_context(p, mm);
-	mm->context = new;
-	p->tss.asn = new & HARDWARE_ASN_MASK;
+	ev5_activate_mm(NULL, mm, smp_processor_id());
 }
 
 
@@ -78,7 +75,8 @@
 {
 	struct vm_area_struct * vma;
 	struct mm_struct *mm = current->mm;
-	unsigned fixup;
+	unsigned int fixup;
+	int fault;
 
 	/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
 	   (or is suppressed by the PALcode).  Support that for older CPUs
@@ -94,8 +92,12 @@
 		}
 	}
 
+	/* If we're in an interrupt context, or have no user context,
+	   we must not take the fault.  */
+	if (!mm || in_interrupt())
+		goto no_context;
+
 	down(&mm->mmap_sem);
-	lock_kernel();
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -121,9 +123,21 @@
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	}
-	handle_mm_fault(current, vma, address, cause > 0);
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+	fault = handle_mm_fault(current, vma, address, cause > 0);
 	up(&mm->mmap_sem);
-	goto out;
+
+	if (fault < 0)
+		goto out_of_memory;
+	if (fault == 0)
+		goto do_sigbus;
+
+	return;
 
 /*
  * Something tried to access memory that isn't in our memory map..
@@ -134,9 +148,10 @@
 
 	if (user_mode(regs)) {
 		force_sig(SIGSEGV, current);
-		goto out;
+		return;
 	}
 
+no_context:
 	/* Are we prepared to handle this fault as an exception?  */
 	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		unsigned long newpc;
@@ -144,7 +159,7 @@
 		printk("%s: Exception at [<%lx>] (%lx)\n",
 		       current->comm, regs->pc, newpc);
 		regs->pc = newpc;
-		goto out;
+		return;
 	}
 
 /*
@@ -155,7 +170,25 @@
 	       "virtual address %016lx\n", address);
 	die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
 	do_exit(SIGKILL);
- out:
-	unlock_kernel();
-}
 
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+	printk(KERN_ALERT "VM: killing process %s(%d)\n",
+	       current->comm, current->pid);
+	if (!user_mode(regs))
+		goto no_context;
+	do_exit(SIGKILL);
+
+do_sigbus:
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	force_sig(SIGBUS, current);
+	if (!user_mode(regs))
+		goto no_context;
+	return;
+}
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.3.12/linux/arch/alpha/mm/init.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/mm/init.c	Thu Jul 29 13:37:22 1999
@@ -178,7 +178,7 @@
 {
 	register unsigned long sp __asm__("$30");
 	pcb->ksp = sp;
-	return __reload_tss(pcb);
+	return __reload_thread(pcb);
 }
 
 /*
@@ -233,10 +233,10 @@
 	}
 
 	/* Also set up the real kernel PCB while we're at it.  */
-	init_task.tss.ptbr = newptbr;
-	init_task.tss.pal_flags = 1;	/* set FEN, clear everything else */
-	init_task.tss.flags = 0;
-	original_pcb_ptr = load_PCB(&init_task.tss);
+	init_task.thread.ptbr = newptbr;
+	init_task.thread.pal_flags = 1;	/* set FEN, clear everything else */
+	init_task.thread.flags = 0;
+	original_pcb_ptr = load_PCB(&init_task.thread);
 	tbia();
 
 	/* Save off the contents of the original PCB so that we can
diff -u --recursive --new-file v2.3.12/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds
--- v2.3.12/linux/arch/alpha/vmlinux.lds	Tue May 13 22:41:00 1997
+++ linux/arch/alpha/vmlinux.lds	Wed Aug  4 15:48:00 1999
@@ -2,11 +2,11 @@
 ENTRY(__start)
 SECTIONS
 {
-   . = 0xfffffc0000310000;
-   _text = .;
-   .text : { *(.text) }
-   .text2 : { *(.text2) }
-   _etext = .;
+  . = 0xfffffc0000310000;
+  _text = .;
+  .text : { *(.text) }
+  .text2 : { *(.text2) }
+  _etext = .;
 
   /* Exception table */
   . = ALIGN(16);
@@ -26,6 +26,17 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+
+  . = ALIGN(8);
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+
   . = ALIGN(2*8192);	/* Align double page for init_task_union */
   __init_end = .;
 
@@ -34,6 +45,7 @@
 
   /* Global data */
   _data = .;
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
   .rodata : { *(.rodata) }
   .data : { *(.data) CONSTRUCTORS }
   .got : { *(.got) }
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S
--- v2.3.12/linux/arch/arm/kernel/entry-armo.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/entry-armo.S	Mon Aug  2 10:19:52 1999
@@ -650,6 +650,15 @@
 		b	SYMBOL_NAME(do_DataAbort)
 
 /*
+ * Register switch for older 26-bit only ARMs
+ */
+ENTRY(__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
+		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
+
+/*
  *=============================================================================
  *		Low-level interface code
  *-----------------------------------------------------------------------------
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.3.12/linux/arch/arm/kernel/entry-armv.S	Wed Jul 21 15:46:48 1999
+++ linux/arch/arm/kernel/entry-armv.S	Mon Aug  2 10:19:52 1999
@@ -455,7 +455,7 @@
 		mov	r0, r2
 		ldr	r2, .LCprocfns
 		mov	lr, pc
-		ldr	pc, [r2, #8]			@ call processor specific code
+		ldr	pc, [r2, #4]			@ call processor specific code
 		mov	r3, sp
 		bl	SYMBOL_NAME(do_DataAbort)
 		ldr	r0, [sp, #S_PSR]
@@ -542,7 +542,7 @@
 		msr	cpsr, r2
 		ldr	r2, .LCprocfns
 		mov	lr, pc
-		ldr	pc, [r2, #8]			@ call processor specific code
+		ldr	pc, [r2, #4]			@ call processor specific code
 		mov	r3, sp
 		adrsvc	al, lr, ret_from_sys_call
 		b	SYMBOL_NAME(do_DataAbort)
@@ -654,6 +654,23 @@
 		add	sp, sp, #S_FRAME_SIZE
 		movs	pc, lr
 #endif
+
+/*
+ * Register switch for ARMv3 and ARMv4 processors
+ * r0 = previous, r1 = next, return previous.
+ * previous and next are guaranteed not to be the same.
+ */
+ENTRY(__switch_to)
+		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
+		mrs	ip, cpsr
+		stmfd	sp!, {ip}			@ Save cpsr_SVC
+		ldr	r2, [r1, #TSS_DOMAIN]
+		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
+		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
+		mcr	p15, 0, r2, c3, c0		@ Set domain register
+		ldmfd	sp!, {ip}
+		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
+		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
 
 		.section ".text.init",#alloc,#execinstr
 /*
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c
--- v2.3.12/linux/arch/arm/kernel/fiq.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/fiq.c	Mon Aug  2 10:19:52 1999
@@ -53,15 +53,12 @@
 #ifdef CONFIG_CPU_32
 static inline void unprotect_page_0(void)
 {
-	__asm__ __volatile__("mcr	p15, 0, %0, c3, c0" :
-			: "r" (DOMAIN_USER_MANAGER |
-			       DOMAIN_KERNEL_CLIENT |
-			       DOMAIN_IO_CLIENT));
+	modify_domain(DOMAIN_USER, DOMAIN_MANAGER);
 }
 
 static inline void protect_page_0(void)
 {
-	set_fs(get_fs());
+	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 }
 #else
 
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.3.12/linux/arch/arm/kernel/process.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/arm/kernel/process.c	Mon Aug  2 10:19:52 1999
@@ -207,9 +207,7 @@
 
 void flush_thread(void)
 {
-	int i;
-
-	memset(&current->tss.debug, 0, sizeof(current->tss.debug));
+	memset(&current->thread.debug, 0, sizeof(current->thread.debug));
 	current->used_math = 0;
 	current->flags &= ~PF_USEDFPU;
 }
@@ -231,7 +229,7 @@
 
 	save = ((struct context_save_struct *)(childregs)) - 1;
 	init_thread_css(save);
-	p->tss.save = save;
+	p->thread.save = save;
 
 	return 0;
 }
@@ -244,7 +242,7 @@
 	int fpvalid = 0;
 
 	if (current->used_math)
-		memcpy (fp, &current->tss.fpstate.soft, sizeof (fp));
+		memcpy (fp, &current->thread.fpstate.soft, sizeof (fp));
 
 	return fpvalid;
 }
@@ -262,11 +260,11 @@
 	dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	dump->u_ssize = 0;
 
-	dump->u_debugreg[0] = current->tss.debug.bp[0].address;
-	dump->u_debugreg[1] = current->tss.debug.bp[1].address;
-	dump->u_debugreg[2] = current->tss.debug.bp[0].insn;
-	dump->u_debugreg[3] = current->tss.debug.bp[1].insn;
-	dump->u_debugreg[4] = current->tss.debug.nsaved;
+	dump->u_debugreg[0] = current->thread.debug.bp[0].address;
+	dump->u_debugreg[1] = current->thread.debug.bp[1].address;
+	dump->u_debugreg[2] = current->thread.debug.bp[0].insn;
+	dump->u_debugreg[3] = current->thread.debug.bp[1].insn;
+	dump->u_debugreg[4] = current->thread.debug.nsaved;
 
 	if (dump->start_stack < 0x04000000)
 		dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- v2.3.12/linux/arch/arm/kernel/ptrace.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/arm/kernel/ptrace.c	Mon Aug  2 10:19:52 1999
@@ -28,7 +28,7 @@
 
 /*
  * this routine will get a word off of the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
+ * the offset is how far from the base addr as stored in the THREAD.
  * this routine assumes that all the privileged stacks are in our
  * data space.
  */
@@ -43,7 +43,7 @@
 
 /*
  * this routine will put a word on the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
+ * the offset is how far from the base addr as stored in the THREAD.
  * this routine assumes that all the privileged stacks are in our
  * data space.
  */
@@ -334,7 +334,7 @@
 
 int ptrace_set_bpt (struct task_struct *child)
 {
-	struct debug_info *dbg = &child->tss.debug;
+	struct debug_info *dbg = &child->thread.debug;
 	unsigned long insn, pc, alt;
 	int res;
 
@@ -363,7 +363,7 @@
  */
 int ptrace_cancel_bpt (struct task_struct *child)
 {
-	struct debug_info *dbg = &child->tss.debug;
+	struct debug_info *dbg = &child->thread.debug;
 	unsigned long tmp;
 	int i, nsaved = dbg->nsaved;
 
@@ -514,7 +514,7 @@
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
 				goto out;
-			child->tss.debug.nsaved = -1;
+			child->thread.debug.nsaved = -1;
 			child->flags &= ~PF_TRACESYS;
 			wake_up_process(child);
 			child->exit_code = data;
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
--- v2.3.12/linux/arch/arm/kernel/signal.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/arm/kernel/signal.c	Mon Aug  2 10:19:52 1999
@@ -273,8 +273,8 @@
 	err |= __put_user (regs->ARM_cpsr, &sc->arm_cpsr);
 #endif
 
-	err |= __put_user (current->tss.trap_no, &sc->trap_no);
-	err |= __put_user (current->tss.error_code, &sc->error_code);
+	err |= __put_user (current->thread.trap_no, &sc->trap_no);
+	err |= __put_user (current->thread.error_code, &sc->error_code);
 	err |= __put_user (mask, &sc->oldmask);
 
 	return err;
diff -u --recursive --new-file v2.3.12/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.3.12/linux/arch/arm/kernel/traps.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/arm/kernel/traps.c	Mon Aug  2 10:19:52 1999
@@ -198,8 +198,8 @@
 {
 	printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr, 
 		__builtin_return_address(0));
-	current->tss.error_code = 0;
-	current->tss.trap_no = 11;
+	current->thread.error_code = 0;
+	current->thread.trap_no = 11;
 	force_sig(SIGBUS, current);
 /*	die_if_kernel("Oops - bad user access alignment", regs, mode);*/
 }
@@ -210,8 +210,8 @@
 	printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
 		current->comm, current->pid, instruction_pointer(regs));
 #endif
-	current->tss.error_code = 0;
-	current->tss.trap_no = 6;
+	current->thread.error_code = 0;
+	current->thread.trap_no = 6;
 	force_sig(SIGILL, current);
 	die_if_kernel("Oops - undefined instruction", regs, mode);
 }
@@ -222,8 +222,8 @@
 	printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
 		current->comm, current->pid, instruction_pointer(regs));
 #endif
-	current->tss.error_code = 0;
-	current->tss.trap_no = 11;
+	current->thread.error_code = 0;
+	current->thread.trap_no = 11;
 	force_sig(SIGBUS, current);
 	die_if_kernel("Oops - address exception", regs, mode);
 }
@@ -367,7 +367,7 @@
 	{
 		pgd_t *pgd;
 
-		printk ("current->tss.memmap = %08lX\n", current->tss.memmap);
+		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.12/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c
--- v2.3.12/linux/arch/arm/lib/getconsdata.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/lib/getconsdata.c	Mon Aug  2 10:19:52 1999
@@ -32,11 +32,13 @@
 unsigned long MM = OFF_TSK(mm);
 unsigned long PGD = OFF_MM(pgd);
 
-unsigned long TSS_MEMMAP = OFF_TSK(tss.memmap);
-unsigned long TSS_SAVE = OFF_TSK(tss.save);
-unsigned long TSS_FPESAVE = OFF_TSK(tss.fpstate.soft.save);
+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_MEMCMAP = OFF_TSK(tss.memcmap);
+unsigned long TSS_MEMMAP = OFF_TSK(thread.memmap);
+unsigned long TSS_MEMCMAP = OFF_TSK(thread.memcmap);
+#elif defined(CONFIG_CPU_32)
+unsigned long TSS_DOMAIN = OFF_TSK(thread.domain);
 #endif
 
 #ifdef _PAGE_PRESENT
diff -u --recursive --new-file v2.3.12/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.3.12/linux/arch/arm/mm/fault-armv.c	Sat May  8 11:06:56 1999
+++ linux/arch/arm/mm/fault-armv.c	Mon Aug  2 10:19:52 1999
@@ -32,13 +32,14 @@
 
 #include "fault-common.c"
 
+/*
+ * need to get a 16k page for level 1
+ */
 pgd_t *get_pgd_slow(void)
 {
-	/*
-	 * need to get a 16k page for level 1
-	 */
 	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);
@@ -46,8 +47,32 @@
 		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)
diff -u --recursive --new-file v2.3.12/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.3.12/linux/arch/arm/mm/fault-common.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/arm/mm/fault-common.c	Mon Aug  2 10:19:52 1999
@@ -85,7 +85,10 @@
 
 	printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
 		reason, addr);
-	printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
+	if (!mm)
+		mm = &init_mm;
+
+	printk(KERN_ALERT "pgd = %p\n", mm->pgd);
 	show_pte(mm, addr);
 	die("Oops", regs, mode);
 
@@ -151,8 +154,8 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (mode & FAULT_CODE_USER) {
-		tsk->tss.error_code = mode;
-		tsk->tss.trap_no = 14;
+		tsk->thread.error_code = mode;
+		tsk->thread.trap_no = 14;
 #ifdef CONFIG_DEBUG_USER
 		printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
 			tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
@@ -186,8 +189,8 @@
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	tsk->tss.error_code = mode;
-	tsk->tss.trap_no = 14;
+	tsk->thread.error_code = mode;
+	tsk->thread.trap_no = 14;
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
diff -u --recursive --new-file v2.3.12/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c
--- v2.3.12/linux/arch/arm/mm/mm-rpc.c	Thu Dec 17 09:05:42 1998
+++ linux/arch/arm/mm/mm-rpc.c	Mon Aug  2 10:19:52 1999
@@ -85,8 +85,6 @@
 
 	rambank[FIRST_VRAM_BANK].phys_offset = 0xd6000000;
 	rambank[FIRST_VRAM_BANK].virt_addr   = 0xd8000000;
-
-	current->tss.memmap = __virt_to_phys((unsigned long)swapper_pg_dir);
 }
 
 #define MAPPING \
diff -u --recursive --new-file v2.3.12/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.3.12/linux/arch/arm/mm/proc-arm6,7.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/mm/proc-arm6,7.S	Mon Aug  2 10:19:52 1999
@@ -53,41 +53,6 @@
 		mov	pc, lr
 
 /*
- * Function: arm6_7_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.
- */
-_arm6_7_switch_to:
-		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
-		mrs	ip, cpsr
-		stmfd	sp!, {ip}			@ Save cpsr_SVC
-		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
-		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r2, [r1, #TSK_ADDR_LIMIT]
-		ldr	r3, [r1, #TSS_MEMMAP]		@ Page table pointer
-		teq	r2, #0
-		moveq	r2, #DOM_KERNELDOMAIN
-		movne	r2, #DOM_USERDOMAIN
-		mcr	p15, 0, r2, c3, c0		@ Set domain reg
-		mov	r1, #0
-		mcr	p15, 0, r1, c7, c0, 0		@ flush cache
-		mcr	p15, 0, r3, c2, c0, 0		@ update page table ptr
-		mcr	p15, 0, r1, c5, c0, 0		@ flush TLBs
-		ldmfd	sp!, {ip}
-		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
-		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
-
-/*
  * Function: arm6_7_data_abort ()
  *
  * Params  : r0 = address of aborted instruction
@@ -341,6 +306,19 @@
 		mov	pc, lr
 
 /*
+ * Function: arm6_7_set_pgd(unsigned long pgd_phys)
+ * Params  : pgd_phys	Physical address of page table
+ * Purpose : Perform a task switch, saving the old processes state, and restoring
+ *	     the new.
+ */
+_arm6_7_set_pgd:
+		mov	r1, #0
+		mcr	p15, 0, r1, c7, c0, 0		@ flush cache
+		mcr	p15, 0, r0, c2, c0, 0		@ update page table ptr
+		mcr	p15, 0, r1, c5, c0, 0		@ flush TLBs
+		mov	pc, lr
+
+/*
  * Function: arm6_set_pmd ()
  *
  * Params  : r0 = Address to set
@@ -421,19 +399,19 @@
 
 ENTRY(arm6_processor_functions)
 		.word	_arm6_name			@  0
-		.word	_arm6_7_switch_to		@  4
-		.word	_arm6_data_abort		@  8
-		.word	_arm6_7_check_bugs		@ 12
-		.word	_arm6_7_proc_init		@ 16
-		.word	_arm6_7_proc_fin		@ 20
+		.word	_arm6_data_abort		@  4
+		.word	_arm6_7_check_bugs		@  8
+		.word	_arm6_7_proc_init		@ 12
+		.word	_arm6_7_proc_fin		@ 16
 
+		.word	_arm6_7_flush_cache		@ 20
 		.word	_arm6_7_flush_cache		@ 24
 		.word	_arm6_7_flush_cache		@ 28
-		.word	_arm6_7_flush_cache		@ 32
-		.word	_arm6_7_null			@ 36
-		.word	_arm6_7_flush_cache		@ 40
-		.word	_arm6_7_flush_tlb_all		@ 44
-		.word	_arm6_7_flush_tlb_area		@ 48
+		.word	_arm6_7_null			@ 32
+		.word	_arm6_7_flush_cache		@ 36
+		.word	_arm6_7_flush_tlb_all		@ 40
+		.word	_arm6_7_flush_tlb_area		@ 44
+		.word	_arm6_7_set_pgd			@ 48
 		.word	_arm6_set_pmd			@ 52
 		.word	_arm6_7_set_pte			@ 56
 		.word	_arm6_7_reset			@ 60
@@ -451,19 +429,19 @@
 
 ENTRY(arm7_processor_functions)
 		.word	_arm7_name			@  0
-		.word	_arm6_7_switch_to		@  4
-		.word	_arm7_data_abort		@  8
-		.word	_arm6_7_check_bugs		@ 12
-		.word	_arm6_7_proc_init		@ 16
-		.word	_arm6_7_proc_fin		@ 20
+		.word	_arm7_data_abort		@  4
+		.word	_arm6_7_check_bugs		@  8
+		.word	_arm6_7_proc_init		@ 12
+		.word	_arm6_7_proc_fin		@ 16
 
+		.word	_arm6_7_flush_cache		@ 20
 		.word	_arm6_7_flush_cache		@ 24
 		.word	_arm6_7_flush_cache		@ 28
-		.word	_arm6_7_flush_cache		@ 32
-		.word	_arm6_7_null			@ 36
-		.word	_arm6_7_flush_cache		@ 40
-		.word	_arm6_7_flush_tlb_all		@ 44
-		.word	_arm6_7_flush_tlb_area		@ 48
+		.word	_arm6_7_null			@ 32
+		.word	_arm6_7_flush_cache		@ 36
+		.word	_arm6_7_flush_tlb_all		@ 40
+		.word	_arm6_7_flush_tlb_area		@ 44
+		.word	_arm6_7_set_pgd			@ 48
 		.word	_arm7_set_pmd			@ 52
 		.word	_arm6_7_set_pte			@ 56
 		.word	_arm6_7_reset			@ 60
diff -u --recursive --new-file v2.3.12/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.3.12/linux/arch/arm/mm/proc-sa110.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/mm/proc-sa110.S	Mon Aug  2 10:19:52 1999
@@ -207,40 +207,35 @@
 		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 		mcr	p15, 0, r0, c7, c5, 0		@ flush I cache
 		mov	pc, lr
+
+/*
+ * Function: sa110_data_abort ()
+ * Params  : r0 = address of aborted instruction
+ * Purpose : obtain information about current aborted instruction
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR
+ *	   : r2 != 0 if writing
+ */
+		.align	5
+_sa110_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
+		and	r3, r2, #0x69 << 2
+		and	r2, r2, #2
+		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+		and	r1, r1, #255
+		mov	pc, lr
+
+		.align	5
 /*
- * Function: sa110_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
+ * Function: sa110_set_pgd(unsigned long pgd_phys)
+ * Params  : pgd_phys	Physical address of page table
  * 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.
  */
 		.align	5
-_sa110_switch_to:
-		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
-		mrs	ip, cpsr
-		stmfd	sp!, {ip}			@ Save cpsr_SVC
-		ldr	r2, [r0, #TSS_MEMMAP]		@ Get old page tables
-		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
-		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r5, [r1, #TSK_ADDR_LIMIT]
-		ldr	r4, [r1, #TSS_MEMMAP]		@ Page table pointer
-		teq	r5, #0
-		moveq	r5, #DOM_KERNELDOMAIN
-		movne	r5, #DOM_USERDOMAIN
-		mcr	p15, 0, r5, c3, c0		@ Set segment
-/*
- * Flushing the cache is nightmarishly slow, so we take any excuse
- * to get out of it.  If the old page table is the same as the new,
- * this is a CLONE_VM relative of the old task and there is no need
- * to flush.  The overhead of the tests isn't even on the radar
- * compared to the cost of the flush itself.
- */
-		teq	r4, r2
-		beq	2f
+_sa110_set_pgd:
 		ldr	r3, =Lclean_switch
 		ldr	r2, [r3]
 		ands	r2, r2, #1
@@ -255,29 +250,8 @@
 		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, r4, c2, c0, 0		@ load page table pointer
+		mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
 		mcr	p15, 0, r1, c8, c7, 0		@ flush TLBs
-2:		ldmfd	sp!, {ip}
-		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
-		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
-
-/*
- * Function: sa110_data_abort ()
- * Params  : r0 = address of aborted instruction
- * Purpose : obtain information about current aborted instruction
- * Returns : r0 = address of abort
- *	   : r1 = FSR
- *	   : r2 != 0 if writing
- */
-		.align	5
-_sa110_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
-		and	r3, r2, #0x69 << 2
-		and	r2, r2, #2
-		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-		and	r1, r1, #255
 		mov	pc, lr
 
 /*
@@ -362,20 +336,20 @@
 
 ENTRY(sa110_processor_functions)
 		.word	_sa110_name			@  0
-		.word	_sa110_switch_to		@  4
-		.word	_sa110_data_abort		@  8
-		.word	_sa110_check_bugs		@ 12
-		.word	_sa110_proc_init		@ 16
-		.word	_sa110_proc_fin			@ 20
-
-		.word	_sa110_flush_cache_all		@ 24
-		.word	_sa110_flush_cache_area		@ 28
-		.word	_sa110_flush_cache_entry	@ 32
-		.word	_sa110_clean_cache_area		@ 36
-		.word	_sa110_flush_ram_page		@ 40
-		.word	_sa110_flush_tlb_all		@ 44
-		.word	_sa110_flush_tlb_area		@ 48
+		.word	_sa110_data_abort		@  4
+		.word	_sa110_check_bugs		@  8
+		.word	_sa110_proc_init		@ 12
+		.word	_sa110_proc_fin			@ 16
+
+		.word	_sa110_flush_cache_all		@ 20
+		.word	_sa110_flush_cache_area		@ 24
+		.word	_sa110_flush_cache_entry	@ 28
+		.word	_sa110_clean_cache_area		@ 32
+		.word	_sa110_flush_ram_page		@ 36
+		.word	_sa110_flush_tlb_all		@ 40
+		.word	_sa110_flush_tlb_area		@ 44
 
+		.word	_sa110_set_pgd			@ 48
 		.word	_sa110_set_pmd			@ 52
 		.word	_sa110_set_pte			@ 56
 		.word	_sa110_reset			@ 60
diff -u --recursive --new-file v2.3.12/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.12/linux/arch/i386/config.in	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/config.in	Thu Aug  5 18:44:28 1999
@@ -94,8 +94,8 @@
 
 source drivers/parport/Config.in
 
-bool 'Advanced Power Management BIOS support' CONFIG_APM
-if [ "$CONFIG_APM" = "y" ]; then
+tristate 'Advanced Power Management BIOS support' CONFIG_APM
+if [ "$CONFIG_APM" != "n" ]; then
   bool '   Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
   bool '   Enable PM at boot time' CONFIG_APM_DO_ENABLE
   bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
diff -u --recursive --new-file v2.3.12/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.12/linux/arch/i386/defconfig	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/defconfig	Thu Aug  5 18:53:36 1999
@@ -94,7 +94,9 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_AEC6210 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_CPQ_DA is not set
 
@@ -293,14 +295,12 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
 
 #
 # 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=y
 # CONFIG_PC110_PAD is not set
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.3.12/linux/arch/i386/kernel/Makefile	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/Makefile	Tue Aug  3 09:56:37 1999
@@ -34,8 +34,12 @@
   endif
 endif
 
-ifdef CONFIG_APM
+ifeq ($(CONFIG_APM),y)
 OX_OBJS += apm.o
+else
+  ifeq ($(CONFIG_APM),m)
+  MX_OBJS += apm.o
+  endif
 endif
 
 ifdef CONFIG_SMP
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.12/linux/arch/i386/kernel/apm.c	Thu May 13 23:22:05 1999
+++ linux/arch/i386/kernel/apm.c	Fri Aug  6 11:17:13 1999
@@ -273,7 +273,6 @@
 static void	set_time(void);
 
 static void	check_events(void);
-static void	do_apm_timer(unsigned long);
 
 static int	do_open(struct inode *, struct file *);
 static int	do_release(struct inode *, struct file *);
@@ -314,11 +313,9 @@
 static int			debug = 0;
 static int			apm_disabled = 0;
 
-static DECLARE_WAIT_QUEUE_HEAD(process_list);
+static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static struct apm_bios_struct *	user_list = NULL;
 
-static struct timer_list	apm_timer;
-
 static char			driver_version[] = "1.9";	/* no spaces */
 
 #ifdef APM_DEBUG
@@ -543,6 +540,50 @@
 	return set_power_state(0x0001, state);
 }
 
+/*
+ * If no process has been interested in this
+ * CPU for some time, we want to wake up the
+ * power management thread - we probably want
+ * to conserve power.
+ */
+#define HARD_IDLE_TIMEOUT (HZ/3)
+
+/* This should wake up kapmd and ask it to slow the CPU */
+#define powermanagement_idle()  do { } while (0)
+
+extern int hlt_counter;
+
+/*
+ * This is the idle thing.
+ */
+void apm_cpu_idle(void)
+{
+	unsigned int start_idle;
+
+	start_idle = jiffies;
+	while (1) {
+		if (!current->need_resched) {
+			if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
+				if (!current_cpu_data.hlt_works_ok)
+					continue;
+				if (hlt_counter)
+					continue;
+				asm volatile("sti ; hlt" : : : "memory");
+				continue;
+			}
+
+			/*
+			 * Ok, do some power management - we've been idle for too long
+			 */
+			powermanagement_idle();
+		}
+
+		schedule();
+		check_pgt_cache();
+		start_idle = jiffies;
+	}
+}
+
 void apm_power_off(void)
 {
 	/*
@@ -756,7 +797,7 @@
 			break;
 		}
 	}
-	wake_up_interruptible(&process_list);
+	wake_up_interruptible(&apm_waitqueue);
 	return 1;
 }
 
@@ -942,32 +983,39 @@
 	}
 }
 
-static void do_apm_timer(unsigned long unused)
+/*
+ * This is the APM thread main loop.
+ */
+static void apm_mainloop(void)
 {
-	int	err;
-
-	static int	pending_count = 0;
+	DECLARE_WAITQUEUE(wait, current);
+	apm_enabled = 1;
 
-	if (((standbys_pending > 0) || (suspends_pending > 0))
-	    && (apm_bios_info.version > 0x100)
-	    && (pending_count-- <= 0)) {
-		pending_count = 4;
+	add_wait_queue(&apm_waitqueue, &wait);
+	for (;;) {
+		static int pending_count = 0;
+		int err;
 
-		err = apm_set_power_state(APM_STATE_BUSY);
-		if (err)
-			apm_error("busy", err);
-	}
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(APM_CHECK_TIMEOUT);
 
-	if (!(((standbys_pending > 0) || (suspends_pending > 0))
-	      && (apm_bios_info.version == 0x100)))
-		check_events();
+		if (((standbys_pending > 0) || (suspends_pending > 0))
+		    && (apm_bios_info.version > 0x100)
+		    && (pending_count-- <= 0)) {
+			pending_count = 4;
+
+			err = apm_set_power_state(APM_STATE_BUSY);
+			if (err)
+				apm_error("busy", err);
+		}
 
-	init_timer(&apm_timer);
-	apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
-	add_timer(&apm_timer);
+		if (!(((standbys_pending > 0) || (suspends_pending > 0))
+		      && (apm_bios_info.version == 0x100)))
+			check_events();
+	}
 }
 
-/* Called from sys_idle, must make sure apm_enabled. */
+/* Called from cpu_idle, must make sure apm_enabled. */
 int apm_do_idle(void)
 {
 #ifdef CONFIG_APM_CPU_IDLE
@@ -986,7 +1034,7 @@
 #endif
 }
 
-/* Called from sys_idle, must make sure apm_enabled. */
+/* Called from cpu_idle, must make sure apm_enabled. */
 void apm_do_busy(void)
 {
 #ifdef CONFIG_APM_CPU_IDLE
@@ -1027,7 +1075,7 @@
 	if (queue_empty(as)) {
 		if (fp->f_flags & O_NONBLOCK)
 			return -EAGAIN;
-		add_wait_queue(&process_list, &wait);
+		add_wait_queue(&apm_waitqueue, &wait);
 repeat:
 		current->state = TASK_INTERRUPTIBLE;
 		if (queue_empty(as) && !signal_pending(current)) {
@@ -1035,7 +1083,7 @@
 			goto repeat;
 		}
 		current->state = TASK_RUNNING;
-		remove_wait_queue(&process_list, &wait);
+		remove_wait_queue(&apm_waitqueue, &wait);
 	}
 	i = count;
 	while ((i >= sizeof(event)) && !queue_empty(as)) {
@@ -1069,7 +1117,7 @@
 	as = fp->private_data;
 	if (check_apm_bios_struct(as, "select"))
 		return 0;
-	poll_wait(fp, &process_list, wait);
+	poll_wait(fp, &apm_waitqueue, wait);
 	if (!queue_empty(as))
 		return POLLIN | POLLRDNORM;
 	return 0;
@@ -1263,7 +1311,97 @@
 	return p - buf;
 }
 
-void __init apm_setup(char *str, int *dummy)
+static int apm(void *unused)
+{
+	unsigned short	bx;
+	unsigned short	cx;
+	unsigned short	dx;
+	unsigned short	error;
+	char *		power_stat;
+	char *		bat_stat;
+
+	strcpy(current->comm, "kapmd");
+	sigfillset(&current->blocked);
+
+	if (apm_bios_info.version > 0x100) {
+		/*
+		 * We only support BIOSs up to version 1.2
+		 */
+		if (apm_bios_info.version > 0x0102)
+			apm_bios_info.version = 0x0102;
+		if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
+			/* Fall back to an APM 1.0 connection. */
+			apm_bios_info.version = 0x100;
+		}
+	}
+	if (debug) {
+		printk(KERN_INFO "apm: Connection version %d.%d\n",
+			(apm_bios_info.version >> 8) & 0xff,
+			apm_bios_info.version & 0xff );
+
+		error = apm_get_power_status(&bx, &cx, &dx);
+		if (error)
+			printk(KERN_INFO "apm: power status not available\n");
+		else {
+			switch ((bx >> 8) & 0xff) {
+			case 0: power_stat = "off line"; break;
+			case 1: power_stat = "on line"; break;
+			case 2: power_stat = "on backup power"; break;
+			default: power_stat = "unknown"; break;
+			}
+			switch (bx & 0xff) {
+			case 0: bat_stat = "high"; break;
+			case 1: bat_stat = "low"; break;
+			case 2: bat_stat = "critical"; break;
+			case 3: bat_stat = "charging"; break;
+			default: bat_stat = "unknown"; break;
+			}
+			printk(KERN_INFO
+			       "apm: AC %s, battery status %s, battery life ",
+			       power_stat, bat_stat);
+			if ((cx & 0xff) == 0xff)
+				printk("unknown\n");
+			else
+				printk("%d%%\n", cx & 0xff);
+			if (apm_bios_info.version > 0x100) {
+				printk(KERN_INFO
+				       "apm: battery flag 0x%02x, battery life ",
+				       (cx >> 8) & 0xff);
+				if (dx == 0xffff)
+					printk("unknown\n");
+				else
+					printk("%d %s\n", dx & 0x7fff,
+						(dx & 0x8000) ?
+						"minutes" : "seconds");
+			}
+		}
+	}
+
+#ifdef CONFIG_APM_DO_ENABLE
+	if (apm_bios_info.flags & APM_BIOS_DISABLED) {
+		/*
+		 * This call causes my NEC UltraLite Versa 33/C to hang if it
+		 * is booted with PM disabled but not in the docking station.
+		 * Unfortunate ...
+		 */
+		error = apm_enable_power_management();
+		if (error) {
+			apm_error("enable power management", error);
+			return -1;
+		}
+	}
+#endif
+	if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0)
+	    && (apm_bios_info.version > 0x0100)) {
+		if (apm_engage_power_management(0x0001) == APM_SUCCESS)
+			apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+	}
+
+	apm_mainloop();
+	return 0;
+}
+
+static int __init apm_setup(char *str)
 {
 	int	invert;
 
@@ -1283,16 +1421,23 @@
 		if (str != NULL)
 			str += strspn(str, ", \t");
 	}
+	return 1;
 }
 
-void __init apm_bios_init(void)
+__setup("apm=", apm_setup);
+
+/*
+ * Just start the APM thread. We do NOT want to do APM BIOS
+ * calls from anything but the APM thread, if for no other reason
+ * than the fact that we don't trust the APM BIOS. This way,
+ * most common APM BIOS problems that lead to protection errors
+ * etc will have at least some level of being contained...
+ *
+ * In short, if something bad happens, at least we have a choice
+ * of just killing the apm thread..
+ */
+static int __init apm_init(void)
 {
-	unsigned short	bx;
-	unsigned short	cx;
-	unsigned short	dx;
-	unsigned short	error;
-	char *		power_stat;
-	char *		bat_stat;
 	static struct proc_dir_entry *ent;
 
 	if (apm_bios_info.version == 0) {
@@ -1339,6 +1484,15 @@
 		return;
 	}
 
+#ifdef CONFIG_SMP
+	if (smp_num_cpus > 1) {
+		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+		if (smp_hack)
+			smp_hack = 2;
+		return -1;
+	}
+#endif
+
 	/*
 	 * Set up a segment that references the real mode segment 0x40
 	 * that extends up to the end of page zero (that we have reserved).
@@ -1378,92 +1532,6 @@
 			(apm_bios_info.dseg_len - 1) & 0xffff);
 	}
 #endif
-#ifdef CONFIG_SMP
-	if (smp_num_cpus > 1) {
-		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
-		if (smp_hack)
-			smp_hack = 2;
-		return;
-	}
-#endif
-	if (apm_bios_info.version > 0x100) {
-		/*
-		 * We only support BIOSs up to version 1.2
-		 */
-		if (apm_bios_info.version > 0x0102)
-			apm_bios_info.version = 0x0102;
-		if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
-			/* Fall back to an APM 1.0 connection. */
-			apm_bios_info.version = 0x100;
-		}
-	}
-	if (debug) {
-		printk(KERN_INFO "apm: Connection version %d.%d\n",
-			(apm_bios_info.version >> 8) & 0xff,
-			apm_bios_info.version & 0xff );
-
-		error = apm_get_power_status(&bx, &cx, &dx);
-		if (error)
-			printk(KERN_INFO "apm: power status not available\n");
-		else {
-			switch ((bx >> 8) & 0xff) {
-			case 0: power_stat = "off line"; break;
-			case 1: power_stat = "on line"; break;
-			case 2: power_stat = "on backup power"; break;
-			default: power_stat = "unknown"; break;
-			}
-			switch (bx & 0xff) {
-			case 0: bat_stat = "high"; break;
-			case 1: bat_stat = "low"; break;
-			case 2: bat_stat = "critical"; break;
-			case 3: bat_stat = "charging"; break;
-			default: bat_stat = "unknown"; break;
-			}
-			printk(KERN_INFO
-			       "apm: AC %s, battery status %s, battery life ",
-			       power_stat, bat_stat);
-			if ((cx & 0xff) == 0xff)
-				printk("unknown\n");
-			else
-				printk("%d%%\n", cx & 0xff);
-			if (apm_bios_info.version > 0x100) {
-				printk(KERN_INFO
-				       "apm: battery flag 0x%02x, battery life ",
-				       (cx >> 8) & 0xff);
-				if (dx == 0xffff)
-					printk("unknown\n");
-				else
-					printk("%d %s\n", dx & 0x7fff,
-						(dx & 0x8000) ?
-						"minutes" : "seconds");
-			}
-		}
-	}
-
-#ifdef CONFIG_APM_DO_ENABLE
-	if (apm_bios_info.flags & APM_BIOS_DISABLED) {
-		/*
-		 * This call causes my NEC UltraLite Versa 33/C to hang if it
-		 * is booted with PM disabled but not in the docking station.
-		 * Unfortunate ...
-		 */
-		error = apm_enable_power_management();
-		if (error) {
-			apm_error("enable power management", error);
-			return;
-		}
-	}
-#endif
-	if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0)
-	    && (apm_bios_info.version > 0x0100)) {
-		if (apm_engage_power_management(0x0001) == APM_SUCCESS)
-			apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
-	}
-
-	init_timer(&apm_timer);
-	apm_timer.function = do_apm_timer;
-	apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
-	add_timer(&apm_timer);
 
 	ent = create_proc_entry("apm", 0, 0);
 	if (ent != NULL)
@@ -1471,5 +1539,7 @@
 
 	misc_register(&apm_device);
 
-	apm_enabled = 1;
+	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 }
+
+module_init(apm_init)
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.3.12/linux/arch/i386/kernel/bios32.c	Sat Apr 24 17:49:37 1999
+++ linux/arch/i386/kernel/bios32.c	Thu Aug  5 18:44:28 1999
@@ -907,12 +907,17 @@
 		if ((try & PCI_BASE_ADDRESS_IO_MASK) != addr) {
 			addr = 0;
 			printk("PCI: Address setup failed, got %04x\n", try);
-		} else
-			dev->base_address[idx] = try;
+		} else {
+			struct resource *res = dev->resource + idx;
+			res->start = addr;
+			res->end = addr + size - 1;
+			res->flags |= PCI_BASE_ADDRESS_IO_MASK;
+		}
 	}
 	if (!addr) {
 		pcibios_write_config_dword(bus, devfn, reg, 0);
-		dev->base_address[idx] = 0;
+		dev->resource[idx].start = 0;
+		dev->resource[idx].flags = 0;
 	}
 	pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
 }
@@ -939,7 +944,7 @@
 			    e->vendor == d->vendor &&
 			    e->device == d->device &&
 			    e->class == d->class &&
-			    !memcmp(e->base_address, d->base_address, sizeof(e->base_address)))
+			    !memcmp(e->resource, d->resource, sizeof(e->resource)))
 				break;
 		if (!e)
 			return;
@@ -1060,7 +1065,7 @@
 	int i;
 
 	for(i=0; i<4; i++)
-		d->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
+		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 }
 
 struct dev_ex {
@@ -1112,11 +1117,12 @@
 		 */
 		has_io = has_mem = 0;
 		for(i=0; i<6; i++) {
-			unsigned long a = dev->base_address[i];
+			struct resource *res = dev->resource + i;
+			unsigned long a = res->flags;
 			if (a & PCI_BASE_ADDRESS_SPACE_IO) {
+				unsigned long addr = res->start;
 				has_io = 1;
-				a &= PCI_BASE_ADDRESS_IO_MASK;
-				if (!a || a == PCI_BASE_ADDRESS_IO_MASK)
+				if (!addr || addr == PCI_BASE_ADDRESS_IO_MASK)
 					pcibios_fixup_io_addr(dev, i);
 			} else if (a & PCI_BASE_ADDRESS_MEM_MASK)
 				has_mem = 1;
@@ -1234,7 +1240,7 @@
 		access_pci = bios;
 }
 
-__initfunc(char *pcibios_setup(char *str))
+char * __init pcibios_setup(char *str)
 {
 	if (!strcmp(str, "off")) {
 		pci_probe = 0;
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.3.12/linux/arch/i386/kernel/entry.S	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/entry.S	Thu Jul 29 15:18:50 1999
@@ -481,7 +481,7 @@
 	.long SYMBOL_NAME(sys_uname)
 	.long SYMBOL_NAME(sys_iopl)		/* 110 */
 	.long SYMBOL_NAME(sys_vhangup)
-	.long SYMBOL_NAME(sys_idle)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* old "idle" system call */
 	.long SYMBOL_NAME(sys_vm86old)
 	.long SYMBOL_NAME(sys_wait4)
 	.long SYMBOL_NAME(sys_swapoff)		/* 115 */
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.3.12/linux/arch/i386/kernel/init_task.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/kernel/init_task.c	Tue Aug  3 10:32:57 1999
@@ -1,10 +1,10 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/desc.h>
-#include <asm/init.h>
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.3.12/linux/arch/i386/kernel/io_apic.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/kernel/io_apic.c	Fri Aug  6 11:43:09 1999
@@ -242,40 +242,43 @@
 int pirq_entries [MAX_PIRQS];
 int pirqs_enabled;
 
-void __init ioapic_setup(char *str, int *ints)
+static int __init ioapic_setup(char *str)
 {
 	extern int skip_ioapic_setup;	/* defined in arch/i386/kernel/smp.c */
 
 	skip_ioapic_setup = 1;
+	return 1;
 }
 
-void __init ioapic_pirq_setup(char *str, int *ints)
+__setup("noapic", ioapic_setup);
+
+static int __init ioapic_pirq_setup(char *str)
 {
 	int i, max;
+	int ints[MAX_PIRQS+1];
+
+	get_options(str, ARRAY_SIZE(ints), ints);
 
 	for (i = 0; i < MAX_PIRQS; i++)
 		pirq_entries[i] = -1;
 
-	if (!ints) {
-		pirqs_enabled = 0;
-		printk("PIRQ redirection, trusting MP-BIOS.\n");
-
-	} else {
-		pirqs_enabled = 1;
-		printk("PIRQ redirection, working around broken MP-BIOS.\n");
-		max = MAX_PIRQS;
-		if (ints[0] < MAX_PIRQS)
-			max = ints[0];
-
-		for (i = 0; i < max; i++) {
-			printk("... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
-			/*
-			 * PIRQs are mapped upside down, usually.
-			 */
-			pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
-		}
+	pirqs_enabled = 1;
+	printk("PIRQ redirection, working around broken MP-BIOS.\n");
+	max = MAX_PIRQS;
+	if (ints[0] < MAX_PIRQS)
+		max = ints[0];
+
+	for (i = 0; i < max; i++) {
+		printk("... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
+		/*
+		 * PIRQs are mapped upside down, usually.
+		 */
+		pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
 	}
+	return 1;
 }
+
+__setup("pirq=", ioapic_pirq_setup);
 
 /*
  * Find the IRQ entry number of a certain pin.
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.12/linux/arch/i386/kernel/irq.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/irq.c	Fri Aug  6 11:43:09 1999
@@ -470,7 +470,6 @@
 	int i;
 	unsigned long *stack;
 	int cpu = smp_processor_id();
-	extern char *get_options(char *str, int *ints);
 
 	printk("\n%s, CPU %d:\n", str, cpu);
 	printk("irq:  %d [%d %d]\n",
@@ -480,7 +479,7 @@
 	stack = (unsigned long *) &stack;
 	for (i = 40; i ; i--) {
 		unsigned long x = *++stack;
-		if (x > (unsigned long) &get_options && x < (unsigned long) &vsprintf) {
+		if (x > (unsigned long) &get_option && x < (unsigned long) &vsprintf) {
 			printk("<[%08lx]> ", x);
 		}
 	}
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.3.12/linux/arch/i386/kernel/ldt.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/ldt.c	Tue Aug  3 12:10:35 1999
@@ -98,8 +98,9 @@
 			printk(KERN_WARNING "LDT allocated for cloned task!\n");
 		/*
 		 * Possibly do an SMP cross-call to other CPUs to reload
-		 * their LDTs
+		 * their LDTs?
 		 */
+		load_LDT(mm);
 	}
 
 	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->segments);
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.3.12/linux/arch/i386/kernel/process.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/kernel/process.c	Fri Aug  6 11:09:10 1999
@@ -51,14 +51,7 @@
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
-#ifdef CONFIG_APM
-extern int  apm_do_idle(void);
-extern void apm_do_busy(void);
-#endif
-
-static int hlt_counter=0;
-
-#define HARD_IDLE_TIMEOUT (HZ / 3)
+int hlt_counter=0;
 
 void disable_hlt(void)
 {
@@ -70,101 +63,67 @@
 	hlt_counter--;
 }
 
-#ifndef __SMP__
-
-static void hard_idle(void)
-{
-	while (!current->need_resched) {
-		if (boot_cpu_data.hlt_works_ok && !hlt_counter) {
-#ifdef CONFIG_APM
-				/* If the APM BIOS is not enabled, or there
-				 is an error calling the idle routine, we
-				 should hlt if possible.  We need to check
-				 need_resched again because an interrupt
-				 may have occurred in apm_do_idle(). */
-			start_bh_atomic();
-			if (!apm_do_idle() && !current->need_resched)
-				__asm__("hlt");
-			end_bh_atomic();
-#else
-			__asm__("hlt");
-#endif
-	        }
- 		if (current->need_resched) 
- 			break;
-		schedule();
-	}
-#ifdef CONFIG_APM
-	apm_do_busy();
-#endif
-}
-
-/*
- * The idle loop on a uniprocessor i386..
- */ 
-static int cpu_idle(void *unused)
+static void default_idle(void)
 {
-	int work = 1;
-	unsigned long start_idle = 0;
-
-	/* endless idle loop with no priority at all */
-	current->priority = 0;
-	current->counter = -100;
-	init_idle();
-
-	for (;;) {
-		if (work)
-			start_idle = jiffies;
-
-		if (jiffies - start_idle > HARD_IDLE_TIMEOUT) 
-			hard_idle();
-		else  {
-			if (boot_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched)
-		        	__asm__("hlt");
+	while (1) {
+		while (!current->need_resched) {
+			if (!current_cpu_data.hlt_works_ok)
+				continue;
+			if (hlt_counter)
+				continue;
+			asm volatile("sti ; hlt" : : : "memory");
 		}
-
-		work = current->need_resched;
 		schedule();
 		check_pgt_cache();
 	}
-}
+}	
 
-#else
+void (*idle)(void) = default_idle;
 
-/*
- *	This is being executed in task 0 'user space'.
- */
+#if 1
+
+#include <linux/pci.h>
 
-int cpu_idle(void *unused)
+static int __init piix4_idle_init(void)
 {
-	/* endless idle loop with no priority at all */
-	current->priority = 0;
-	current->counter = -100;
-	init_idle();
+	/* This is the PIIX4 ACPI device */
+	struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
 
-	while(1) {
-		if (current_cpu_data.hlt_works_ok && !hlt_counter &&
-				 !current->need_resched)
-			__asm__("hlt");
+	if (dev) {
+		u32 base;
+
+		printk("Found PIIX4 ACPI device\n");
+		pci_read_config_dword(dev, 0x40, &base);
+		printk("  Base address %04x\n", base);
+#ifdef __SMP__
 		/*
-		 * although we are an idle CPU, we do not want to
-		 * get into the scheduler unnecessarily.
+		 * We can't really do idle things with multiple CPU's, I'm
+		 * afraid.  We'd need a per-CPU ACPI device.
 		 */
-		if (current->need_resched) {
-			schedule();
-			check_pgt_cache();
-		}
+		if (smp_num_cpus > 1)
+			return 0;
+#endif
 	}
+	return 0;
 }
 
+__initcall(piix4_idle_init);
+
 #endif
 
-asmlinkage int sys_idle(void)
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
 {
-	if (current->pid != 0)
-		return -EPERM;
-	cpu_idle(NULL);
-	return 0;
+	/* endless idle loop with no priority at all */
+	init_idle();
+	current->priority = 0;
+	current->counter = -100;
+	idle();
 }
 
 /*
@@ -177,7 +136,7 @@
 static int reboot_mode = 0;
 static int reboot_thru_bios = 0;
 
-__initfunc(void reboot_setup(char *str, int *ints))
+static int __init reboot_setup(char *str)
 {
 	while(1) {
 		switch (*str) {
@@ -199,8 +158,10 @@
 		else
 			break;
 	}
+	return 1;
 }
 
+__setup("reboot=", reboot_setup);
 
 /* The following code and data reboots the machine by switching to real
    mode and jumping to the BIOS reset entry point, as if the CPU has
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.12/linux/arch/i386/kernel/setup.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/kernel/setup.c	Thu Jul 29 16:02:09 1999
@@ -35,9 +35,7 @@
 #include <linux/delay.h>
 #include <linux/config.h>
 #include <linux/init.h>
-#ifdef CONFIG_APM
 #include <linux/apm_bios.h>
-#endif
 #ifdef CONFIG_BLK_DEV_RAM
 #include <linux/blk.h>
 #endif
@@ -77,9 +75,7 @@
  */
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info;
-#ifdef CONFIG_APM
 struct apm_bios_info apm_bios_info;
-#endif
 struct sys_desc_table_struct {
 	unsigned short length;
 	unsigned char table[0];
@@ -284,9 +280,7 @@
  	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
-#ifdef CONFIG_APM
 	apm_bios_info = APM_BIOS_INFO;
-#endif
 	if( SYS_DESC_TABLE.length != 0 ) {
 		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
 		machine_id = SYS_DESC_TABLE.table[0];
diff -u --recursive --new-file v2.3.12/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.12/linux/arch/i386/kernel/smp.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/kernel/smp.c	Sat Aug  7 12:59:40 1999
@@ -172,6 +172,22 @@
 		max_cpus = 0;
 }
 
+static int __init nosmp(char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus", maxcpus);
+
 void ack_APIC_irq(void)
 {
 	/* Clear the IPI */
@@ -875,7 +891,7 @@
 
 int cpucount = 0;
 
-extern int cpu_idle(void * unused);
+extern int cpu_idle(void);
 
 /*
  *	Activate a secondary processor.
@@ -891,7 +907,7 @@
 	smp_callin();
 	while (!atomic_read(&smp_commenced))
 		/* nothing */ ;
-	return cpu_idle(NULL);
+	return cpu_idle();
 }
 
 /*
@@ -939,8 +955,6 @@
 	 * once we got the process:
 	 */
 	idle = init_task.prev_task;
-
-	init_tasks[cpucount] = idle;
 	if (!idle)
 		panic("No idle process for CPU %d", i);
 
@@ -952,6 +966,7 @@
 
 	del_from_runqueue(idle);
 	unhash_process(idle);
+	init_tasks[cpucount] = idle;
 
 	/* start_eip had better be page-aligned! */
 	start_eip = setup_trampoline();
@@ -1229,6 +1244,7 @@
 		io_apic_irqs = 0;
 #endif
 		cpu_online_map = cpu_present_map;
+		smp_num_cpus = 1;
 		goto smp_done;
 	}
 
@@ -1615,7 +1631,10 @@
 			 * Take care of "crossing" invalidates
 			 */
 			if (test_bit(cpu, &smp_invalidate_needed)) {
+				struct mm_struct *mm = current->mm;
 				clear_bit(cpu, &smp_invalidate_needed);
+				if (mm)
+					atomic_set_mask(1 << cpu, &mm->cpu_vm_mask);
 				local_flush_tlb();
 			}
 			--stuck;
@@ -1639,11 +1658,10 @@
 {
 	unsigned long vm_mask = 1 << current->processor;
 	struct mm_struct *mm = current->mm;
+	unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
 
-	if (mm->cpu_vm_mask != vm_mask) {
-		flush_tlb_others(mm->cpu_vm_mask & ~vm_mask);
-		mm->cpu_vm_mask = vm_mask;
-	}
+	mm->cpu_vm_mask = vm_mask;
+	flush_tlb_others(cpu_mask);
 	local_flush_tlb();
 }
 
diff -u --recursive --new-file v2.3.12/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.12/linux/arch/i386/mm/fault.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/i386/mm/fault.c	Mon Aug  2 15:56:47 1999
@@ -245,6 +245,7 @@
 	printk(" at virtual address %08lx\n",address);
 	printk(" printing eip:\n");
 	printk("%08lx\n", regs->eip);
+	asm("movl %%cr3,%0":"=r" (page));
 	page = ((unsigned long *) __va(page))[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
 	if (page & 1) {
diff -u --recursive --new-file v2.3.12/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.12/linux/arch/i386/mm/init.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/mm/init.c	Wed Aug  4 22:53:14 1999
@@ -28,6 +28,8 @@
 #include <asm/dma.h>
 #include <asm/fixmap.h>
 
+static unsigned long totalram = 0;
+
 extern void show_net_buffers(void);
 extern unsigned long init_smp_mappings(unsigned long);
 
@@ -419,6 +421,7 @@
 			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))
@@ -446,28 +449,16 @@
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
 		set_page_count(mem_map+MAP_NR(addr), 1);
 		free_page(addr);
+		totalram += PAGE_SIZE;
 	}
 	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
 {
-	int i;
-
-	i = max_mapnr;
-	val->totalram = 0;
+	val->totalram = totalram;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
 	val->bufferram = atomic_read(&buffermem);
-	while (i-- > 0)  {
-		if (PageReserved(mem_map+i))
-			continue;
-		val->totalram++;
-		if (!page_count(mem_map+i))
-			continue;
-		val->sharedram += page_count(mem_map+i) - 1;
-	}
-	val->totalram <<= PAGE_SHIFT;
-	val->sharedram <<= PAGE_SHIFT;
 	return;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.3.12/linux/arch/i386/vmlinux.lds	Tue Jun 22 14:41:36 1999
+++ linux/arch/i386/vmlinux.lds	Mon Aug  9 12:41:57 1999
@@ -42,15 +42,21 @@
   __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(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
   . = ALIGN(4096);
   .data.page_aligned : { *(.data.idt) }
 
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --recursive --new-file v2.3.12/linux/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S
--- v2.3.12/linux/arch/i386/vmlinux.lds.S	Mon Jun  7 17:02:23 1999
+++ linux/arch/i386/vmlinux.lds.S	Mon Aug  2 13:57:59 1999
@@ -42,15 +42,21 @@
   __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(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
   . = ALIGN(4096);
   .data.page_aligned : { *(.data.idt) }
 
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/apollo/config.c linux/arch/m68k/apollo/config.c
--- v2.3.12/linux/arch/m68k/apollo/config.c	Fri Jul 10 15:18:30 1998
+++ linux/arch/m68k/apollo/config.c	Mon Aug  9 12:27:30 1999
@@ -1,4 +1,3 @@
-#include <stdarg.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/apollo/dn_debug.c linux/arch/m68k/apollo/dn_debug.c
--- v2.3.12/linux/arch/m68k/apollo/dn_debug.c	Thu Feb 12 16:30:12 1998
+++ linux/arch/m68k/apollo/dn_debug.c	Mon Aug  9 12:27:30 1999
@@ -1,4 +1,3 @@
-#include <stdarg.h>
 
 #define DN_DEBUG_BUFFER_BASE 0x82800000
 #define DN_DEBUG_BUFFER_SIZE 8*1024*1024
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c
--- v2.3.12/linux/arch/m68k/atari/joystick.c	Wed Sep  2 09:39:18 1998
+++ linux/arch/m68k/atari/joystick.c	Mon Aug  9 12:27:30 1999
@@ -134,7 +134,8 @@
 {
     joystick[0].active = joystick[1].active = 0;
     joystick[0].ready = joystick[1].ready = 0;
-    joystick[0].wait = joystick[1].wait = NULL;
+    init_waitqueue_head(&joystick[0].wait);
+    init_waitqueue_head(&joystick[1].wait);
 
     if (register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops))
 	printk("unable to get major %d for joystick devices\n", MAJOR_NR);
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v2.3.12/linux/arch/m68k/atari/stram.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/m68k/atari/stram.c	Mon Aug  9 12:27:30 1999
@@ -200,7 +200,7 @@
 static int stram_swap_type;
 
 /* Semaphore for get_stram_region.  */
-static struct semaphore stram_swap_sem = MUTEX;
+static DECLARE_MUTEX(stram_swap_sem);
 
 /* major and minor device number of the ST-RAM device; for the major, we use
  * the same as Amiga z2ram, which is really similar and impossible on Atari,
@@ -346,12 +346,11 @@
 				 "swap=%08lx-%08lx\n", swap_start, swap_end );
 		
 		/* reserve some amount of memory for maintainance of
-		 * swapping itself: 1 page for the lockmap, and one page
-		 * for each 2048 (PAGE_SIZE/2) swap pages. (2 bytes for
-		 * each page) */
+		 * swapping itself: one page for each 2048 (PAGE_SIZE/2)
+		 * swap pages. (2 bytes for each page) */
 		swap_data = start_mem;
-		start_mem += (((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1)
-			       >> (PAGE_SHIFT-1)) + 1) << PAGE_SHIFT;
+		start_mem += ((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1)
+			      >> (PAGE_SHIFT-1)) << PAGE_SHIFT;
 		/* correct swap_start if necessary */
 		if (swap_start == swap_data)
 			swap_start = start_mem;
@@ -610,8 +609,7 @@
 	p->flags        = SWP_USED;
 	p->swap_file    = &fake_dentry[0];
 	p->swap_device  = 0;
-	p->swap_lockmap = (unsigned char *)(swap_data);
-	p->swap_map	= (unsigned short *)(swap_data + PAGE_SIZE);
+	p->swap_map	= (unsigned short *)swap_data;
 	p->cluster_nr   = 0;
 	p->next         = -1;
 	p->prio         = 0x7ff0;	/* a rather high priority, but not the higest
@@ -623,9 +621,6 @@
 	swap_inode.i_rdev = p->swap_device;
 	stram_open( &swap_inode, MAGIC_FILE_P );
 	p->max = SWAP_NR(swap_end);
-
-	/* initialize lockmap */
-	memset( p->swap_lockmap, 0, PAGE_SIZE );
 
 	/* initialize swap_map: set regions that are already allocated or belong
 	 * to kernel data space to SWAP_MAP_BAD, otherwise to free */
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c
--- v2.3.12/linux/arch/m68k/bvme6000/config.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/bvme6000/config.c	Mon Aug  9 12:27:30 1999
@@ -14,7 +14,6 @@
  * for more details.
  */
 
-#include <stdarg.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.3.12/linux/arch/m68k/config.in	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/config.in	Mon Aug  9 12:27:30 1999
@@ -100,7 +100,7 @@
 bool '/proc/hardware support' CONFIG_PROC_HARDWARE
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT
+  tristate 'Parallel port support (EXPERIMENTAL)' CONFIG_PARPORT
   if [ "$CONFIG_PARPORT" != "n" ]; then
     if [ "$CONFIG_AMIGA" != "n" ]; then
       dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
@@ -118,6 +118,10 @@
   if [ "$CONFIG_ATARI" == "y" ]; then
     dep_tristate '    Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
   fi
+  dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+  if [ "$CONFIG_PRINTER" != "n" ]; then
+    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+  fi
 fi
 
 
@@ -318,25 +322,23 @@
   define_bool CONFIG_NVRAM y
 fi
 
-if [ "$CONFIG_PARPORT" = "n" ]; then
-  tristate 'Parallel printer support' CONFIG_M68K_PRINTER
-  if [ "$CONFIG_ZORRO" = "y" ]; then
-    dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
-  fi
-else
-  dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
-  if [ "$CONFIG_PRINTER" != "n" ]; then
-    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
-  fi
-fi   
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
+  if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then
+    define_bool CONFIG_MOUSE y
+  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari mouse support' CONFIG_ATARIMOUSE
+  if [ "$CONFIG_ATARIMOUSE" != "n" ]; then
+    define_bool CONFIG_MOUSE y
+  fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
    bool 'Mac ADB mouse support' CONFIG_ADBMOUSE
+  if [ "$CONFIG_ADBMOUSE" != "n" ]; then
+    define_bool CONFIG_MOUSE y
+  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
@@ -374,6 +376,9 @@
   if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
     bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
     bool 'Sun mouse support' CONFIG_SUN_MOUSE
+    if [ "$CONFIG_SUN_MOUSE" != "n" ]; then
+      define_bool CONFIG_MOUSE y
+    fi
     define_bool CONFIG_SBUS y
     define_bool CONFIG_SBUSCHAR y
     define_bool CONFIG_SUN_SERIAL y
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.3.12/linux/arch/m68k/kernel/entry.S	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/kernel/entry.S	Mon Aug  9 12:27:30 1999
@@ -67,7 +67,7 @@
 
 ENTRY(reschedule)
 	| save top of frame
-	movel	%sp,%curptr@(TASK_TSS+TSS_ESP0)
+	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
 
 	pea	SYMBOL_NAME(ret_from_exception)
 	jmp	SYMBOL_NAME(schedule)
@@ -89,6 +89,16 @@
 	SAVE_SWITCH_STACK
 	jbsr	SYMBOL_NAME(syscall_trace)
 
+	| After a fork we jump here directly from resume,
+	| so that %d1 contains the previous task
+	| Theoretically only needed on SMP, but let's watch
+	| what happens in schedule_tail() in future...
+ENTRY(ret_from_fork)
+	movel	%d1,%sp@-
+	jsr	SYMBOL_NAME(schedule_tail)
+	addql	#4,%sp
+	jra	SYMBOL_NAME(ret_from_exception)
+
 SYMBOL_NAME_LABEL(ret_from_signal)
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
@@ -100,7 +110,7 @@
 
 	GET_CURRENT(%d0)
 	| save top of frame
-	movel	%sp,%curptr@(TASK_TSS+TSS_ESP0)
+	movel	%sp,%curptr@(TASK_THREAD+THREAD_ESP0)
 
 	cmpl	#NR_syscalls,%d2
 	jcc	badsys
@@ -118,8 +128,10 @@
 	andw	#ALLOWINT,%sr
 	tstl	%curptr@(TASK_NEEDRESCHED)
 	jne	SYMBOL_NAME(reschedule)
+#if 0
 	cmpl	#SYMBOL_NAME(task),%curptr	| task[0] cannot have signals
 	jeq	2f
+#endif
 					| check for delayed trace
 	bclr	#PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF)
 	jne	do_delayed_trace
@@ -265,25 +277,25 @@
 	 */
 
 	/* save sr */
-	movew	%sr,%a0@(TASK_TSS+TSS_SR)
+	movew	%sr,%a0@(TASK_THREAD+THREAD_SR)
 
 	/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
 	movec	%sfc,%d0
-	movew	%d0,%a0@(TASK_TSS+TSS_FS)
+	movew	%d0,%a0@(TASK_THREAD+THREAD_FS)
 
 	/* save usp */
 	/* it is better to use a movel here instead of a movew 8*) */
 	movec	%usp,%d0
-	movel	%d0,%a0@(TASK_TSS+TSS_USP)
+	movel	%d0,%a0@(TASK_THREAD+THREAD_USP)
 
 	/* save non-scratch registers on stack */
 	SAVE_SWITCH_STACK
 
 	/* save current kernel stack pointer */
-	movel	%sp,%a0@(TASK_TSS+TSS_KSP)
+	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP)
 
 	/* save floating point context */
-	fsave	%a0@(TASK_TSS+TSS_FPSTATE)
+	fsave	%a0@(TASK_THREAD+THREAD_FPSTATE)
 
 #if defined(CONFIG_M68060)
 #if !defined(CPU_M68060_ONLY)
@@ -291,18 +303,18 @@
 	beqs	1f
 #endif
 	/* The 060 FPU keeps status in bits 15-8 of the first longword */
-	tstb	%a0@(TASK_TSS+TSS_FPSTATE+2)
+	tstb	%a0@(TASK_THREAD+THREAD_FPSTATE+2)
 	jeq	3f
 #if !defined(CPU_M68060_ONLY)
 	jra	2f
 #endif
 #endif /* CONFIG_M68060 */
 #if !defined(CPU_M68060_ONLY)
-1:	tstb	%a0@(TASK_TSS+TSS_FPSTATE)
+1:	tstb	%a0@(TASK_THREAD+THREAD_FPSTATE)
 	jeq	3f
 #endif
-2:	fmovemx	%fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
-	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
+2:	fmovemx	%fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
+	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
 3:
 	/* Return previous task in %d1 */
 	movel	%curptr,%d1
@@ -310,69 +322,6 @@
 	/* switch to new task (a1 contains new task) */
 	movel	%a1,%curptr
 
-	/* Skip address space switching if they are the same. */
-	movel	%a0@(TASK_MM),%d0
-	cmpl	%a1@(TASK_MM),%d0
-	jeq	4f
-
-#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
-	/* 68040 or 68060 ? */
-	tstl	SYMBOL_NAME(m68k_is040or060)
-	bnes	1f
-#endif
-#if defined(CPU_M68020_OR_M68030)
-	/*
-	 * switch address space
-	 */
-
-	/* flush MC68030/MC68020 caches (they are virtually addressed) */
-	movec	%cacr,%d0
-	oriw	#LFLUSH_I_AND_D,%d0
-	movec	%d0,%cacr
-
-	/* switch the root pointer */
-#ifdef CPU_M68030_ONLY
-	.chip	68030
-	pmovefd	%a1@(TASK_TSS+TSS_CRP),%crp
-	.chip	68k
-	pflush	#0,#4
-#else
-	pmove	%a1@(TASK_TSS+TSS_CRP),%crp
-#endif
-#endif
-
-#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
-	jra	2f	/* skip m68040 stuff */
-1:
-#endif
-#if defined(CPU_M68040_OR_M68060)
-	/*
-	 * switch address space
-	 */
-	.chip	68040
-
-	/* flush address translation cache (user entries) */
-	pflushan
-
-	/* switch the root pointer */
-	movel	%a1@(TASK_TSS+TSS_CRP+4),%d0
-	movec	%d0,%urp
-
-#if defined (CONFIG_M68060)
-	/* is it a '060 ? */
-#if !defined(CPU_M68060_ONLY)
-	btst	#3,SYMBOL_NAME(m68k_cputype)+3
-	beqs	2f
-#endif
-	/* clear user entries in the branch cache */
-	movec	%cacr,%d0
-	orl	#0x00200000,%d0
-	movec	%d0,%cacr
-#endif /* CONFIG_M68060 */
-	.chip	68k
-#endif /* CPU_M68040_OR_M68060 */
-2:
-4:
 	/* restore floating point context */
 
 #if defined(CONFIG_M68060)
@@ -381,37 +330,37 @@
 	beqs	1f
 #endif
 	/* The 060 FPU keeps status in bits 15-8 of the first longword */
-	tstb	%a1@(TASK_TSS+TSS_FPSTATE+2)
+	tstb	%a1@(TASK_THREAD+THREAD_FPSTATE+2)
 	jeq	3f
 #if !defined(CPU_M68060_ONLY)
 	jra	2f
 #endif
 #endif /* CONFIG_M68060 */
 #if !defined(CPU_M68060_ONLY)
-1:	tstb	%a1@(TASK_TSS+TSS_FPSTATE)
+1:	tstb	%a1@(TASK_THREAD+THREAD_FPSTATE)
 	jeq	3f
 #endif	
-2:	fmovemx	%a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7
-	fmoveml	%a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar
-3:	frestore %a1@(TASK_TSS+TSS_FPSTATE)
+2:	fmovemx	%a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
+	fmoveml	%a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
+3:	frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
 
 	/* restore the kernel stack pointer */
-	movel	%a1@(TASK_TSS+TSS_KSP),%sp
+	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp
 
 	/* restore non-scratch registers */
 	RESTORE_SWITCH_STACK
 
 	/* restore user stack pointer */
-	movel	%a1@(TASK_TSS+TSS_USP),%a0
+	movel	%a1@(TASK_THREAD+THREAD_USP),%a0
 	movel	%a0,%usp
 
 	/* restore fs (sfc,%dfc) */
-	movew	%a1@(TASK_TSS+TSS_FS),%a0
+	movew	%a1@(TASK_THREAD+THREAD_FS),%a0
 	movec	%a0,%sfc
 	movec	%a0,%dfc
 
 	/* restore status register */
-	movew	%a1@(TASK_TSS+TSS_SR),%sr
+	movew	%a1@(TASK_THREAD+THREAD_SR),%sr
 
 	rts
 
@@ -530,7 +479,7 @@
 	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* iopl for i386 */ /* 110 */
 	.long SYMBOL_NAME(sys_vhangup)
-	.long SYMBOL_NAME(sys_idle)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* obsolete idle() syscall */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* vm86old for i386 */
 	.long SYMBOL_NAME(sys_wait4)
 	.long SYMBOL_NAME(sys_swapoff)		/* 115 */
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/m68k_defs.c linux/arch/m68k/kernel/m68k_defs.c
--- v2.3.12/linux/arch/m68k/kernel/m68k_defs.c	Tue Jan 19 10:58:26 1999
+++ linux/arch/m68k/kernel/m68k_defs.c	Mon Aug  9 12:27:30 1999
@@ -26,25 +26,34 @@
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending));
 	DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched));
-	DEFINE(TASK_TSS, offsetof(struct task_struct, tss));
+	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
 	/* offsets into the thread struct */
-	DEFINE(TSS_KSP, offsetof(struct thread_struct, ksp));
-	DEFINE(TSS_USP, offsetof(struct thread_struct, usp));
-	DEFINE(TSS_SR, offsetof(struct thread_struct, sr));
-	DEFINE(TSS_FS, offsetof(struct thread_struct, fs));
-	DEFINE(TSS_CRP, offsetof(struct thread_struct, crp));
-	DEFINE(TSS_ESP0, offsetof(struct thread_struct, esp0));
-	DEFINE(TSS_FPREG, offsetof(struct thread_struct, fp));
-	DEFINE(TSS_FPCNTL, offsetof(struct thread_struct, fpcntl));
-	DEFINE(TSS_FPSTATE, offsetof(struct thread_struct, fpstate));
+	DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+	DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+	DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+	DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+	DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+	DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+	DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+	DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+	DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
 
 	/* offsets into the pt_regs */
 	DEFINE(PT_D0, offsetof(struct pt_regs, d0));
 	DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+	DEFINE(PT_D1, offsetof(struct pt_regs, d1));
+	DEFINE(PT_D2, offsetof(struct pt_regs, d2));
+	DEFINE(PT_D3, offsetof(struct pt_regs, d3));
+	DEFINE(PT_D4, offsetof(struct pt_regs, d4));
+	DEFINE(PT_D5, offsetof(struct pt_regs, d5));
+	DEFINE(PT_A0, offsetof(struct pt_regs, a0));
+	DEFINE(PT_A1, offsetof(struct pt_regs, a1));
+	DEFINE(PT_A2, offsetof(struct pt_regs, a2));
+	DEFINE(PT_PC, offsetof(struct pt_regs, pc));
 	DEFINE(PT_SR, offsetof(struct pt_regs, sr));
-
 	/* bitfields are a bit difficult */
 	DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
 
@@ -68,6 +77,12 @@
 	DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height));
 	DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data));
 	DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref));
+
+	/* signal defines */
+	DEFINE(SIGSEGV, SIGSEGV);
+	DEFINE(SEGV_MAPERR, SEGV_MAPERR);
+	DEFINE(SIGTRAP, SIGTRAP);
+	DEFINE(TRAP_TRACE, TRAP_TRACE);
 
 	/* offsets into the custom struct */
 	DEFINE(CUSTOMBASE, &custom);
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.3.12/linux/arch/m68k/kernel/m68k_ksyms.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Mon Aug  9 12:27:30 1999
@@ -55,8 +55,6 @@
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_set_cachemode);
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(register_serial);
-EXPORT_SYMBOL(unregister_serial);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.3.12/linux/arch/m68k/kernel/process.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/m68k/kernel/process.c	Mon Aug  9 12:27:30 1999
@@ -45,35 +45,47 @@
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 union task_union init_task_union
-	__attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
-	= { task: INIT_TASK };
+__attribute__((section("init_task"), aligned(THREAD_SIZE)))
+	= { task: INIT_TASK(init_task_union.task) };
+
+asmlinkage void ret_from_fork(void);
 
-asmlinkage void ret_from_exception(void);
 
 /*
  * The idle loop on an m68k..
  */
-asmlinkage int sys_idle(void)
+static void default_idle(void)
 {
-	if (current->pid != 0)
-		return -EPERM;
-
-	/* endless idle loop with no priority at all */
-	current->priority = 0;
-	current->counter = -100;
-	for (;;) {
+	while(1) {
 		if (!current->need_resched)
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+#ifdef MACH_ATARI_ONLY
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
-#else /* portable version */
+#else
 			__asm__("stop #0x2000" : : : "cc");
-#endif /* machine compilation types */ 
+#endif
 		schedule();
 		check_pgt_cache();
 	}
 }
 
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+	/* endless idle loop with no priority at all */
+	init_idle();
+	current->priority = 0;
+	current->counter = -100;
+	idle();
+}
+
 void machine_restart(char * __unused)
 {
 	if (mach_reset)
@@ -148,7 +160,7 @@
 {
 	unsigned long zero = 0;
 	set_fs(USER_DS);
-	current->tss.fs = __USER_DS;
+	current->thread.fs = __USER_DS;
 	asm volatile (".chip 68k/68881\n\t"
 		      "frestore %0@\n\t"
 		      ".chip 68k" : : "a" (&zero));
@@ -191,7 +203,7 @@
 	struct switch_stack * childstack, *stack;
 	unsigned long stack_offset, *retp;
 
-	stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs);
+	stack_offset = THREAD_SIZE - sizeof(struct pt_regs);
 	childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
 
 	*childregs = *regs;
@@ -202,26 +214,26 @@
 
 	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
-	childstack->retpc = (unsigned long) ret_from_exception;
+	childstack->retpc = (unsigned long)ret_from_fork;
 
-	p->tss.usp = usp;
-	p->tss.ksp = (unsigned long)childstack;
+	p->thread.usp = usp;
+	p->thread.ksp = (unsigned long)childstack;
 	/*
 	 * Must save the current SFC/DFC value, NOT the value when
 	 * the parent was last descheduled - RGH  10-08-96
 	 */
-	p->tss.fs = get_fs().seg;
+	p->thread.fs = get_fs().seg;
 
 	/* Copy the current fpu state */
-	asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
+	asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
 
-	if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2])
+	if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
 	  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
 			"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-			: : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0])
+			: : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
 			: "memory");
 	/* Restore the state in case the fpu was busy */
-	asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0]));
+	asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
 
 	return 0;
 }
@@ -230,7 +242,7 @@
 
 int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 {
-  char fpustate[216];
+	char fpustate[216];
 
   /* First dump the fpu context to avoid protocol violation.  */
   asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.3.12/linux/arch/m68k/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
+++ linux/arch/m68k/kernel/ptrace.c	Mon Aug  9 12:27:30 1999
@@ -37,7 +37,7 @@
 /* sets the trace bits. */
 #define TRACE_BITS 0x8000
 
-/* Find the stack offset for a register, relative to tss.esp0. */
+/* Find the stack offset for a register, relative to thread.esp0. */
 #define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
 #define SW_REG(reg)	((long)&((struct switch_stack *)0)->reg \
 			 - sizeof(struct switch_stack))
@@ -60,9 +60,9 @@
 	unsigned long *addr;
 
 	if (regno == PT_USP)
-		addr = &task->tss.usp;
+		addr = &task->thread.usp;
 	else if (regno < sizeof(regoff)/sizeof(regoff[0]))
-		addr = (unsigned long *)(task->tss.esp0 + regoff[regno]);
+		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
 	else
 		return 0;
 	return *addr;
@@ -77,9 +77,9 @@
 	unsigned long *addr;
 
 	if (regno == PT_USP)
-		addr = &task->tss.usp;
+		addr = &task->thread.usp;
 	else if (regno < sizeof(regoff)/sizeof(regoff[0]))
-		addr = (unsigned long *) (task->tss.esp0 + regoff[regno]);
+		addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
 	else
 		return -1;
 	*addr = data;
@@ -386,7 +386,7 @@
 					tmp >>= 16;
 			}
 			else if (addr >= 21 && addr < 49)
-				tmp = child->tss.fp[addr - 21];
+				tmp = child->thread.fp[addr - 21];
 			else
 				goto out;
 			ret = put_user(tmp,(unsigned long *) data);
@@ -423,7 +423,7 @@
 			}
 			if (addr >= 21 && addr < 48)
 			{
-				child->tss.fp[addr - 21] = data;
+				child->thread.fp[addr - 21] = data;
 				ret = 0;
 			}
 			goto out;
@@ -544,7 +544,7 @@
 
 		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
 			ret = 0;
-			if (copy_to_user((void *)data, &child->tss.fp,
+			if (copy_to_user((void *)data, &child->thread.fp,
 					 sizeof(struct user_m68kfp_struct)))
 				ret = -EFAULT;
 			goto out;
@@ -552,7 +552,7 @@
 
 		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
 			ret = 0;
-			if (copy_from_user(&child->tss.fp, (void *)data,
+			if (copy_from_user(&child->thread.fp, (void *)data,
 					   sizeof(struct user_m68kfp_struct)))
 				ret = -EFAULT;
 			goto out;
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.3.12/linux/arch/m68k/kernel/signal.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/m68k/kernel/signal.c	Mon Aug  9 12:27:30 1999
@@ -156,6 +156,9 @@
 
 /*
  * Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
  */
 
 struct sigframe
@@ -175,9 +178,9 @@
 	int sig;
 	struct siginfo *pinfo;
 	void *puc;
+	char retcode[8];
 	struct siginfo info;
 	struct ucontext uc;
-	char retcode[8];
 };
 
 
@@ -478,7 +481,7 @@
 	struct switch_stack *sw = (struct switch_stack *) &__unused;
 	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 	unsigned long usp = rdusp();
-	struct sigframe *frame = (struct sigframe *)(usp - 24);
+	struct sigframe *frame = (struct sigframe *)(usp - 4);
 	sigset_t set;
 	int d0;
 
@@ -677,25 +680,6 @@
 				      "cpushl %%bc,(%0)\n\t"
 				      ".chip 68k"
 				      : : "a" (temp));
-		if (((vaddr + 8) ^ vaddr) & ~15) {
-			if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
-				__asm__ __volatile__ (".chip 68040\n\t"
-						      "nop\n\t"
-						      "ptestr (%1)\n\t"
-						      "movec %%mmusr,%0\n\t"
-						      ".chip 68k"
-						      : "=r" (temp)
-						      : "a" (vaddr + 8));
-
-			temp &= PAGE_MASK;
-			temp |= (vaddr + 8) & ~PAGE_MASK;
-
-			__asm__ __volatile__ (".chip 68040\n\t"
-					      "nop\n\t"
-					      "cpushl %%bc,(%0)\n\t"
-					      ".chip 68k"
-					      : : "a" (temp));
-		}
 	}
 	else if (CPU_IS_060) {
 		unsigned long temp;
@@ -708,18 +692,6 @@
 				      "cpushl %%bc,(%0)\n\t"
 				      ".chip 68k"
 				      : : "a" (temp));
-		if (((vaddr + 8) ^ vaddr) & ~15) {
-			if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
-				__asm__ __volatile__ (".chip 68060\n\t"
-						      "plpar (%0)\n\t"
-						      ".chip 68k"
-						      : "=a" (temp)
-						      : "0" (vaddr + 8));
-			__asm__ __volatile__ (".chip 68060\n\t"
-					      "cpushl %%bc,(%0)\n\t"
-					      ".chip 68k"
-					      : : "a" (temp));
-		}
 	}
 	else {
 		/*
@@ -797,11 +769,9 @@
 
 	/* Set up to return from userspace.  */
 	err |= __put_user(frame->retcode, &frame->pretcode);
-	/* addaw #20,sp */
-	err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0));
 	/* moveq #,d0; trap #0 */
 	err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
-			  (long *)(frame->retcode + 4));
+			  (long *)(frame->retcode));
 
 	if (err)
 		goto give_sigsegv;
@@ -881,10 +851,10 @@
 
 	/* Set up to return from userspace.  */
 	err |= __put_user(frame->retcode, &frame->pretcode);
-	/* movel #,d0; trap #0 */
-	err |= __put_user(0x203c, (short *)(frame->retcode + 0));
-	err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
-	err |= __put_user(0x4e40, (short *)(frame->retcode + 6));
+	/* moveq #,d0; notb d0; trap #0 */
+	err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
+			  (long *)(frame->retcode + 0));
+	err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
 
 	if (err)
 		goto give_sigsegv;
@@ -964,11 +934,10 @@
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+	sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+	if (!(ka->sa.sa_flags & SA_NODEFER))
 		sigaddset(&current->blocked,sig);
-		recalc_sigpending(current);
-	}
+	recalc_sigpending(current);
 }
 
 /*
@@ -985,7 +954,7 @@
 	siginfo_t info;
 	struct k_sigaction *ka;
 
-	current->tss.esp0 = (unsigned long) regs;
+	current->thread.esp0 = (unsigned long) regs;
 
 	if (!oldset)
 		oldset = &current->blocked;
@@ -1090,6 +1059,7 @@
 
 			default:
 				sigaddset(&current->signal, signr);
+				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
 				do_exit(exit_code);
 				/* NOTREACHED */
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.3.12/linux/arch/m68k/kernel/traps.c	Mon Oct  5 13:54:39 1998
+++ linux/arch/m68k/kernel/traps.c	Mon Aug  9 12:27:30 1999
@@ -648,7 +648,7 @@
 {
 	/* Only set esp0 if coming from user mode */
 	if (user_mode(&fp->ptregs))
-		current->tss.esp0 = (unsigned long) fp;
+		current->thread.esp0 = (unsigned long) fp;
 
 #if DEBUG
 	printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c
--- v2.3.12/linux/arch/m68k/mac/adb-bus.c	Sat May 15 15:05:35 1999
+++ linux/arch/m68k/mac/adb-bus.c	Mon Aug  9 12:27:30 1999
@@ -13,7 +13,6 @@
  *	MSch (1/98) Integrated start of IIsi driver by Robert Thompson
  */
  
-#include <stdarg.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.3.12/linux/arch/m68k/mm/fault.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/m68k/mm/fault.c	Mon Aug  9 12:27:30 1999
@@ -36,7 +36,7 @@
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct * vma;
 	unsigned long fixup;
-	int write;
+	int write, fault;
 
 #ifdef DEBUG
 	printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
@@ -44,7 +44,6 @@
 		current->mm->pgd);
 #endif
 
-
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
@@ -100,7 +99,10 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	if (!handle_mm_fault(current, vma, address, write))
+	fault = handle_mm_fault(current, vma, address, write);
+	if (fault < 0)
+		goto out_of_memory;
+	if (!fault)
 		goto do_sigbus;
 
 	/* There seems to be a missing invalidate somewhere in do_no_page.
@@ -160,6 +162,13 @@
  * We ran out of memory, or some other thing happened to us that made
  * us unable to handle the page fault gracefully.
  */
+out_of_memory:
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", current->comm);
+	if (error_code & 4)
+		do_exit(SIGKILL);
+	goto no_context;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.3.12/linux/arch/m68k/mm/init.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/m68k/mm/init.c	Mon Aug  9 12:27:30 1999
@@ -28,8 +28,6 @@
 #include <asm/atari_stram.h>
 #endif
 
-#undef DEBUG
-
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
@@ -94,12 +92,12 @@
 	    reserved++;
 	else if (PageSwapCache(mem_map+i))
 	    cached++;
-	else if (!atomic_read(&mem_map[i].count))
+	else if (!page_count(mem_map+i))
 	    free++;
-	else if (atomic_read(&mem_map[i].count) == 1)
+	else if (page_count(mem_map+i) == 1)
 	    nonshared++;
 	else
-	    shared += atomic_read(&mem_map[i].count) - 1;
+	    shared += page_count(mem_map+i) - 1;
     }
     printk("%d pages of RAM\n",total);
     printk("%d free pages\n",free);
@@ -138,6 +136,7 @@
 }
 
 static pmd_t *last_pgtable __initdata = NULL;
+static pmd_t *zero_pgtable __initdata = NULL;
 
 __initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp))
 {
@@ -183,7 +182,7 @@
 {
 #define PTRTREESIZE (256*1024)
 #define ROOTTREESIZE (32*1024*1024)
-	static unsigned long virtaddr = 0;
+	static unsigned long virtaddr = PAGE_OFFSET;
 	unsigned long physaddr;
 	pgd_t *pgd_dir;
 	pmd_t *pmd_dir;
@@ -235,7 +234,8 @@
 #ifdef DEBUG
 				printk ("[zero map]");
 #endif
-				pte_dir = (pte_t *)kernel_ptr_table(memavailp);
+				zero_pgtable = kernel_ptr_table(memavailp);
+				pte_dir = (pte_t *)zero_pgtable;
 				pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
 					_PAGE_TABLE | _PAGE_ACCESSED;
 				pte_val(*pte_dir++) = 0;
@@ -352,38 +352,6 @@
 	start_mem += PAGE_SIZE;
 	memset((void *)empty_zero_page, 0, PAGE_SIZE);
 
-	/* 
-	 * allocate the "swapper" page directory and
-	 * record in task 0 (swapper) tss 
-	 */
-	init_mm.pgd = (pgd_t *)kernel_ptr_table(&start_mem);
-	memset (init_mm.pgd, 0, sizeof(pgd_t)*PTRS_PER_PGD);
-
-	/* setup CPU root pointer for swapper task */
-	task[0]->tss.crp[0] = 0x80000000 | _PAGE_TABLE;
-	task[0]->tss.crp[1] = virt_to_phys(init_mm.pgd);
-
-#ifdef DEBUG
-	printk ("task 0 pagedir at %p virt, %#lx phys\n",
-		swapper_pg_dir, task[0]->tss.crp[1]);
-#endif
-
-	if (CPU_IS_040_OR_060)
-		asm __volatile__ (".chip 68040\n\t"
-				  "movec %0,%%urp\n\t"
-				  ".chip 68k"
-				  : /* no outputs */
-				  : "r" (task[0]->tss.crp[1]));
-	else
-		asm __volatile__ (".chip 68030\n\t"
-				  "pmove %0,%%crp\n\t"
-				  ".chip 68k"
-				  : /* no outputs */
-				  : "m" (task[0]->tss.crp[0]));
-#ifdef DEBUG
-	printk ("set crp\n");
-#endif
-
 	/*
 	 * Set up SFC/DFC registers (user data space)
 	 */
@@ -418,7 +386,7 @@
 		atari_stram_reserve_pages( start_mem );
 #endif
 
-	for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) {
+	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (virt_to_phys ((void *)tmp) >= mach_max_dma_address)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
@@ -435,7 +403,7 @@
 				datapages++;
 			continue;
 		}
-		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
+		set_page_count(mem_map+MAP_NR(tmp), 1);
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start ||
 		    (tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end))
@@ -450,6 +418,10 @@
 			init_pointer_table(pgd_page(kernel_pg_dir[i]));
 	}
 
+	/* insert also pointer table that we used to unmap the zero page */
+	if (zero_pgtable)
+		init_pointer_table((unsigned long)zero_pgtable);
+
 	printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
 	       (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
 	       max_mapnr << (PAGE_SHIFT-10),
@@ -465,7 +437,7 @@
 	addr = (unsigned long)&__init_begin;
 	for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+		set_page_count(mem_map+MAP_NR(addr), 1);
 		free_page(addr);
 	}
 }
@@ -483,9 +455,9 @@
 	if (PageReserved(mem_map+i))
 	    continue;
 	val->totalram++;
-	if (!atomic_read(&mem_map[i].count))
+	if (!page_count(mem_map+i))
 	    continue;
-	val->sharedram += atomic_read(&mem_map[i].count) - 1;
+	val->sharedram += page_count(mem_map+i) - 1;
     }
     val->totalram <<= PAGE_SHIFT;
     val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.3.12/linux/arch/m68k/mm/memory.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/mm/memory.c	Mon Aug  9 12:27:30 1999
@@ -227,31 +227,33 @@
     /* address match? */
     base = regval & 0xff000000;
     mask = ~(regval << 8) & 0xff000000;
-    return ((vaddr ^ base) & mask) == 0;
+    return (((unsigned long)vaddr ^ base) & mask) == 0;
 }
 
+#if DEBUG_INVALID_PTOV
+int mm_inv_cnt = 5;
+#endif
+
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
 /*
  * The following two routines map from a physical address to a kernel
  * virtual address and vice versa.
  */
-unsigned long mm_vtop (unsigned long vaddr)
+unsigned long mm_vtop(unsigned long vaddr)
 {
 	int i=0;
-	unsigned long voff = vaddr;
-	unsigned long offset = 0;
+	unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
 
-	do{
-		if (voff < offset + m68k_memory[i].size) {
+	do {
+		if (voff < m68k_memory[i].size) {
 #ifdef DEBUGPV
-			printk ("VTOP(%lx)=%lx\n", vaddr,
-				m68k_memory[i].addr + voff - offset);
+			printk ("VTOP(%p)=%lx\n", vaddr,
+				m68k_memory[i].addr + voff);
 #endif
-			return m68k_memory[i].addr + voff - offset;
-		} else
-			offset += m68k_memory[i].size;
-		i++;
-	}while (i < m68k_num_memory);
+			return m68k_memory[i].addr + voff;
+		}
+		voff -= m68k_memory[i].size;
+	} while (++i < m68k_num_memory);
 
 	return mm_vtop_fallback(vaddr);
 }
@@ -259,7 +261,7 @@
 
 /* Separate function to make the common case faster (needs to save less
    registers) */
-unsigned long mm_vtop_fallback (unsigned long vaddr)
+unsigned long mm_vtop_fallback(unsigned long vaddr)
 {
 	/* not in one of the memory chunks; test for applying transparent
 	 * translation */
@@ -272,13 +274,13 @@
 			  ".chip 68k"
 			  : : "a" (&ttreg) );
 	    if (transp_transl_matches( ttreg, vaddr ))
-		return vaddr;
+		return (unsigned long)vaddr;
 	    asm volatile( ".chip 68030\n\t"
 			  "pmove %/tt1,%0@\n\t"
 			  ".chip 68k"
 			  : : "a" (&ttreg) );
 	    if (transp_transl_matches( ttreg, vaddr ))
-		return vaddr;
+		return (unsigned long)vaddr;
 	}
 	else if (CPU_IS_040_OR_060) {
 	    unsigned long ttreg;
@@ -288,13 +290,13 @@
 			  ".chip 68k"
 			  : "=d" (ttreg) );
 	    if (transp_transl_matches( ttreg, vaddr ))
-		return vaddr;
+		return (unsigned long)vaddr;
 	    asm volatile( ".chip 68040\n\t"
 			  "movec %%dtt1,%0\n\t"
 			  ".chip 68k"
 			  : "=d" (ttreg) );
 	    if (transp_transl_matches( ttreg, vaddr ))
-		return vaddr;
+		return (unsigned long)vaddr;
 	}
 
 	/* no match, too, so get the actual physical address from the MMU. */
@@ -306,11 +308,21 @@
 	  set_fs (MAKE_MM_SEG(SUPER_DATA));
 
 	  /* The PLPAR instruction causes an access error if the translation
-	   * is not possible. We don't catch that here, so a bad kernel trap
-	   * will be reported in this case. */
-	  asm volatile (".chip 68060\n\t"
-			"plpar (%0)\n\t"
-			".chip 68k"
+	   * is not possible. To catch this we use the same exception mechanism
+	   * as for user space accesses in <asm/uaccess.h>. */
+	  asm volatile (".chip 68060\n"
+			"1: plpar (%0)\n"
+			".chip 68k\n"
+			"2:\n"
+			".section .fixup,\"ax\"\n"
+			"   .even\n"
+			"3: lea -1,%0\n"
+			"   jra 2b\n"
+			".previous\n"
+			".section __ex_table,\"a\"\n"
+			"   .align 4\n"
+			"   .long 1b,3b\n"
+			".previous"
 			: "=a" (paddr)
 			: "0" (vaddr));
 	  set_fs (fs);
@@ -332,12 +344,13 @@
 	  set_fs (fs);
 
 	  if (mmusr & MMU_T_040) {
-	    return (vaddr);	/* Transparent translation */
+	    return (unsigned long)vaddr;	/* Transparent translation */
 	  }
 	  if (mmusr & MMU_R_040)
-	    return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+	    return (mmusr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
 
-	  panic ("VTOP040: bad virtual address %08lx (%lx)", vaddr, mmusr);
+	  printk("VTOP040: bad virtual address %lx (%lx)", vaddr, mmusr);
+	  return -1;
 	} else {
 	  volatile unsigned short temp;
 	  unsigned short mmusr;
@@ -350,46 +363,51 @@
 	  mmusr = temp;
 
 	  if (mmusr & (MMU_I|MMU_B|MMU_L))
-	    panic ("VTOP030: bad virtual address %08lx (%x)", vaddr, mmusr);
+	    printk("VTOP030: bad virtual address %lx (%x)\n", vaddr, mmusr);
 
 	  descaddr = phys_to_virt((unsigned long)descaddr);
 
 	  switch (mmusr & MMU_NUM) {
 	  case 1:
-	    return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+	    return (*descaddr & 0xfe000000) | ((unsigned long)vaddr & 0x01ffffff);
 	  case 2:
-	    return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+	    return (*descaddr & 0xfffc0000) | ((unsigned long)vaddr & 0x0003ffff);
 	  case 3:
-	    return (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+	    return (*descaddr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
 	  default:
-	    panic ("VTOP: bad levels (%u) for virtual address %08lx", 
+	    printk("VTOP: bad levels (%u) for virtual address %lx\n", 
 		   mmusr & MMU_NUM, vaddr);
 	  }
 	}
 
-	panic ("VTOP: bad virtual address %08lx", vaddr);
+	printk("VTOP: bad virtual address %lx\n", vaddr);
+	return -1;
 }
 
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
-unsigned long mm_ptov (unsigned long paddr)
+void *mm_ptov (unsigned long paddr)
 {
 	int i = 0;
-	unsigned long offset = 0;
+	unsigned long poff, voff = PAGE_OFFSET;
 
-	do{
-		if (paddr >= m68k_memory[i].addr &&
-		    paddr < (m68k_memory[i].addr
-			     + m68k_memory[i].size)) {
+	do {
+		poff = paddr - m68k_memory[i].addr;
+		if (poff < m68k_memory[i].size) {
 #ifdef DEBUGPV
-			printk ("PTOV(%lx)=%lx\n", paddr,
-				(paddr - m68k_memory[i].addr) + offset);
+			printk ("PTOV(%lx)=%lx\n", paddr, poff + voff);
+#endif
+			return (void *)(poff + voff);
+		}
+		voff += m68k_memory[i].size;
+	} while (++i < m68k_num_memory);
+
+#if DEBUG_INVALID_PTOV
+	if (mm_inv_cnt > 0) {
+		mm_inv_cnt--;
+		printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n",
+			paddr, __builtin_return_address(0));
+	}
 #endif
-			return (paddr - m68k_memory[i].addr) + offset;
-		} else
-			offset += m68k_memory[i].size;
-		i++;
-	}while (i < m68k_num_memory);
-
 	/*
 	 * assume that the kernel virtual address is the same as the
 	 * physical address.
@@ -411,9 +429,9 @@
 	 * to the ZTWO_VADDR range
 	 */
 	if (MACH_IS_AMIGA && paddr < 16*1024*1024)
-		return ZTWO_VADDR(paddr);
+		return (void *)ZTWO_VADDR(paddr);
 #endif
-	return paddr;
+	return (void *)-1;
 }
 #endif
 
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- v2.3.12/linux/arch/m68k/mvme147/config.c	Wed May 12 08:50:00 1999
+++ linux/arch/m68k/mvme147/config.c	Mon Aug  9 12:27:30 1999
@@ -13,7 +13,6 @@
  * for more details.
  */
 
-#include <stdarg.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- v2.3.12/linux/arch/m68k/mvme16x/config.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/mvme16x/config.c	Mon Aug  9 12:27:30 1999
@@ -15,7 +15,6 @@
  */
 
 #include <linux/config.h>
-#include <stdarg.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.3.12/linux/arch/m68k/q40/config.c	Wed May 12 08:50:00 1999
+++ linux/arch/m68k/q40/config.c	Mon Aug  9 12:27:30 1999
@@ -12,7 +12,6 @@
  * for more details.
  */
 
-#include <stdarg.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.12/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- v2.3.12/linux/arch/m68k/vmlinux.lds	Tue Jan  5 11:20:43 1999
+++ linux/arch/m68k/vmlinux.lds	Mon Aug  9 12:27:30 1999
@@ -31,22 +31,32 @@
 	CONSTRUCTORS
 	}
 
-  .bss : { *(.bss) }		/* BSS */
-
   _edata = .;			/* End of data section */
 
-  . = ALIGN(16);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  . = ALIGN(8192);
+  init_task : { *(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(8192);
   __init_end = .;
 
-  init_task : { *(init_task) }	/* The initial task and kernel stack */
+  . = ALIGN(16);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+	}
   _end = . ;
 
   /* Stabs debugging sections.  */
diff -u --recursive --new-file v2.3.12/linux/arch/mips/dec/serial.c linux/arch/mips/dec/serial.c
--- v2.3.12/linux/arch/mips/dec/serial.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/dec/serial.c	Wed Aug  4 16:36:41 1999
@@ -17,7 +17,7 @@
  */
 
 #include <linux/config.h>
-#include <asm/init.h>
+#include <linux/init.h>
 #include <asm/dec/machtype.h>
 
 #ifdef CONFIG_ZS
diff -u --recursive --new-file v2.3.12/linux/arch/mips/dec/setup.c linux/arch/mips/dec/setup.c
--- v2.3.12/linux/arch/mips/dec/setup.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/dec/setup.c	Wed Aug  4 16:36:41 1999
@@ -13,7 +13,7 @@
 #include <linux/param.h>
 #include <asm/mipsregs.h>
 #include <asm/bootinfo.h>
-#include <asm/init.h>
+#include <linux/init.h>
 #include <asm/irq.h>
 #include <asm/reboot.h>
 
diff -u --recursive --new-file v2.3.12/linux/arch/mips/dec/wbflush.c linux/arch/mips/dec/wbflush.c
--- v2.3.12/linux/arch/mips/dec/wbflush.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/dec/wbflush.c	Wed Aug  4 16:36:41 1999
@@ -14,7 +14,7 @@
  */
 
 #include <asm/bootinfo.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 static void wbflush_kn01(void);
 static void wbflush_kn210(void);
diff -u --recursive --new-file v2.3.12/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.3.12/linux/arch/ppc/kernel/apus_setup.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/ppc/kernel/apus_setup.c	Mon Aug  9 12:32:28 1999
@@ -325,11 +325,11 @@
 
 	switch (cmode)
 	{
-	case KERNELMAP_FULL_CACHING:
+	case IOMAP_FULL_CACHING:
 		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
 		flags = 0;
 		break;
-	case KERNELMAP_NOCACHE_SER:
+	case IOMAP_NOCACHE_SER:
 		mask = ~0;
 		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
 		break;
diff -u --recursive --new-file v2.3.12/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- v2.3.12/linux/arch/ppc/kernel/pmac_support.c	Sun Nov 15 10:51:43 1998
+++ linux/arch/ppc/kernel/pmac_support.c	Wed Aug  4 16:36:41 1999
@@ -5,7 +5,7 @@
 #include <linux/stddef.h>
 #include <linux/reboot.h>
 #include <linux/nvram.h>
-#include <asm/init.h>
+#include <linux/init.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.3.12/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.12/linux/arch/ppc/kernel/ppc_ksyms.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Mon Aug  9 11:39:37 1999
@@ -219,3 +219,7 @@
 
 EXPORT_SYMBOL(abs);
 EXPORT_SYMBOL(device_is_compatible);
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
+#endif
diff -u --recursive --new-file v2.3.12/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.12/linux/arch/ppc/kernel/smp.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/ppc/kernel/smp.c	Wed Aug  4 16:36:41 1999
@@ -31,7 +31,7 @@
 #include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
-#include <asm/init.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- v2.3.12/linux/arch/sparc/kernel/pcic.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/pcic.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.6 1999/06/03 15:02:18 davem Exp $
+/* $Id: pcic.c,v 1.7 1999/07/23 01:56:07 davem Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.3.12/linux/arch/sparc/kernel/process.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/process.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $
+/*  $Id: process.c,v 1.138 1999/07/23 01:56:10 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.12/linux/arch/sparc/kernel/setup.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc/kernel/setup.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.107 1999/06/03 15:02:20 davem Exp $
+/*  $Id: setup.c,v 1.108 1999/07/30 09:35:03 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.3.12/linux/arch/sparc/kernel/signal.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc/kernel/signal.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.92 1999/06/14 05:23:53 davem Exp $
+/*  $Id: signal.c,v 1.94 1999/07/30 09:35:04 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -659,6 +659,9 @@
 	
 	err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
 			      sizeof (struct reg_window));	
+
+	err |= __copy_to_user(&sf->info, info, sizeof(siginfo_t));
+
 	if (err)
 		goto sigsegv;
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c
--- v2.3.12/linux/arch/sparc/kernel/sparc-stub.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/sparc-stub.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.24 1998/02/08 07:58:44 ecd Exp $
+/* $Id: sparc-stub.c,v 1.25 1999/07/23 01:56:13 davem Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.12/linux/arch/sparc/kernel/sparc_ksyms.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.78 1999/07/23 01:56:15 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c
--- v2.3.12/linux/arch/sparc/kernel/sunos_ioctl.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/sunos_ioctl.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.33 1999/07/28 12:59:03 anton Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/file.h>
 #include <asm/kbio.h>
 
 #if 0
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.12/linux/arch/sparc/kernel/sys_sunos.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.101 1999/06/29 12:33:54 davem Exp $
+/* $Id: sys_sunos.c,v 1.102 1999/07/23 01:56:19 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S
--- v2.3.12/linux/arch/sparc/kernel/trampoline.S	Tue Apr 14 17:44:19 1998
+++ linux/arch/sparc/kernel/trampoline.S	Wed Aug  4 16:36:41 1999
@@ -1,10 +1,11 @@
-/* $Id: trampoline.S,v 1.12 1998/03/19 15:36:38 jj Exp $
+/* $Id: trampoline.S,v 1.13 1999/08/04 03:19:15 davem Exp $
  * trampoline.S: SMP cpu boot-up trampoline code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/init.h>
 #include <asm/cprefix.h>
 #include <asm/head.h>
 #include <asm/psr.h>
@@ -13,7 +14,6 @@
 #include <asm/ptrace.h>
 #include <asm/vaddrs.h>
 #include <asm/contregs.h>
-#include <asm/init.h>
 
 	.globl C_LABEL(sun4m_cpu_startup), C_LABEL(__smp4m_processor_id)
 	.globl C_LABEL(sun4d_cpu_startup), C_LABEL(__smp4d_processor_id)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/lib/debuglocks.c linux/arch/sparc/lib/debuglocks.c
--- v2.3.12/linux/arch/sparc/lib/debuglocks.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/lib/debuglocks.c	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.7 1999/04/21 02:26:58 anton Exp $
+/* $Id: debuglocks.c,v 1.8 1999/08/05 09:49:59 anton Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -53,7 +53,7 @@
 		lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
 
 	for(i = 0; i < NR_CPUS; i++)
-		printk(" reader[i]=%08lx", lock->reader_pc[i]);
+		printk(" reader[%d]=%08lx", i, lock->reader_pc[i]);
 
 	printk("\n");
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/math-emu/sfp-machine.h linux/arch/sparc/math-emu/sfp-machine.h
--- v2.3.12/linux/arch/sparc/math-emu/sfp-machine.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc/math-emu/sfp-machine.h	Mon Aug  2 22:07:16 1999
@@ -30,9 +30,12 @@
 #define _FP_WS_TYPE		signed long
 #define _FP_I_TYPE		long
 
-#define _FP_MUL_MEAT_S(R,X,Y)	_FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_D(R,X,Y)	_FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y)	_FP_MUL_MEAT_4_wide(Q,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_S(R,X,Y)					\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y)
+#define _FP_MUL_MEAT_D(R,X,Y)					\
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)					\
+  _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
 
 #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_udiv(S,R,X,Y)
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
@@ -54,7 +57,7 @@
  * CPU instruction emulation this should prefer Y.
  * (see SPAMv9 B.2.2 section).
  */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y)				\
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
   do {								\
     if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)		\
 	&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c
--- v2.3.12/linux/arch/sparc/mm/asyncd.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/mm/asyncd.c	Wed Aug  4 15:39:46 1999
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.15 1999/07/04 04:35:50 davem Exp $
+/*  $Id: asyncd.c,v 1.16 1999/08/04 03:19:16 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -271,3 +271,14 @@
 	}
 }
 
+#if CONFIG_AP1000
+
+static int __init init_ap1000(void)
+{
+	kernel_thread(asyncd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	return 0;
+}
+
+module_init(init_ap1000)
+
+#endif
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.3.12/linux/arch/sparc/mm/fault.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc/mm/fault.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.103 1999/07/04 04:35:51 davem Exp $
+/* $Id: fault.c,v 1.106 1999/07/30 09:35:07 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -382,12 +382,13 @@
 	if(expand_stack(vma, address))
 		goto bad_area;
 good_area:
-	if(write)
+	if(write) {
 		if(!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
-	else
+	} else {
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
+	}
 	if (!handle_mm_fault(current, vma, address, write))
 		goto do_sigbus;
 	up(&mm->mmap_sem);
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.12/linux/arch/sparc/mm/srmmu.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc/mm/srmmu.c	Mon Aug  9 11:29:37 1999
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.187 1999/04/28 17:00:45 davem Exp $
+/* $Id: srmmu.c,v 1.190 1999/08/07 17:47:01 anton Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -114,6 +114,7 @@
 #define srmmu_ahashfn(addr)	((addr) >> 24)
 
 int viking_mxcc_present = 0;
+static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED;
 
 /* Physical memory can be _very_ non-contiguous on the sun4m, especially
  * the SS10/20 class machines and with the latest openprom revisions.
@@ -819,7 +820,9 @@
 static void srmmu_switch_to_context(struct task_struct *tsk)
 {
 	if(tsk->mm->context == NO_CONTEXT) {
+		spin_lock(&srmmu_context_spinlock);
 		alloc_context(tsk->mm);
+		spin_unlock(&srmmu_context_spinlock);
 		ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
 	}
 	srmmu_set_context(tsk->mm->context);
@@ -827,7 +830,9 @@
 
 static void srmmu_init_new_context(struct mm_struct *mm)
 {
+	spin_lock(&srmmu_context_spinlock);
 	alloc_context(mm);
+	spin_unlock(&srmmu_context_spinlock);
 
 	flush_cache_mm(mm);
 	ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
@@ -1398,7 +1403,9 @@
 	if(tsk->mm->context == NO_CONTEXT) {
 		ctxd_t *ctxp;
 
+		spin_lock(&srmmu_context_spinlock);
 		alloc_context(tsk->mm);
+		spin_unlock(&srmmu_context_spinlock);
 		ctxp = &srmmu_context_table[tsk->mm->context];
 		srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
 		hypersparc_flush_page_to_ram((unsigned long)ctxp);
@@ -1411,7 +1418,9 @@
 {
 	ctxd_t *ctxp;
 
+	spin_lock(&srmmu_context_spinlock);
 	alloc_context(mm);
+	spin_unlock(&srmmu_context_spinlock);
 
 	ctxp = &srmmu_context_table[mm->context];
 	srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
diff -u --recursive --new-file v2.3.12/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.12/linux/arch/sparc/mm/sun4c.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc/mm/sun4c.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.173 1999/01/17 02:20:37 davem Exp $
+/* $Id: sun4c.c,v 1.175 1999/07/30 09:35:10 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.3.12/linux/arch/sparc64/Makefile	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/Makefile	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.37 1999/06/04 13:29:10 jj Exp $
+# $Id: Makefile,v 1.38 1999/08/02 12:06:06 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -15,7 +15,7 @@
 CC		:= sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
 
 CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| 	\)' > /dev/null; then echo y; else echo n; fi)
-IS_EGCS := $(shell if $(CC) -c -m64 -mcmodel=medlow -o _tmp.o arch/sparc64/math-emu/fnegq.c >/dev/null 2>&1; then echo y; else echo n; fi; rm -f _tmp.o)
+IS_EGCS := $(shell if $(CC) -c -m64 -mcmodel=medlow -o /dev/null /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 
 ifneq ($(CC_HAS_ARGS),y)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.12/linux/arch/sparc64/config.in	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/config.in	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.67 1999/05/01 09:17:37 davem Exp $
+# $Id: config.in,v 1.73 1999/08/06 12:11:47 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -36,6 +36,7 @@
 # Global things across all Sun machines.
 define_bool CONFIG_SBUS y
 define_bool CONFIG_SBUSCHAR y
+define_bool CONFIG_MOUSE y
 define_bool CONFIG_SUN_MOUSE y
 define_bool CONFIG_SERIAL y
 define_bool CONFIG_SUN_SERIAL y
@@ -105,7 +106,8 @@
 	  dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
 	  define_bool CONFIG_BLK_DEV_IDEPCI y
 	  define_bool CONFIG_BLK_DEV_IDEDMA y
-	  define_bool CONFIG_IDEDMA_PCI_AUTO y
+	  define_bool CONFIG_IDEDMA_AUTO y
+	  define_bool IDEDMA_NEW_DRIVE_LISTINGS y
 	  define_bool CONFIG_BLK_DEV_NS87415 y
 	  define_bool CONFIG_BLK_DEV_CMD646 y
 	fi
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.12/linux/arch/sparc64/defconfig	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/defconfig	Fri Aug  6 11:58:00 1999
@@ -49,6 +49,7 @@
 # CONFIG_FBCON_FONTS is not set
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
+CONFIG_MOUSE=y
 CONFIG_SUN_MOUSE=y
 CONFIG_SERIAL=y
 CONFIG_SUN_SERIAL=y
@@ -93,12 +94,13 @@
 CONFIG_BINFMT_MISC=m
 CONFIG_SOLARIS_EMUL=m
 CONFIG_PARPORT=m
-# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_FIFO=y
 # CONFIG_PARPORT_AMIGA is not set
 # CONFIG_PARPORT_MFC3 is not set
 # CONFIG_PARPORT_ATARI is not set
 # CONFIG_PARPORT_OTHER is not set
-# CONFIG_PARPORT_1284 is not set
+CONFIG_PARPORT_1284=y
 CONFIG_PRINTER=m
 CONFIG_ENVCTRL=m
 
@@ -123,7 +125,8 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_AUTO=y
+IDEDMA_NEW_DRIVE_LISTINGS=y
 CONFIG_BLK_DEV_NS87415=y
 CONFIG_BLK_DEV_CMD646=y
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.3.12/linux/arch/sparc64/kernel/Makefile	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/kernel/Makefile	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.43 1999/01/02 16:45:53 davem Exp $
+# $Id: Makefile,v 1.44 1999/08/02 12:05:53 jj Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -61,12 +61,16 @@
 check_asm: dummy
 	@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
 	@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
-	@echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
-	@echo "#include <linux/config.h>" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
-	@echo "#ifndef CONFIG_SMP" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
+	@echo -e "#define __ASM_OFFSETS_H__\n" >> asm_offsets.h
+	@echo -e "#include <linux/config.h>\n" >> asm_offsets.h
+	@echo '#if defined(__KERNEL__) && !defined(__ASSEMBLY__)' >> asm_offsets.h
+	@if $(CC) -c -m64 -mcmodel=medlow -o /dev/null /dev/null >/dev/null 2>&1; then \
+		echo '# if !((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))' >> asm_offsets.h; \
+	 else \
+		echo '# if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)' >> asm_offsets.h; \
+	 fi
+	@echo -e "#  error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h
+	@echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
@@ -92,11 +96,8 @@
 	# </hack>
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo "" >> asm_offsets.h
-	@echo "#else /* CONFIG_SMP */" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
-	@echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
-	@echo "" >> asm_offsets.h
+	@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
+	@echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
@@ -124,9 +125,7 @@
 	# </hack>
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo "" >> asm_offsets.h
-	@echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
+	@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
 	$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@@ -151,10 +150,8 @@
 	# </hack>
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
-	@echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
+	@echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
 	  if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.3.12/linux/arch/sparc64/kernel/binfmt_aout32.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Mon Aug  2 22:07:16 1999
@@ -339,6 +339,16 @@
 
 	current->mm->start_stack =
 		(unsigned long) create_aout32_tables((char *)bprm->p, bprm);
+	if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
+		unsigned long pgd_cache;
+
+		pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL;
+		__asm__ __volatile__("stxa\t%0, [%1] %2"
+				     : /* no outputs */
+				     : "r" (pgd_cache),
+				       "r" (TSB_REG), "i" (ASI_DMMU));
+		current->thread.flags |= SPARC_FLAG_32BIT;
+	}
 	start_thread32(regs, ex.a_entry, current->mm->start_stack);
 	if (current->flags & PF_PTRACED)
 		send_sig(SIGTRAP, current, 0);
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/binfmt_elf32.c linux/arch/sparc64/kernel/binfmt_elf32.c
--- v2.3.12/linux/arch/sparc64/kernel/binfmt_elf32.c	Sun Oct  4 10:22:43 1998
+++ linux/arch/sparc64/kernel/binfmt_elf32.c	Mon Aug  2 22:07:16 1999
@@ -142,7 +142,7 @@
 #ifdef CONFIG_BINFMT_ELF32_MODULE
 #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
 #endif
-#define ELF_FLAGS_INIT	current->tss.flags |= SPARC_FLAG_32BIT
+#define ELF_FLAGS_INIT	current->thread.flags |= SPARC_FLAG_32BIT
 
 MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
 MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.3.12/linux/arch/sparc64/kernel/devices.c	Tue May 11 08:24:31 1999
+++ linux/arch/sparc64/kernel/devices.c	Mon Aug  2 22:07:16 1999
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/tasks.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
@@ -27,6 +28,10 @@
 	int nd, prom_node_cpu, thismid;
 	int cpu_nds[64];  /* One node for each cpu */
 	int cpu_ctr = 0;
+
+	/* FIX ME FAST... -DaveM */
+	ioport_resource.end = 0xffffffffffffffffUL;
+	iomem_resource.end = 0xffffffffffffffffUL;
 
 	prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.3.12/linux/arch/sparc64/kernel/ebus.c	Tue May 11 08:24:31 1999
+++ linux/arch/sparc64/kernel/ebus.c	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $
+/* $Id: ebus.c,v 1.38 1999/08/06 10:37:32 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -17,6 +17,7 @@
 #include <asm/ebus.h>
 #include <asm/oplib.h>
 #include <asm/bpp.h>
+#include <asm/irq.h>
 
 #undef PROM_DEBUG
 #undef DEBUG_FILL_EBUS_DEV
@@ -56,9 +57,9 @@
 	return mem;
 }
 
-__initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
-				  struct linux_prom_registers *reg,
-				  int *interrupt))
+void __init ebus_intmap_match(struct linux_ebus *ebus,
+			      struct linux_prom_registers *reg,
+			      int *interrupt)
 {
 	unsigned int hi, lo, irq;
 	int i;
@@ -83,8 +84,8 @@
 	prom_halt();
 }
 
-__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
-				struct linux_ebus_child *dev))
+void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
+			    struct linux_ebus_child *dev)
 {
 	int regs[PROMREG_MAX];
 	int irqs[PROMREG_MAX];
@@ -135,10 +136,11 @@
 	}
 
 #ifdef DEBUG_FILL_EBUS_DEV
-	dprintf("child '%s': address%s\n", dev->prom_name,
+	dprintf("child '%s': address%s ", dev->prom_name,
 	       dev->num_addrs > 1 ? "es" : "");
 	for (i = 0; i < dev->num_addrs; i++)
-		dprintf("        %016lx\n", dev->base_address[i]);
+		dprintf("%016lx ", dev->base_address[i]);
+	dprintf("\n");
 	if (dev->num_irqs) {
 		dprintf("        IRQ%s", dev->num_irqs > 1 ? "s" : "");
 		for (i = 0; i < dev->num_irqs; i++)
@@ -148,7 +150,7 @@
 #endif
 }
 
-__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
 {
 	struct linux_prom_registers regs[PROMREG_MAX];
 	struct linux_ebus_child *child;
@@ -172,7 +174,7 @@
 	for (i = 0; i < dev->num_addrs; i++) {
 		n = (regs[i].which_io - 0x10) >> 2;
 
-		dev->base_address[i] = dev->bus->self->base_address[n];
+		dev->base_address[i] = dev->bus->self->resource[n].start;
 		dev->base_address[i] += (unsigned long)regs[i].phys_addr;
 	}
 
@@ -189,10 +191,11 @@
 	}
 
 #ifdef DEBUG_FILL_EBUS_DEV
-	dprintf("'%s': address%s\n", dev->prom_name,
+	dprintf("'%s': address%s ", dev->prom_name,
 	       dev->num_addrs > 1 ? "es" : "");
 	for (i = 0; i < dev->num_addrs; i++)
-		dprintf("  %016lx\n", dev->base_address[i]);
+		dprintf("%016lx ", dev->base_address[i]);
+	dprintf("\n");
 	if (dev->num_irqs) {
 		dprintf("  IRQ%s", dev->num_irqs > 1 ? "s" : "");
 		for (i = 0; i < dev->num_irqs; i++)
@@ -225,7 +228,7 @@
 
 extern void clock_probe(void);
 
-__initfunc(void ebus_init(void))
+void __init ebus_init(void)
 {
 	struct linux_prom_pci_registers regs[PROMREG_MAX];
 	struct linux_pbm_info *pbm;
@@ -234,7 +237,8 @@
 	struct pci_dev *pdev;
 	struct pcidev_cookie *cookie;
 	char lbuf[128];
-	unsigned long addr, *base;
+	struct resource *base;
+	unsigned long addr;
 	unsigned short pci_command;
 	int nd, len, ebusnd;
 	int reg, rng, nreg;
@@ -317,7 +321,7 @@
 		}
 		nreg = len / sizeof(struct linux_prom_pci_registers);
 
-		base = &ebus->self->base_address[0];
+		base = &ebus->self->resource[0];
 		for (reg = 0; reg < nreg; reg++) {
 			if (!(regs[reg].phys_hi & 0x03000000))
 				continue;
@@ -334,7 +338,14 @@
 				addr += (u64)regs[reg].phys_mid << 32UL;
 				addr += (u64)rp->parent_phys_lo;
 				addr += (u64)rp->parent_phys_hi << 32UL;
-				*base++ = (unsigned long)__va(addr);
+
+				base->name = "EBUS";
+				base->start = (unsigned long)__va(addr);
+				base->end = base->start + regs[reg].size_lo - 1;
+				base->flags = 0;
+				request_resource(&ioport_resource, base);
+
+				base += 1;
 
 				printk(" %lx[%x]", (unsigned long)__va(addr),
 				       regs[reg].size_lo);
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.3.12/linux/arch/sparc64/kernel/entry.S	Tue May 11 08:24:31 1999
+++ linux/arch/sparc64/kernel/entry.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $
+/* $Id: entry.S,v 1.106 1999/08/02 08:39:34 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -42,13 +42,13 @@
 	/* This is trivial with the new code... */
 	.globl		do_fpdis
 do_fpdis:
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5	! Load	Group
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5	! Load	Group
 	sethi		%hi(TSTATE_PEF), %g4					! IEU0
 	wr		%g0, FPRS_FEF, %fprs					! LSU	Group+4bubbles
 	andcc		%g5, FPRS_FEF, %g0					! IEU1	Group
 	be,a,pt		%icc, 1f						! CTI
 	 clr		%g7							! IEU0
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_gsr], %g7		! Load	Group
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7		! Load	Group
 1:	andcc		%g5, FPRS_DL, %g0					! IEU1
 	bne,pn		%icc, 2f						! CTI
 	 fzero		%f0							! FPA
@@ -157,7 +157,7 @@
 	flush		%g6
 fpdis_exit2:
 	wr		%g7, 0, %gsr
-	ldx		[%g6 + AOFF_task_tss + AOFF_thread_xfsr], %fsr
+	ldx		[%g6 + AOFF_task_thread + AOFF_thread_xfsr], %fsr
 	rdpr		%tstate, %g3
 	or		%g3, %g4, %g3		! anal...
 	wrpr		%g3, %tstate
@@ -167,13 +167,13 @@
 	.globl		do_fptrap
 	.align		32
 do_fptrap:
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
-	stx		%fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
+	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
 	rd		%fprs, %g1
 	or		%g3, %g1, %g3
-	stb		%g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+	stb		%g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
 	rd		%gsr, %g3
-	stb		%g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr]
+	stb		%g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
 	mov		SECONDARY_CONTEXT, %g3
 	add		%g6, AOFF_task_fpregs, %g2
 	ldxa		[%g3] ASI_DMMU, %g5
@@ -633,41 +633,28 @@
 	jmpl		%g1, %g0
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 
-	.globl	sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+	.globl	sys_pipe, sys_sigpause, sys_nis_syscall
 	.globl	sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend
-	.globl	sys_sigreturn, sys_rt_sigreturn
+	.globl	sys_rt_sigreturn
 	.globl	sys32_sigreturn, sys32_rt_sigreturn
 	.globl	sys32_execve, sys_ptrace
 	.globl	sys_sigaltstack, sys32_sigaltstack
 	.globl	sys32_sigstack
 	.align	32
-sys_pipe:	sethi		%hi(sparc_pipe), %g1
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
-		jmpl		%g1 + %lo(sparc_pipe), %g0
-		 nop
-sys_nis_syscall:sethi		%hi(c_sys_nis_syscall), %g1
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
-		jmpl		%g1 + %lo(c_sys_nis_syscall), %g0
-		 nop
-
+sys_pipe:	ba,pt		%xcc, sparc_pipe
+		 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+sys_nis_syscall:ba,pt		%xcc, c_sys_nis_syscall
+		 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 sys_memory_ordering:
-		sethi		%hi(sparc_memory_ordering), %g1
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o1
-		jmpl		%g1 + %lo(sparc_memory_ordering), %g0
-		 nop
-sys_sigaltstack:sethi		%hi(do_sigaltstack), %g1
-		add		%i6, STACK_BIAS, %o2
-		jmpl		%g1 + %lo(do_sigaltstack), %g1
-		 nop
-sys32_sigstack:	sethi		%hi(do_sys32_sigstack), %g1
-		mov		%i6, %o2
-		jmpl		%g1 + %lo(do_sys32_sigstack), %g1
-		 nop
+		ba,pt		%xcc, sparc_memory_ordering
+		 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+sys_sigaltstack:ba,pt		%xcc, do_sigaltstack
+		 add		%i6, STACK_BIAS, %o2
+sys32_sigstack:	ba,pt		%xcc, do_sys32_sigstack
+		 mov		%i6, %o2
 sys32_sigaltstack:
-		sethi		%hi(do_sys32_sigaltstack), %g1
-		mov		%i6, %o2
-		jmpl		%g1 + %lo(do_sys32_sigaltstack), %g1
-		 nop
+		ba,pt		%xcc, do_sys32_sigaltstack
+		 mov		%i6, %o2
 
 		.align		32
 sys_sigsuspend:	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
@@ -689,10 +676,6 @@
 		call		do_sigpause
 		 add		%o7, 1f-.-4, %o7
 		nop
-sys_sigreturn:	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
-		call		do_sigreturn
-		 add		%o7, 1f-.-4, %o7
-		nop
 sys32_sigreturn:
 		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 		call		do_sigreturn32
@@ -761,38 +744,30 @@
 		ba,pt		%xcc, do_fork
 		 add		%sp, STACK_BIAS + REGWIN_SZ, %o2
 ret_from_syscall:
-		/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
+		/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in
 		 * %o7 for us.  Check performance counter stuff too.
 		 */
-#ifdef __SMP__
-		andn		%o7, 0x100, %l0
+		andn		%o7, SPARC_FLAG_NEWCHILD, %l0
 		mov		%g5, %o0	/* 'prev' */
 		call		schedule_tail
-		 sth		%l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
-#else
-		andn		%o7, 0x100, %l0
-		sth		%l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
-#endif
-		andcc		%l0, 0x200, %g0
+		 stb		%l0, [%g6 + AOFF_task_thread + AOFF_thread_flags]
+		andcc		%l0, SPARC_FLAG_PERFCTR, %g0
 		be,pt		%icc, 1f
 		 nop
-		ldx		[%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
+		ldx		[%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7
 		wr		%g0, %o7, %pcr
 		wr		%g0, %g0, %pic
 1:		b,pt		%xcc, ret_sys_call
 		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 sparc_exit:	rdpr		%otherwin, %g1
-		rdpr		%pstate, %g2
-		wrpr		%g2, PSTATE_IE, %pstate
+		wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate
 		rdpr		%cansave, %g3
 		add		%g3, %g1, %g3
 		wrpr		%g3, 0x0, %cansave
 		wrpr		%g0, 0x0, %otherwin
-		wrpr		%g2, 0x0, %pstate
-		mov		%o7, %l5
-		sth		%g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
-		call		sys_exit
-		 mov		%l5, %o7
+		wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate
+		ba,pt		%xcc, sys_exit
+		 stb		%g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
 
 linux_sparc_ni_syscall:
 	sethi		%hi(sys_ni_syscall), %l7
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.3.12/linux/arch/sparc64/kernel/etrap.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/kernel/etrap.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.41 1999/05/25 16:53:09 jj Exp $
+/* $Id: etrap.S,v 1.42 1999/07/30 09:35:18 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -56,7 +56,7 @@
 		wrpr			%g0, 0, %canrestore					! Single	Group+4bubbles
 		sll			%g2, 3, %g2						! IEU0		Group
 		mov			1, %l5							! IEU1
-		stb			%l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth]	! Store
+		stb			%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
 		wrpr			%g3, 0, %otherwin					! Single	Group+4bubbles
 		wrpr			%g2, 0, %wstate						! Single	Group+4bubbles
 		stxa			%g0, [%l4] ASI_DMMU					! Store		Group
@@ -89,11 +89,11 @@
 		jmpl			%l2 + 0x4, %g0						! CTI		Group
 		 mov			%l6, %g6						! IEU0
 
-3:		ldub			[%l6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5	! Load		Group
-		add			%l6, AOFF_task_tss + AOFF_thread_fpsaved + 1, %l4	! IEU0
+3:		ldub			[%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5	! Load		Group
+		add			%l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4	! IEU0
 		srl			%l5, 1, %l3						! IEU0		Group
 		add			%l5, 2, %l5						! IEU1
-		stb			%l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth]	! Store
+		stb			%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
 		ba,pt			%xcc, 2b						! CTI
 		 stb			%g0, [%l4 + %l3]					! Store		Group
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.12/linux/arch/sparc64/kernel/ioctl32.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Aug  9 11:29:37 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.63 1999/06/09 04:56:14 davem Exp $
+/* $Id: ioctl32.c,v 1.66 1999/08/08 01:37:06 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -38,6 +38,7 @@
 #include <linux/ext2_fs.h>
 #include <linux/videodev.h>
 #include <linux/netdevice.h>
+#include <linux/raw.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -570,7 +571,7 @@
 			if(cmd == SIOCETHTOOL)
 				len = sizeof(struct ethtool_cmd);
 			if(cmd == SIOCGPPPVER)
-				len = strlen(PPP_VERSION) + 1;
+				len = strlen((char *)ifr.ifr_data) + 1;
 			else if(cmd == SIOCGPPPCSTATS)
 				len = sizeof(struct ppp_comp_stats);
 			else
@@ -2366,6 +2367,10 @@
 	case AUTOFS_IOC_PROTOVER:
 	case AUTOFS_IOC_EXPIRE:
 	
+	/* Raw devices */
+	case RAW_SETBIND:
+	case RAW_GETBIND:
+
 		error = sys_ioctl (fd, cmd, arg);
 		goto out;
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.3.12/linux/arch/sparc64/kernel/process.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/kernel/process.c	Wed Aug  4 15:39:46 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.95 1999/06/28 08:48:51 davem Exp $
+/*  $Id: process.c,v 1.99 1999/08/04 03:19:20 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -46,7 +46,7 @@
 /*
  * the idle loop on a Sparc... ;)
  */
-asmlinkage int sys_idle(void)
+int cpu_idle(void)
 {
 	if (current->pid != 0)
 		return -EPERM;
@@ -77,7 +77,7 @@
  */
 #define idle_me_harder()	(cpu_data[current->processor].idle_volume += 1)
 #define unidle_me()		(cpu_data[current->processor].idle_volume = 0)
-asmlinkage int cpu_idle(void)
+int cpu_idle(void)
 {
 	current->priority = 0;
 	current->counter = -100;
@@ -99,15 +99,6 @@
 	}
 }
 
-asmlinkage int sys_idle(void)
-{
-	if(current->pid != 0)
-		return -EPERM;
-
-	cpu_idle();
-	return 0;
-}
-
 #endif
 
 extern char reboot_command [];
@@ -189,7 +180,7 @@
 	struct reg_window r_w;
 	mm_segment_t old_fs;
 
-	if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) {
+	if ((regs->tstate & TSTATE_PRIV) || !(current->thread.flags & SPARC_FLAG_32BIT)) {
 		__asm__ __volatile__ ("flushw");
 		rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS);
 		if (!(regs->tstate & TSTATE_PRIV)) {
@@ -369,90 +360,96 @@
 	       regs->u_regs[15]);
 }
 
-void show_thread(struct thread_struct *tss)
+void show_thread(struct thread_struct *thread)
 {
 	int i;
 
 #if 0
-	printk("kregs:             0x%016lx\n", (unsigned long)tss->kregs);
-	show_regs(tss->kregs);
+	printk("kregs:             0x%016lx\n", (unsigned long)thread->kregs);
+	show_regs(thread->kregs);
 #endif	
-	printk("sig_address:       0x%016lx\n", tss->sig_address);
-	printk("sig_desc:          0x%016lx\n", tss->sig_desc);
-	printk("ksp:               0x%016lx\n", tss->ksp);
+	printk("sig_address:       0x%016lx\n", thread->sig_address);
+	printk("sig_desc:          0x%016lx\n", thread->sig_desc);
+	printk("ksp:               0x%016lx\n", thread->ksp);
 
-	if (tss->w_saved) {
+	if (thread->w_saved) {
 		for (i = 0; i < NSWINS; i++) {
-			if (!tss->rwbuf_stkptrs[i])
+			if (!thread->rwbuf_stkptrs[i])
 				continue;
 			printk("reg_window[%d]:\n", i);
-			printk("stack ptr:         0x%016lx\n", tss->rwbuf_stkptrs[i]);
+			printk("stack ptr:         0x%016lx\n", thread->rwbuf_stkptrs[i]);
 		}
-		printk("w_saved:           0x%04x\n", tss->w_saved);
+		printk("w_saved:           0x%04x\n", thread->w_saved);
 	}
 
-	printk("flags:             0x%08x\n", tss->flags);
-	printk("current_ds:        0x%x\n", tss->current_ds.seg);
+	printk("flags:             0x%08x\n", thread->flags);
+	printk("current_ds:        0x%x\n", thread->current_ds.seg);
 }
 
 /* Free current thread data structures etc.. */
 void exit_thread(void)
 {
-	if (current->tss.utraps) {
-		if (current->tss.utraps[0] < 2)
-			kfree (current->tss.utraps);
+	struct thread_struct *t = &current->thread;
+
+	if (t->utraps) {
+		if (t->utraps[0] < 2)
+			kfree (t->utraps);
 		else
-			current->tss.utraps[0]--;
+			t->utraps[0]--;
 	}
 
 	/* Turn off performance counters if on. */
-	if (current->tss.flags & SPARC_FLAG_PERFCTR) {
-		current->tss.user_cntd0 =
-			current->tss.user_cntd1 = NULL;
-		current->tss.pcr_reg = 0;
-		current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+	if (t->flags & SPARC_FLAG_PERFCTR) {
+		t->user_cntd0 = t->user_cntd1 = NULL;
+		t->pcr_reg = 0;
+		t->flags &= ~(SPARC_FLAG_PERFCTR);
 		write_pcr(0);
 	}
 }
 
 void flush_thread(void)
 {
-	if (!(current->tss.flags & SPARC_FLAG_KTHREAD))
-		flush_user_windows();
-	current->tss.w_saved = 0;
+	struct thread_struct *t = &current->thread;
+
+	if (current->mm) {
+		if (t->flags & SPARC_FLAG_32BIT) {
+			struct mm_struct *mm = current->mm;
+			pgd_t *pgd0 = &mm->pgd[0];
+			unsigned long pgd_cache;
+
+			if (pgd_none(*pgd0)) {
+				pmd_t *page = get_pmd_fast();
+				if (!page)
+					(void) get_pmd_slow(pgd0, 0);
+				else
+					pgd_set(pgd0, page);
+			}
+			pgd_cache = pgd_val(*pgd0) << 11UL;
+			__asm__ __volatile__("stxa %0, [%1] %2"
+					     : /* no outputs */
+					     : "r" (pgd_cache),
+					       "r" (TSB_REG),
+					       "i" (ASI_DMMU));
+		}
+	}
+	t->w_saved = 0;
 
 	/* Turn off performance counters if on. */
-	if (current->tss.flags & SPARC_FLAG_PERFCTR) {
-		current->tss.user_cntd0 =
-			current->tss.user_cntd1 = NULL;
-		current->tss.pcr_reg = 0;
-		current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+	if (t->flags & SPARC_FLAG_PERFCTR) {
+		t->user_cntd0 = t->user_cntd1 = NULL;
+		t->pcr_reg = 0;
+		t->flags &= ~(SPARC_FLAG_PERFCTR);
 		write_pcr(0);
 	}
 
-	/* No new signal delivery by default. */
-	current->tss.new_signal = 0;
-	current->tss.fpsaved[0] = 0;
+	/* Clear FPU register state. */
+	t->fpsaved[0] = 0;
 	
-	/* Now, this task is no longer a kernel thread. */
-	current->tss.current_ds = USER_DS;
-	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
-		current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+	if (t->current_ds.seg != ASI_AIUS)
+		set_fs(USER_DS);
 
-		/* exec_mmap() set context to NO_CONTEXT, here is
-		 * where we grab a new one.
-		 */
-		activate_context(current);
-	}
-	if (current->tss.flags & SPARC_FLAG_32BIT)
-		__asm__ __volatile__("stxa %%g0, [%0] %1"
-				     : /* no outputs */
-				     : "r"(TSB_REG), "i"(ASI_DMMU));
-	__cli();
-	current->tss.ctx = current->mm->context & 0x3ff;
-	spitfire_set_secondary_context (current->tss.ctx);
-	__asm__ __volatile__("flush %g6");
-	__sti();
+	/* Init new signal delivery disposition. */
+	t->flags &= ~SPARC_FLAG_NEWSIGNALS;
 }
 
 /* It's a bit more tricky when 64-bit tasks are involved... */
@@ -460,12 +457,7 @@
 {
 	unsigned long fp, distance, rval;
 
-	/* do_fork() grabs the parent semaphore, we must release it
-	 * temporarily so we can build the child clone stack frame
-	 * without deadlocking.
-	 */
-	up(&current->mm->mmap_sem);
-	if(!(current->tss.flags & SPARC_FLAG_32BIT)) {
+	if(!(current->thread.flags & SPARC_FLAG_32BIT)) {
 		csp += STACK_BIAS;
 		psp += STACK_BIAS;
 		__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
@@ -482,7 +474,7 @@
 	rval = (csp - distance);
 	if(copy_in_user(rval, psp, distance))
 		rval = 0;
-	else if(current->tss.flags & SPARC_FLAG_32BIT) {
+	else if(current->thread.flags & SPARC_FLAG_32BIT) {
 		if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
 			rval = 0;
 	} else {
@@ -492,47 +484,46 @@
 		else
 			rval = rval - STACK_BIAS;
 	}
-	down(&current->mm->mmap_sem);
 
 	return rval;
 }
 
 /* Standard stuff. */
 static inline void shift_window_buffer(int first_win, int last_win,
-				       struct thread_struct *tp)
+				       struct thread_struct *t)
 {
 	int i;
 
 	for(i = first_win; i < last_win; i++) {
-		tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
-		memcpy(&tp->reg_window[i], &tp->reg_window[i+1],
+		t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1];
+		memcpy(&t->reg_window[i], &t->reg_window[i+1],
 		       sizeof(struct reg_window));
 	}
 }
 
 void synchronize_user_stack(void)
 {
-	struct thread_struct *tp = &current->tss;
+	struct thread_struct *t = &current->thread;
 	unsigned long window;
 
 	flush_user_windows();
-	if((window = tp->w_saved) != 0) {
+	if((window = t->w_saved) != 0) {
 		int winsize = REGWIN_SZ;
 		int bias = 0;
 
-		if(tp->flags & SPARC_FLAG_32BIT)
+		if(t->flags & SPARC_FLAG_32BIT)
 			winsize = REGWIN32_SZ;
 		else
 			bias = STACK_BIAS;
 
 		window -= 1;
 		do {
-			unsigned long sp = (tp->rwbuf_stkptrs[window] + bias);
-			struct reg_window *rwin = &tp->reg_window[window];
+			unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
+			struct reg_window *rwin = &t->reg_window[window];
 
 			if(!copy_to_user((char *)sp, rwin, winsize)) {
-				shift_window_buffer(window, tp->w_saved - 1, tp);
-				tp->w_saved--;
+				shift_window_buffer(window, t->w_saved - 1, t);
+				t->w_saved--;
 			}
 		} while(window--);
 	}
@@ -540,28 +531,28 @@
 
 void fault_in_user_windows(struct pt_regs *regs)
 {
-	struct thread_struct *tp = &current->tss;
+	struct thread_struct *t = &current->thread;
 	unsigned long window;
 	int winsize = REGWIN_SZ;
 	int bias = 0;
 
-	if(tp->flags & SPARC_FLAG_32BIT)
+	if(t->flags & SPARC_FLAG_32BIT)
 		winsize = REGWIN32_SZ;
 	else
 		bias = STACK_BIAS;
 	flush_user_windows();
-	window = tp->w_saved;
+	window = t->w_saved;
 	if(window != 0) {
 		window -= 1;
 		do {
-			unsigned long sp = (tp->rwbuf_stkptrs[window] + bias);
-			struct reg_window *rwin = &tp->reg_window[window];
+			unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
+			struct reg_window *rwin = &t->reg_window[window];
 
 			if(copy_to_user((char *)sp, rwin, winsize))
 				goto barf;
 		} while(window--);
 	}
-	current->tss.w_saved = 0;
+	t->w_saved = 0;
 	return;
 barf:
 	do_exit(SIGILL);
@@ -582,65 +573,73 @@
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 		struct task_struct *p, struct pt_regs *regs)
 {
+	struct thread_struct *t = &p->thread;
 	char *child_trap_frame;
 
 	/* Calculate offset to stack_frame & pt_regs */
 	child_trap_frame = ((char *)p) + ((PAGE_SIZE << 1) - (TRACEREG_SZ+REGWIN_SZ));
 	memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
-	p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
-	p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
-	p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
-	p->tss.fpsaved[0] = 0;
-	p->mm->segments = (void *) 0;
+	t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+	t->flags |= SPARC_FLAG_NEWCHILD;
+	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
+	t->cwp = (regs->tstate + 1) & TSTATE_CWP;
+	t->fpsaved[0] = 0;
 	if(regs->tstate & TSTATE_PRIV) {
 		/* Special case, if we are spawning a kernel thread from
 		 * a userspace task (via KMOD, NFS, or similar) we must
 		 * disable performance counters in the child because the
 		 * address space and protection realm are changing.
 		 */
-		if (current->tss.flags & SPARC_FLAG_PERFCTR) {
-			p->tss.user_cntd0 =
-				p->tss.user_cntd1 = NULL;
-			p->tss.pcr_reg = 0;
-			p->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+		if (t->flags & SPARC_FLAG_PERFCTR) {
+			t->user_cntd0 = t->user_cntd1 = NULL;
+			t->pcr_reg = 0;
+			t->flags &= ~(SPARC_FLAG_PERFCTR);
 		}
-		p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
-		p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD);
-		p->tss.current_ds = KERNEL_DS;
-		p->tss.ctx = 0;
-		__asm__ __volatile__("flushw");
-		memcpy((void *)(p->tss.ksp + STACK_BIAS),
+		t->kregs->u_regs[UREG_FP] = p->thread.ksp;
+		t->current_ds = KERNEL_DS;
+		flush_register_windows();
+		memcpy((void *)(t->ksp + STACK_BIAS),
 		       (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
 		       sizeof(struct reg_window));
-		p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
+		t->kregs->u_regs[UREG_G6] = (unsigned long) p;
 	} else {
-		if(current->tss.flags & SPARC_FLAG_32BIT) {
+		if(t->flags & SPARC_FLAG_32BIT) {
 			sp &= 0x00000000ffffffffUL;
 			regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
 		}
-		p->tss.kregs->u_regs[UREG_FP] = sp;
-		p->tss.flags = (p->tss.flags & ~SPARC_FLAG_KTHREAD) |
-			SPARC_FLAG_NEWCHILD;
-		p->tss.current_ds = USER_DS;
-		p->tss.ctx = (p->mm->context & 0x3ff);
+		t->kregs->u_regs[UREG_FP] = sp;
+		t->current_ds = USER_DS;
 		if (sp != regs->u_regs[UREG_FP]) {
 			unsigned long csp;
 
 			csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
 			if(!csp)
 				return -EFAULT;
-			p->tss.kregs->u_regs[UREG_FP] = csp;
+			t->kregs->u_regs[UREG_FP] = csp;
 		}
-		if (p->tss.utraps)
-			p->tss.utraps[0]++;
+		if (t->utraps)
+			t->utraps[0]++;
 	}
 
 	/* Set the return value for the child. */
-	p->tss.kregs->u_regs[UREG_I0] = current->pid;
-	p->tss.kregs->u_regs[UREG_I1] = 1;
+	t->kregs->u_regs[UREG_I0] = current->pid;
+	t->kregs->u_regs[UREG_I1] = 1;
 
 	/* Set the second return value for the parent. */
 	regs->u_regs[UREG_I1] = 0;
+#if 0
+	printk("\ncopy_thread: c(%p[mm(%p:%p)]) p(%p[mm(%p:%p)])\n",
+	       current, current->mm, current->active_mm,
+	       p, p->mm, p->active_mm);
+	printk("copy_thread: c MM_ctx(%016lx) MM_pgd(%016lx)\n",
+	       (current->mm ? current->mm->context : 0),
+	       (current->mm ? pgd_val(current->mm->pgd[0]) : 0));
+	printk("copy_thread: p MM_ctx(%016lx) MM_pgd(%08x)\n",
+	       (p->mm ? p->mm->context : 0),
+	       (p->mm ? pgd_val(p->mm->pgd[0]) : 0));
+	printk("copy_thread: c->flags(%x) p->flags(%x) ",
+	       current->thread.flags, p->thread.flags);
+#endif
 	return 0;
 }
 
@@ -703,10 +702,10 @@
 	dump->u_dsize &= ~(PAGE_SIZE - 1);
 	first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
 	dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
-	memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->tss.float_regs[0], (sizeof(unsigned long) * 32));
-	dump->fpu.fpstatus.fsr = current->tss.fsr;
+	memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->thread.float_regs[0], (sizeof(unsigned long) * 32));
+	dump->fpu.fpstatus.fsr = current->thread.fsr;
 	dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
-	dump->sigcode = current->tss.sig_desc;
+	dump->sigcode = current->thread.sig_desc;
 #endif	
 }
 
@@ -729,9 +728,9 @@
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 {
 	unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
-	unsigned long fprs = current->tss.fpsaved[0];
+	unsigned long fprs = current->thread.fpsaved[0];
 
-	if ((current->tss.flags & SPARC_FLAG_32BIT) != 0) {
+	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
 		elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
 
 		if (fprs & FPRS_DL)
@@ -745,7 +744,7 @@
 		memset(&fpregs32->pr_q[0], 0,
 		       (sizeof(unsigned int) * 64));
 		if (fprs & FPRS_FEF) {
-			fpregs32->pr_fsr = (unsigned int) current->tss.xfsr[0];
+			fpregs32->pr_fsr = (unsigned int) current->thread.xfsr[0];
 			fpregs32->pr_en = 1;
 		} else {
 			fpregs32->pr_fsr = 0;
@@ -765,8 +764,8 @@
 			memset(&fpregs->pr_regs[16], 0,
 			       sizeof(unsigned int) * 32);
 		if(fprs & FPRS_FEF) {
-			fpregs->pr_fsr = current->tss.xfsr[0];
-			fpregs->pr_gsr = current->tss.gsr[0];
+			fpregs->pr_fsr = current->thread.xfsr[0];
+			fpregs->pr_gsr = current->thread.gsr[0];
 		} else {
 			fpregs->pr_fsr = fpregs->pr_gsr = 0;
 		}
@@ -784,6 +783,8 @@
 	int error, base = 0;
 	char *filename;
 
+	/* User register window flush is done by entry.S */
+
 	/* Check for indirect call. */
 	if(regs->u_regs[UREG_G1] == 0)
 		base = 1;
@@ -798,8 +799,8 @@
 	putname(filename);
 	if(!error) {
 		fprs_write(0);
-		current->tss.xfsr[0] = 0;
-		current->tss.fpsaved[0] = 0;
+		current->thread.xfsr[0] = 0;
+		current->thread.fpsaved[0] = 0;
 		regs->tstate &= ~TSTATE_PEF;
 	}
 out:
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
--- v2.3.12/linux/arch/sparc64/kernel/psycho.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/psycho.c	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.86 1999/07/01 10:39:43 davem Exp $
+/* $Id: psycho.c,v 1.89 1999/08/06 10:37:35 davem Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -808,6 +808,264 @@
 	}
 }
 
+extern struct pci_bus pci_root;
+extern struct pci_dev *pci_devices;
+static struct pci_dev **pci_last_dev_p = &pci_devices;
+extern int pci_reverse;
+
+extern void pci_namedevice(struct pci_dev *);
+
+static void __init sparc64_pci_read_bases(struct pci_dev *dev, unsigned int howmany)
+{
+	unsigned int reg;
+	u32 l;
+
+	for(reg=0; reg < howmany; reg++) {
+		struct resource *res = dev->resource + reg;
+		unsigned long mask;
+		unsigned int newval, size;
+
+		res->name = dev->name;
+		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+		if (l == 0xffffffff)
+			continue;
+
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), 0xffffffff);
+		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &newval);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), l);
+
+		mask = PCI_BASE_ADDRESS_MEM_MASK;
+		if (l & PCI_BASE_ADDRESS_SPACE_IO)
+			mask = PCI_BASE_ADDRESS_IO_MASK;
+
+		newval &= mask;
+		if (!newval)
+			continue;
+
+		res->start = l & mask;
+		res->flags = l & ~mask;
+
+		size = 1;
+		do {
+			size <<= 1;
+		} while (!(size & newval));
+
+		/* 64-bit memory? */
+		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+		    	unsigned int high;
+			reg++;
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &high);
+			if (high)
+				res->start |= ((unsigned long) high) << 32;
+		}
+		res->end = res->start + size - 1;
+	}
+}
+
+static unsigned int __init sparc64_pci_scan_bus(struct pci_bus *bus)
+{
+	unsigned int devfn, l, max, class;
+	unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
+	struct pci_dev *dev, **bus_last;
+	struct pci_bus *child;
+
+	bus_last = &bus->devices;
+	max = bus->secondary;
+	for (devfn = 0; devfn < 0xff; ++devfn) {
+		if (PCI_FUNC(devfn) && !is_multi) {
+			/* not a multi-function device */
+			continue;
+		}
+		if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		if (!PCI_FUNC(devfn))
+			is_multi = hdr_type & 0x80;
+
+		if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
+		    /* some broken boards return 0 if a slot is empty: */
+		    l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
+			continue;
+
+		dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
+		if(dev==NULL)
+		{
+			printk(KERN_ERR "pci: out of memory.\n");
+			continue;
+		}
+		memset(dev, 0, sizeof(*dev));
+		dev->bus = bus;
+		dev->devfn  = devfn;
+		dev->vendor = l & 0xffff;
+		dev->device = (l >> 16) & 0xffff;
+		pci_namedevice(dev);
+
+		/* non-destructively determine if device can be a master: */
+		pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd);
+		pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+		pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp);
+		dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
+		pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd);
+
+		pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class);
+		class >>= 8;				    /* upper 3 bytes */
+		dev->class = class;
+		class >>= 8;
+		dev->hdr_type = hdr_type;
+
+		switch (hdr_type & 0x7f) {		    /* header type */
+		case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
+			if (class == PCI_CLASS_BRIDGE_PCI)
+				goto bad;
+			/*
+			 * If the card generates interrupts, read IRQ number
+			 * (some architectures change it during pcibios_fixup())
+			 */
+			pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq);
+			if (irq)
+				pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
+			dev->irq = irq;
+			sparc64_pci_read_bases(dev, 6);
+			pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
+			dev->rom_address = (l == 0xffffffff) ? 0 : l;
+			break;
+		case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
+			if (class != PCI_CLASS_BRIDGE_PCI)
+				goto bad;
+			sparc64_pci_read_bases(dev, 2);
+			pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
+			dev->rom_address = (l == 0xffffffff) ? 0 : l;
+			break;
+		case PCI_HEADER_TYPE_CARDBUS:		    /* CardBus bridge header */
+			if (class != PCI_CLASS_BRIDGE_CARDBUS)
+				goto bad;
+			sparc64_pci_read_bases(dev, 1);
+			break;
+		default:				    /* unknown header */
+		bad:
+			printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
+			       bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
+			continue;
+		}
+
+		/*
+		 * Put it into the global PCI device chain. It's used to
+		 * find devices once everything is set up.
+		 */
+		if (!pci_reverse) {
+			*pci_last_dev_p = dev;
+			pci_last_dev_p = &dev->next;
+		} else {
+			dev->next = pci_devices;
+			pci_devices = dev;
+		}
+
+		/*
+		 * Now insert it into the list of devices held
+		 * by the parent bus.
+		 */
+		*bus_last = dev;
+		bus_last = &dev->sibling;
+	}
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	pcibios_fixup_bus(bus);
+	for(dev=bus->devices; dev; dev=dev->sibling)
+		/*
+		 * If it's a bridge, scan the bus behind it.
+		 */
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+			unsigned int buses;
+			unsigned int devfn = dev->devfn;
+			unsigned short cr;
+
+			/*
+			 * Insert it into the tree of buses.
+			 */
+			child = kmalloc(sizeof(*child), GFP_ATOMIC);
+			if(child==NULL)
+			{
+				printk(KERN_ERR "pci: out of memory for bridge.\n");
+				continue;
+			}
+			memset(child, 0, sizeof(*child));
+			child->next = bus->children;
+			bus->children = child;
+			child->self = dev;
+			child->parent = bus;
+
+			/*
+			 * Set up the primary, secondary and subordinate
+			 * bus numbers.
+			 */
+			child->number = child->secondary = ++max;
+			child->primary = bus->secondary;
+			child->subordinate = 0xff;
+			/*
+			 * Clear all status bits and turn off memory,
+			 * I/O and master enables.
+			 */
+			pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
+			pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
+			pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
+			/*
+			 * Read the existing primary/secondary/subordinate bus
+			 * number configuration to determine if the PCI bridge
+			 * has already been configured by the system.  If so,
+			 * do not modify the configuration, merely note it.
+			 */
+			pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
+			if ((buses & 0xFFFFFF) != 0)
+			  {
+			    unsigned int cmax;
+
+			    child->primary = buses & 0xFF;
+			    child->secondary = (buses >> 8) & 0xFF;
+			    child->subordinate = (buses >> 16) & 0xFF;
+			    child->number = child->secondary;
+			    cmax = sparc64_pci_scan_bus(child);
+			    if (cmax > max) max = cmax;
+			  }
+			else
+			  {
+			    /*
+			     * Configure the bus numbers for this bridge:
+			     */
+			    buses &= 0xff000000;
+			    buses |=
+			      (((unsigned int)(child->primary)     <<  0) |
+			       ((unsigned int)(child->secondary)   <<  8) |
+			       ((unsigned int)(child->subordinate) << 16));
+			    pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
+			    /*
+			     * Now we can scan all subordinate buses:
+			     */
+			    max = sparc64_pci_scan_bus(child);
+			    /*
+			     * Set the subordinate bus number to its real
+			     * value:
+			     */
+			    child->subordinate = max;
+			    buses = (buses & 0xff00ffff)
+			      | ((unsigned int)(child->subordinate) << 16);
+			    pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
+			  }
+			pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
+		}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	return max;
+}
+
 static void __init sabre_probe(struct linux_psycho *sabre)
 {
 	struct pci_bus *pbus = sabre->pci_bus;
@@ -816,7 +1074,7 @@
 	pbus->number = pbus->secondary = busno;
 	pbus->sysdata = sabre;
 
-	pbus->subordinate = pci_scan_bus(pbus);
+	pbus->subordinate = sparc64_pci_scan_bus(pbus);
 	busno = pbus->subordinate + 1;
 
 	for(pbus = pbus->children; pbus; pbus = pbus->next) {
@@ -847,7 +1105,7 @@
 
 	pbm_fixup_busno(pbm, busno);
 
-	pbus->subordinate = pci_scan_bus(pbus);
+	pbus->subordinate = sparc64_pci_scan_bus(pbus);
 
 	/*
 	 * Set the maximum subordinate bus of this pbm.
@@ -1159,7 +1417,7 @@
 		int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
 		int bsreg, brindex;
 		unsigned int rtmp;
-		u64 pci_addr;
+		u64 pci_addr, pci_size;
 
 		if(bustype == 0) {
 			/* Config space cookie, nothing to do. */
@@ -1216,6 +1474,8 @@
 		/* Now construct UPA physical address. */
 		pci_addr  = (((u64)pregs[preg].phys_mid) << 32UL);
 		pci_addr |= (((u64)pregs[preg].phys_lo));
+		pci_size  = (((u64)pregs[preg].size_hi) << 32UL);
+		pci_size |= (((u64)pregs[preg].size_lo));
 
 		if(ap) {
 			pci_addr += ((u64)ap->phys_lo);
@@ -1224,12 +1484,12 @@
 
 		/* Final step, apply PBM range. */
 		for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
-			struct linux_prom_pci_ranges *rp = &pbm->pbm_ranges[rng];
-			int space = (rp->child_phys_hi >> 24) & 3;
+			struct linux_prom_pci_ranges *rngp = &pbm->pbm_ranges[rng];
+			int space = (rngp->child_phys_hi >> 24) & 3;
 
 			if(space == bustype) {
-				pci_addr += ((u64)rp->parent_phys_lo);
-				pci_addr += (((u64)rp->parent_phys_hi) << 32UL);
+				pci_addr += ((u64)rngp->parent_phys_lo);
+				pci_addr += (((u64)rngp->parent_phys_hi) << 32UL);
 				break;
 			}
 		}
@@ -1246,15 +1506,31 @@
 			 */
 			pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp);
 			pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1);
-		} else
-			pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
-
-		/* Preserve I/O space bit. */
-		if(bustype == 0x1) {
-			pdev->base_address[brindex] |= 1;
-			IO_seen = 1;
 		} else {
-			MEM_seen = 1;
+			struct resource *root, *rp;
+
+			rp = &pdev->resource[brindex];
+
+			pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + (brindex * 4), &rtmp);
+			if (rtmp & 0x1)
+				rtmp &= 0x1;
+			else
+				rtmp &= 0xf;
+
+			rp->name = pdev->name;
+			rp->start = (unsigned long)__va(pci_addr);
+			rp->end = rp->start + pci_size - 1;
+
+			/* Keep track of what we've seen so far. */
+			if(rtmp & 0x1) {
+				IO_seen = 1;
+				root = &ioport_resource;
+			} else {
+				MEM_seen = 1;
+				root = &iomem_resource;
+			}
+			rp->flags = rtmp;
+			request_resource(root, rp);
 		}
 	}
 
@@ -1267,28 +1543,32 @@
 		int breg;
 
 		for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
+			struct resource *rp;
 			int io;
 
 			ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
-			base = (unsigned int)pdev->base_address[ridx];
+			rp = &pdev->resource[ridx];
+			base = (unsigned int)rp->start;
 
-			if(pdev->base_address[ridx] > PAGE_OFFSET)
+			/* Already handled? */
+			if(rp->start > PAGE_OFFSET)
 				continue;
 
-			io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
-			base &= ~((io ?
-				   PCI_BASE_ADDRESS_IO_MASK :
-				   PCI_BASE_ADDRESS_MEM_MASK));
+			pci_read_config_dword(pdev, breg, &rtmp);
+			io = (rtmp & 0x1);
 			offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
 			vp = pci_find_vma(pbm, base, offset, io);
 			if(!vp || vp->start > base) {
 				unsigned int size, new_base;
 
-				pci_read_config_dword(pdev, breg, &rtmp);
 				pci_write_config_dword(pdev, breg, 0xffffffff);
 				pci_read_config_dword(pdev, breg, &size);
+
 				if(io)
-					size &= ~1;
+					size &= ~0x1;
+				else
+					size &= ~0xf;
+
 				size = (~(size) + 1);
 				if(!size)
 					continue;
@@ -1332,17 +1612,17 @@
 				/* Apply PBM ranges and update pci_dev. */
 				pci_addr = new_base;
 				for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
-					struct linux_prom_pci_ranges *rp;
+					struct linux_prom_pci_ranges *rngp;
 					int rspace;
 
-					rp = &pbm->pbm_ranges[rng];
-					rspace = (rp->child_phys_hi >> 24) & 3;
+					rngp = &pbm->pbm_ranges[rng];
+					rspace = (rngp->child_phys_hi >> 24) & 3;
 					if(io && rspace != 1)
 						continue;
 					else if(!io && rspace != 2)
 						continue;
-					pci_addr += ((u64)rp->parent_phys_lo);
-					pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
+					pci_addr += ((u64)rngp->parent_phys_lo);
+					pci_addr += (((u64)rngp->parent_phys_hi)<<32UL);
 					break;
 				}
 				if(rng == pbm->num_pbm_ranges) {
@@ -1350,14 +1630,19 @@
 					prom_printf("fixup_doit: YIEEE, cannot find "
 						    "PBM ranges\n");
 				}
-				pdev->base_address[ridx] = (unsigned long)__va(pci_addr);
+				rp->name = pdev->name;
+				rp->start = (unsigned long) __va(pci_addr);
+				rp->end = rp->start + size - 1;
 
-				/* Preserve I/O space bit. */
+				/* Keep track of what we've seen so far. */
 				if(io) {
-					pdev->base_address[ridx] |= 1;
 					IO_seen = 1;
+					rp->flags = rtmp & 0x1;
+					request_resource(&ioport_resource, rp);
 				} else {
 					MEM_seen = 1;
+					rp->flags = rtmp & 0xf;
+					request_resource(&iomem_resource, rp);
 				}
 			}
 		}
@@ -1420,15 +1705,15 @@
 			/* Apply PBM ranges and update pci_dev. */
 			pci_addr = new_base;
 			for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
-				struct linux_prom_pci_ranges *rp;
+				struct linux_prom_pci_ranges *rngp;
 				int rspace;
 
-				rp = &pbm->pbm_ranges[rng];
-				rspace = (rp->child_phys_hi >> 24) & 3;
+				rngp = &pbm->pbm_ranges[rng];
+				rspace = (rngp->child_phys_hi >> 24) & 3;
 				if(rspace != 2)
 					continue;
-				pci_addr += ((u64)rp->parent_phys_lo);
-				pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
+				pci_addr += ((u64)rngp->parent_phys_lo);
+				pci_addr += (((u64)rngp->parent_phys_hi)<<32UL);
 				break;
 			}
 			if(rng == pbm->num_pbm_ranges) {
@@ -1471,8 +1756,8 @@
 #ifdef FIXUP_REGS_DEBUG
 	dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device);
 	for(preg = 0; preg < 6; preg++) {
-		if(pdev->base_address[preg] != 0)
-			dprintf("%d[%016lx] ", preg, pdev->base_address[preg]);
+		if(pdev->resource[preg].start != 0)
+			dprintf("%d[%016lx] ", preg, pdev->resource[preg].start);
 	}
 	dprintf("\n");
 #endif
@@ -2119,9 +2404,10 @@
 static inline int
 sabre_out_of_range(unsigned char devfn)
 {
-	return ((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
-	       ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
-	       (PCI_SLOT(devfn) > 1);
+	return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
+		((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
+		(PCI_SLOT(devfn) > 1) ||
+		(pci_probe_enable == 0));
 }
 
 static int
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.3.12/linux/arch/sparc64/kernel/ptrace.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/ptrace.c	Mon Aug  2 22:07:16 1999
@@ -52,7 +52,7 @@
 static inline void
 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
 {
-	if (current->tss.flags & SPARC_FLAG_32BIT) {
+	if (current->thread.flags & SPARC_FLAG_32BIT) {
 		if(put_user(value, (unsigned int *)addr))
 			return pt_error_return(regs, EFAULT);
 	} else {
@@ -114,7 +114,7 @@
 	unsigned long addr2 = regs->u_regs[UREG_I4];
 	struct task_struct *child;
 
-	if (current->tss.flags & SPARC_FLAG_32BIT) {
+	if (current->thread.flags & SPARC_FLAG_32BIT) {
 		addr &= 0xffffffffUL;
 		data &= 0xffffffffUL;
 		addr2 &= 0xffffffffUL;
@@ -220,7 +220,7 @@
 		goto out;
 	}
 
-	if(!(child->tss.flags & SPARC_FLAG_32BIT)	&&
+	if(!(child->thread.flags & SPARC_FLAG_32BIT)	&&
 	   ((request == PTRACE_READDATA64)		||
 	    (request == PTRACE_WRITEDATA64)		||
 	    (request == PTRACE_READTEXT64)		||
@@ -242,7 +242,7 @@
 		int res, copied;
 
 		res = -EIO;
-		if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (current->thread.flags & SPARC_FLAG_32BIT) {
 			copied = access_process_vm(child, addr,
 						   &tmp32, sizeof(tmp32), 0);
 			tmp64 = (unsigned long) tmp32;
@@ -267,7 +267,7 @@
 		unsigned int tmp32;
 		int copied, res = -EIO;
 
-		if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (current->thread.flags & SPARC_FLAG_32BIT) {
 			tmp32 = data;
 			copied = access_process_vm(child, addr,
 						   &tmp32, sizeof(tmp32), 1);
@@ -289,7 +289,7 @@
 
 	case PTRACE_GETREGS: {
 		struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
-		struct pt_regs *cregs = child->tss.kregs;
+		struct pt_regs *cregs = child->thread.kregs;
 		int rval;
 
 		if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
@@ -313,7 +313,7 @@
 
 	case PTRACE_GETREGS64: {
 		struct pt_regs *pregs = (struct pt_regs *) addr;
-		struct pt_regs *cregs = child->tss.kregs;
+		struct pt_regs *cregs = child->thread.kregs;
 		int rval;
 
 		if (__put_user(cregs->tstate, (&pregs->tstate)) ||
@@ -337,7 +337,7 @@
 
 	case PTRACE_SETREGS: {
 		struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
-		struct pt_regs *cregs = child->tss.kregs;
+		struct pt_regs *cregs = child->thread.kregs;
 		unsigned int psr, pc, npc, y;
 		int i;
 
@@ -370,7 +370,7 @@
 
 	case PTRACE_SETREGS64: {
 		struct pt_regs *pregs = (struct pt_regs *) addr;
-		struct pt_regs *cregs = child->tss.kregs;
+		struct pt_regs *cregs = child->thread.kregs;
 		unsigned long tstate, tpc, tnpc, y;
 		int i;
 
@@ -418,7 +418,7 @@
 
 		if (copy_to_user(&fps->regs[0], fpregs,
 				 (32 * sizeof(unsigned int))) ||
-		    __put_user(child->tss.xfsr[0], (&fps->fsr)) ||
+		    __put_user(child->thread.xfsr[0], (&fps->fsr)) ||
 		    __put_user(0, (&fps->fpqd)) ||
 		    __put_user(0, (&fps->flags)) ||
 		    __put_user(0, (&fps->extra)) ||
@@ -439,7 +439,7 @@
 
 		if (copy_to_user(&fps->regs[0], fpregs,
 				 (64 * sizeof(unsigned int))) ||
-		    __put_user(child->tss.xfsr[0], (&fps->fsr))) {
+		    __put_user(child->thread.xfsr[0], (&fps->fsr))) {
 			pt_error_return(regs, EFAULT);
 			goto out;
 		}
@@ -468,11 +468,11 @@
 			pt_error_return(regs, EFAULT);
 			goto out;
 		}
-		child->tss.xfsr[0] &= 0xffffffff00000000UL;
-		child->tss.xfsr[0] |= fsr;
-		if (!(child->tss.fpsaved[0] & FPRS_FEF))
-			child->tss.gsr[0] = 0;
-		child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
+		child->thread.xfsr[0] &= 0xffffffff00000000UL;
+		child->thread.xfsr[0] |= fsr;
+		if (!(child->thread.fpsaved[0] & FPRS_FEF))
+			child->thread.gsr[0] = 0;
+		child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
 		pt_succ_return(regs, 0);
 		goto out;
 	}
@@ -486,13 +486,13 @@
 
 		if (copy_from_user(fpregs, &fps->regs[0],
 				   (64 * sizeof(unsigned int))) ||
-		    __get_user(child->tss.xfsr[0], (&fps->fsr))) {
+		    __get_user(child->thread.xfsr[0], (&fps->fsr))) {
 			pt_error_return(regs, EFAULT);
 			goto out;
 		}
-		if (!(child->tss.fpsaved[0] & FPRS_FEF))
-			child->tss.gsr[0] = 0;
-		child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
+		if (!(child->thread.fpsaved[0] & FPRS_FEF))
+			child->thread.gsr[0] = 0;
+		child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
 		pt_succ_return(regs, 0);
 		goto out;
 	}
@@ -538,11 +538,11 @@
 				goto out;
 			}
 #ifdef DEBUG_PTRACE
-			printk ("Original: %016lx %016lx\n", child->tss.kregs->tpc, child->tss.kregs->tnpc);
+			printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc);
 			printk ("Continuing with %016lx %016lx\n", addr, addr+4);
 #endif
-			child->tss.kregs->tpc = addr;
-			child->tss.kregs->tnpc = addr + 4;
+			child->thread.kregs->tpc = addr;
+			child->thread.kregs->tnpc = addr + 4;
 		}
 
 		if (request == PTRACE_SYSCALL)
@@ -554,8 +554,8 @@
 #ifdef DEBUG_PTRACE
 		printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
 			child->pid, child->exit_code,
-			child->tss.kregs->tpc,
-			child->tss.kregs->tnpc);
+			child->thread.kregs->tpc,
+			child->thread.kregs->tnpc);
 		       
 #endif
 		wake_up_process(child);
@@ -634,7 +634,7 @@
 		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	current->tss.flags ^= MAGIC_CONSTANT;
+	current->thread.flags ^= MAGIC_CONSTANT;
 	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.3.12/linux/arch/sparc64/kernel/rtrap.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/kernel/rtrap.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.46 1999/05/25 16:53:20 jj Exp $
+/* $Id: rtrap.S,v 1.47 1999/07/30 09:35:23 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -11,6 +11,7 @@
 #include <asm/spitfire.h>
 #include <asm/head.h>
 #include <asm/visasm.h>
+#include <asm/processor.h>
 
 #define		PTREGS_OFF		(STACK_BIAS + REGWIN_SZ)
 
@@ -39,13 +40,13 @@
 		be,pt			%icc, to_user
 		 andn			%l7, PSTATE_IE, %l7
 
-		ldub			[%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
 		brz,pt			%l5, rt_continue
 		 srl			%l5, 1, %o0
-		add			%g6, AOFF_task_tss + AOFF_thread_fpsaved, %l6
+		add			%g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
 		ldub			[%l6 + %o0], %l2
 		sub			%l5, 2, %l5
-		add			%g6, AOFF_task_tss + AOFF_thread_gsr, %o1
+		add			%g6, AOFF_task_thread + AOFF_thread_gsr, %o1
 		andcc			%l2, (FPRS_FEF|FPRS_DU), %g0
 		be,pt			%icc, 2f
 		 and			%l2, FPRS_DL, %l6
@@ -55,7 +56,7 @@
 		rd			%fprs, %g5
 		wr			%g5, FPRS_FEF, %fprs
 		ldub			[%o1 + %o0], %g5
-		add			%g6, AOFF_task_tss + AOFF_thread_xfsr, %o1
+		add			%g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
 		membar			#StoreLoad | #LoadLoad
 		sll			%o0, 8, %o2
 		add			%g6, AOFF_task_fpregs, %o3
@@ -71,9 +72,8 @@
 		ldda			[%o4 + %o2] ASI_BLK_P, %f48
 1:		membar			#Sync
 		ldx			[%o1 + %o5], %fsr
-2:		stb			%l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
-rt_continue:	lduh			[%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
-		ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
+2:		stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
+rt_continue:	ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
 		ldx			[%sp + PTREGS_OFF + PT_V9_G2], %g2
 		ldx			[%sp + PTREGS_OFF + PT_V9_G3], %g3
 		mov			%g6, %o5
@@ -105,10 +105,11 @@
 		wrpr			%o2, %g0, %tnpc
 		brnz,pn			%l3, kern_rtt
 		 mov			PRIMARY_CONTEXT, %l7
+		ldxa			[%l7 + %l7] ASI_DMMU, %l0
 		stxa			%l0, [%l7] ASI_DMMU
 		flush			%o5
-		rdpr			%wstate, %l1
 
+		rdpr			%wstate, %l1
 		rdpr			%otherwin, %l2
 		srl			%l1, 3, %l1
 		wrpr			%l2, %g0, %canrestore
@@ -116,8 +117,8 @@
 		wrpr			%g0, %g0, %otherwin
 		restore
 		rdpr			%canrestore, %g1
-		wrpr			%g1, 0x0, %cleanwin
 
+		wrpr			%g1, 0x0, %cleanwin
 		retry
 kern_rtt:	restore
 		retry
@@ -125,8 +126,8 @@
 		wrpr			%l7, PSTATE_IE, %pstate
 		orcc			%g0, %l0, %g0
 		be,a,pt			%xcc, check_signal
-		 lduw			[%g6 + AOFF_task_sigpending], %l0
 
+		 lduw			[%g6 + AOFF_task_sigpending], %l0
 		call			schedule
 		 nop
 		lduw			[%g6 + AOFF_task_sigpending], %l0
@@ -146,7 +147,7 @@
 		 */
 check_user_wins:
 		wrpr			%l7, 0x0, %pstate
-		lduh			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
 		brz,pt			%o2, 1f
 		 sethi			%hi(TSTATE_PEF), %l6
 
@@ -162,8 +163,8 @@
 		call			rtrap_check
 		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
 #endif
-		lduh			[%g6 + AOFF_task_tss + AOFF_thread_flags], %l5
-		andcc			%l5, 0x200, %g0
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
+		andcc			%l5, SPARC_FLAG_PERFCTR, %g0
 		be,pt			%xcc, 1f
 		 nop
 
@@ -172,7 +173,7 @@
 		call			update_perfctrs
 		 nop
 		wrpr			%l7, 0x0, %pstate
-		lduh			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
 		brz,pt			%o2, 1f
 		 sethi			%hi(TSTATE_PEF), %l6
 		wrpr			%l7, PSTATE_IE, %pstate
@@ -182,14 +183,14 @@
 1:
 		andcc			%l1, %l6, %g0
 		be,pt			%xcc, rt_continue
-		 stb			%g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
 
 		rd			%fprs, %l5
 		andcc			%l5, FPRS_FEF, %g0
 		be,a,pn			%icc, rt_continue
 		 andn			%l1, %l6, %l1
-		ba,pt			%xcc, rt_continue+4
-		 lduh			[%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+		ba,pt			%xcc, rt_continue
+		 nop
 
 5:		wr			%g0, FPRS_FEF, %fprs
 		membar			#StoreLoad | #LoadLoad
@@ -201,6 +202,6 @@
 1:		membar			#Sync
 		wr			%g0, FPRS_DU, %fprs
 		ba,pt			%xcc, rt_continue
-		 stb			%l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
+		 stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
 
 #undef PTREGS_OFF
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.3.12/linux/arch/sparc64/kernel/setup.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/kernel/setup.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.44 1999/05/28 02:17:29 davem Exp $
+/*  $Id: setup.c,v 1.46 1999/08/02 08:39:36 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -135,17 +135,21 @@
 			 * Find process owning ctx, lookup mapping.
 			 */
 			struct task_struct *p;
+			struct mm_struct *mm = NULL;
 			pgd_t *pgdp;
 			pmd_t *pmdp;
 			pte_t *ptep;
 
-			for_each_task(p)
-				if (p->tss.ctx == ctx)
+			for_each_task(p) {
+				mm = p->mm;
+				if (CTX_HWBITS(mm->context) == ctx)
 					break;
-			if (p->tss.ctx != ctx)
+			}
+			if (!mm ||
+			    CTX_HWBITS(mm->context) != ctx)
 				goto done;
 
-			pgdp = pgd_offset(p->mm, va);
+			pgdp = pgd_offset(mm, va);
 			if (pgd_none(*pgdp))
 				goto done;
 			pmdp = pmd_offset(pgdp, va);
@@ -534,8 +538,7 @@
 	init_mm.mmap->vm_page_prot = PAGE_SHARED;
 	init_mm.mmap->vm_start = PAGE_OFFSET;
 	init_mm.mmap->vm_end = *memory_end_p;
-	init_mm.context = (unsigned long) NO_CONTEXT;
-	init_task.tss.kregs = &fake_swapper_regs;
+	init_task.thread.kregs = &fake_swapper_regs;
 
 #ifdef CONFIG_IP_PNP
 	if (!ic_set_manually) {
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.3.12/linux/arch/sparc64/kernel/signal.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/kernel/signal.c	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.41 1999/06/14 05:23:58 davem Exp $
+/*  $Id: signal.c,v 1.44 1999/08/04 07:04:13 jj Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -46,7 +46,7 @@
 asmlinkage void sparc64_set_context(struct pt_regs *regs)
 {
 	struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
-	struct thread_struct *tp = &current->tss;
+	struct thread_struct *tp = &current->thread;
 	mc_gregset_t *grp;
 	unsigned long pc, npc, tstate;
 	unsigned long fp, i7;
@@ -123,9 +123,9 @@
 			err |= copy_from_user(fpregs+16,
 			 ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
 			 (sizeof(unsigned int) * 32));
-		err |= __get_user(current->tss.xfsr[0],
+		err |= __get_user(current->thread.xfsr[0],
 				  &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
-		err |= __get_user(current->tss.gsr[0],
+		err |= __get_user(current->thread.gsr[0],
 				  &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
 		regs->tstate &= ~TSTATE_PEF;
 	}
@@ -141,7 +141,7 @@
 asmlinkage void sparc64_get_context(struct pt_regs *regs)
 {
 	struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
-	struct thread_struct *tp = &current->tss;
+	struct thread_struct *tp = &current->thread;
 	mc_gregset_t *grp;
 	mcontext_t *mcp;
 	unsigned long fp, i7;
@@ -155,7 +155,7 @@
 #if 1
 	fenab = 0; /* IMO get_context is like any other system call, thus modifies FPU state -jj */
 #else
-	fenab = (current->tss.fpsaved[0] & FPRS_FEF);
+	fenab = (current->thread.fpsaved[0] & FPRS_FEF);
 #endif
 		
 	mcp = &ucp->uc_mcontext;
@@ -205,7 +205,7 @@
 		unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
 		unsigned long fprs;
 		
-		fprs = current->tss.fpsaved[0];
+		fprs = current->thread.fpsaved[0];
 		if (fprs & FPRS_DL)
 			err |= copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
 					    (sizeof(unsigned int) * 32));
@@ -213,8 +213,8 @@
 			err |= copy_to_user(
                           ((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
 			  (sizeof(unsigned int) * 32));
-		err |= __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
-		err |= __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
+		err |= __put_user(current->thread.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
+		err |= __put_user(current->thread.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
 		err |= __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
 	}
 	if (err)
@@ -226,34 +226,17 @@
 	do_exit(SIGSEGV);
 }
 
-/* 
- * The new signal frame, intended to be used for Linux applications only
- * (we have enough in there to work with clone).
- * All the interesting bits are in the info field.
- */
-
-struct new_signal_frame {
-	struct sparc_stackf	ss;
-	__siginfo_t		info;
-	__siginfo_fpu_t *	fpu_save;
-	unsigned int		insns [2];
-	unsigned long		extramask[_NSIG_WORDS-1];
-	__siginfo_fpu_t		fpu_state;
-};
-
 struct rt_signal_frame {
 	struct sparc_stackf	ss;
-	siginfo_t		info;
+	siginfo_t	info;
 	struct pt_regs		regs;
-	sigset_t		mask;
 	__siginfo_fpu_t *	fpu_save;
-	unsigned int		insns [2];
 	stack_t			stack;
+	sigset_t		mask;
 	__siginfo_fpu_t		fpu_state;
 };
 
 /* Align macros */
-#define NF_ALIGNEDSZ  (((sizeof(struct new_signal_frame) + 7) & (~7)))
 #define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))
 
 /*
@@ -265,7 +248,7 @@
 	sigset_t saveset;
 
 #ifdef CONFIG_SPARC32_COMPAT
-	if (current->tss.flags & SPARC_FLAG_32BIT) {
+	if (current->thread.flags & SPARC_FLAG_32BIT) {
 		extern asmlinkage void _sigpause32_common(old_sigset_t32,
 							  struct pt_regs *);
 		_sigpause32_common(set, regs);
@@ -372,65 +355,12 @@
 	if (fprs & FPRS_DU)
 		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
 		       	       (sizeof(unsigned int) * 32));
-	err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr);
-	err |= __get_user(current->tss.gsr[0], &fpu->si_gsr);
-	current->tss.fpsaved[0] |= fprs;
+	err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr);
+	err |= __get_user(current->thread.gsr[0], &fpu->si_gsr);
+	current->thread.fpsaved[0] |= fprs;
 	return err;
 }
 
-void do_sigreturn(struct pt_regs *regs)
-{
-	struct new_signal_frame *sf;
-	unsigned long tpc, tnpc, tstate;
-	__siginfo_fpu_t *fpu_save;
-	sigset_t set;
-	int err;
-
-	synchronize_user_stack ();
-	sf = (struct new_signal_frame *)
-		(regs->u_regs [UREG_FP] + STACK_BIAS);
-
-	/* 1. Make sure we are not getting garbage from the user */
-	if (((unsigned long) sf) & 3)
-		goto segv;
-
-	err = get_user(tpc, &sf->info.si_regs.tpc);
-	err |= __get_user(tnpc, &sf->info.si_regs.tnpc);
-	err |= ((tpc | tnpc) & 3);
-
-	/* 2. Restore the state */
-	err |= __get_user(regs->y, &sf->info.si_regs.y);
-	err |= __get_user(tstate, &sf->info.si_regs.tstate);
-	err |= copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
-
-	/* User can only change condition codes in %tstate. */
-	regs->tstate &= ~(TSTATE_ICC);
-	regs->tstate |= (tstate & TSTATE_ICC);
-
-	err |= __get_user(fpu_save, &sf->fpu_save);
-	if (fpu_save)
-		err |= restore_fpu_state(regs, &sf->fpu_state);
-		
-	err |= __get_user(set.sig[0], &sf->info.si_mask);
-	if (_NSIG_WORDS > 1)
-		err |= __copy_from_user(&set.sig[1], &sf->extramask, sizeof(sf->extramask));
-		
-	if (err)
-		goto segv;
-
-	regs->tpc = tpc;
-	regs->tnpc = tnpc;
-
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
-	current->blocked = set;
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
-	return;
-segv:
-	send_sig(SIGSEGV, current, 1);
-}
-
 void do_rt_sigreturn(struct pt_regs *regs)
 {
 	struct rt_signal_frame *sf;
@@ -503,15 +433,15 @@
 	unsigned long fprs;
 	int err = 0;
 	
-	fprs = current->tss.fpsaved[0];
+	fprs = current->thread.fpsaved[0];
 	if (fprs & FPRS_DL)
 		err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
 				    (sizeof(unsigned int) * 32));
 	if (fprs & FPRS_DU)
 		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
 				    (sizeof(unsigned int) * 32));
-	err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr);
-	err |= __put_user(current->tss.gsr[0], &fpu->si_gsr);
+	err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr);
+	err |= __put_user(current->thread.gsr[0], &fpu->si_gsr);
 	err |= __put_user(fprs, &fpu->si_fprs);
 
 	return err;
@@ -533,77 +463,6 @@
 }
 
 static inline void
-new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
-		  int signo, sigset_t *oldset)
-{
-	struct new_signal_frame *sf;
-	int sigframe_size, err;
-
-	/* 1. Make sure everything is clean */
-	synchronize_user_stack();
-	save_and_clear_fpu();
-	
-	sigframe_size = NF_ALIGNEDSZ;
-
-	if (!(current->tss.fpsaved[0] & FPRS_FEF))
-		sigframe_size -= sizeof(__siginfo_fpu_t);
-
-	sf = (struct new_signal_frame *)get_sigframe(ka, regs, sigframe_size);
-	
-	if (invalid_frame_pointer (sf, sigframe_size))
-		goto sigill;
-
-	if (current->tss.w_saved != 0) {
-#ifdef DEBUG_SIGNALS
-		printk ("%s[%d]: Invalid user stack frame for "
-			"signal delivery.\n", current->comm, current->pid);
-#endif
-		goto sigill;
-	}
-
-	/* 2. Save the current process state */
-	err = copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
-	
-	if (current->tss.fpsaved[0] & FPRS_FEF) {
-		err |= save_fpu_state(regs, &sf->fpu_state);
-		err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
-	} else {
-		err |= __put_user(0, &sf->fpu_save);
-	}
-
-	err |= __put_user(oldset->sig[0], &sf->info.si_mask);
-	if (_NSIG_WORDS > 1)
-		err |= __copy_to_user(sf->extramask, &oldset->sig[1],
-				      sizeof(sf->extramask));
-
-	err |= copy_in_user((u64 *)sf,
-			    (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
-			    sizeof(struct reg_window));
-	if (err)
-		goto sigsegv;
-	
-	/* 3. signal handler back-trampoline and parameters */
-	regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
-	regs->u_regs[UREG_I0] = signo;
-	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
-
-	/* 5. signal handler */
-	regs->tpc = (unsigned long) ka->sa.sa_handler;
-	regs->tnpc = (regs->tpc + 4);
-
-	/* 4. return to kernel instructions */
-	regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
-	return;
-
-sigill:
-	lock_kernel();
-	do_exit(SIGILL);
-sigsegv:
-	lock_kernel();
-	do_exit(SIGSEGV);
-}
-
-static inline void
 setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
 	       int signo, sigset_t *oldset, siginfo_t *info)
 {
@@ -615,7 +474,7 @@
 	save_and_clear_fpu();
 	
 	sigframe_size = RT_ALIGNEDSZ;
-	if (!(current->tss.fpsaved[0] & FPRS_FEF))
+	if (!(current->thread.fpsaved[0] & FPRS_FEF))
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct rt_signal_frame *)get_sigframe(ka, regs, sigframe_size);
@@ -623,7 +482,7 @@
 	if (invalid_frame_pointer (sf, sigframe_size))
 		goto sigill;
 
-	if (current->tss.w_saved != 0) {
+	if (current->thread.w_saved != 0) {
 #ifdef DEBUG_SIGNALS
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
@@ -634,7 +493,7 @@
 	/* 2. Save the current process state */
 	err = copy_to_user(&sf->regs, regs, sizeof (*regs));
 
-	if (current->tss.fpsaved[0] & FPRS_FEF) {
+	if (current->thread.fpsaved[0] & FPRS_FEF) {
 		err |= save_fpu_state(regs, &sf->fpu_state);
 		err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
 	} else {
@@ -652,7 +511,12 @@
 			    (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
 			    sizeof(struct reg_window));
 
-	err |= copy_to_user(&sf->info, info, sizeof(siginfo_t));
+	if (info)
+		err |= copy_to_user(&sf->info, info, sizeof(siginfo_t));
+	else {
+		err |= __put_user(signo, &sf->info.si_signo);
+		err |= __put_user(SI_NOINFO, &sf->info.si_code);
+	}
 	if (err)
 		goto sigsegv;
 	
@@ -681,10 +545,7 @@
 				 siginfo_t *info,
 				 sigset_t *oldset, struct pt_regs *regs)
 {
-	if(ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(ka, regs, signr, oldset, info);
-	else
-		new_setup_frame(ka, regs, signr, oldset);
+	setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
 	if(ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 	if(!(ka->sa.sa_flags & SA_NOMASK)) {
@@ -785,7 +646,7 @@
 		oldset = &current->blocked;
 
 #ifdef CONFIG_SPARC32_COMPAT
-	if (current->tss.flags & SPARC_FLAG_32BIT) {
+	if (current->thread.flags & SPARC_FLAG_32BIT) {
 		extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *,
 						  unsigned long, int);
 		return do_signal32(oldset, regs, orig_i0, restart_syscall);
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.3.12/linux/arch/sparc64/kernel/signal32.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/kernel/signal32.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.48 1999/06/14 05:24:01 davem Exp $
+/*  $Id: signal32.c,v 1.50 1999/07/30 09:35:25 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -202,9 +202,9 @@
 		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
 	if (fprs & FPRS_DU)
 		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
-	err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr);
-	err |= __get_user(current->tss.gsr[0], &fpu->si_gsr);
-	current->tss.fpsaved[0] |= fprs;
+	err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr);
+	err |= __get_user(current->thread.gsr[0], &fpu->si_gsr);
+	current->thread.fpsaved[0] |= fprs;
 	return err;
 }
 
@@ -285,7 +285,7 @@
 	int err;
 
 	synchronize_user_stack();
-	if (current->tss.new_signal)
+	if (current->thread.flags & SPARC_FLAG_NEWSIGNALS)
 		return do_new_sigreturn32(regs);
 
 	scptr = (struct sigcontext32 *)
@@ -489,20 +489,20 @@
 	err |= __put_user(pc, &sc->sigc_pc);
 	err |= __put_user(npc, &sc->sigc_npc);
 	psr = tstate_to_psr (regs->tstate);
-	if(current->tss.fpsaved[0] & FPRS_FEF)
+	if(current->thread.fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sc->sigc_psr);
 	err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
 	err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
-	err |= __put_user(current->tss.w_saved, &sc->sigc_oswins);
+	err |= __put_user(current->thread.w_saved, &sc->sigc_oswins);
 #if 0
 /* w_saved is not currently used... */
-	if(current->tss.w_saved)
-		for(window = 0; window < current->tss.w_saved; window++) {
+	if(current->thread.w_saved)
+		for(window = 0; window < current->thread.w_saved; window++) {
 			sc->sigc_spbuf[window] =
-				(char *)current->tss.rwbuf_stkptrs[window];
+				(char *)current->thread.rwbuf_stkptrs[window];
 			err |= copy_to_user(&sc->sigc_wbuf[window],
-					    &current->tss.reg_window[window],
+					    &current->thread.reg_window[window],
 					    sizeof(struct reg_window));
 		}
 	else
@@ -511,15 +511,15 @@
 				    (u32 *)(regs->u_regs[UREG_FP]),
 				    sizeof(struct reg_window32));
 		       
-	current->tss.w_saved = 0; /* So process is allowed to execute. */
+	current->thread.w_saved = 0; /* So process is allowed to execute. */
 	err |= __put_user(signr, &sframep->sig_num);
 	if(signr == SIGSEGV ||
 	   signr == SIGILL ||
 	   signr == SIGFPE ||
 	   signr == SIGBUS ||
 	   signr == SIGEMT) {
-		err |= __put_user(current->tss.sig_desc, &sframep->sig_code);
-		err |= __put_user(current->tss.sig_address, &sframep->sig_address);
+		err |= __put_user(current->thread.sig_desc, &sframep->sig_code);
+		err |= __put_user(current->thread.sig_address, &sframep->sig_address);
 	} else {
 		err |= __put_user(0, &sframep->sig_code);
 		err |= __put_user(0, &sframep->sig_address);
@@ -544,15 +544,15 @@
 	unsigned long fprs;
 	int err = 0;
 	
-	fprs = current->tss.fpsaved[0];
+	fprs = current->thread.fpsaved[0];
 	if (fprs & FPRS_DL)
 		err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
 				    (sizeof(unsigned int) * 32));
 	if (fprs & FPRS_DU)
 		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
 				    (sizeof(unsigned int) * 32));
-	err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr);
-	err |= __put_user(current->tss.gsr[0], &fpu->si_gsr);
+	err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr);
+	err |= __put_user(current->thread.gsr[0], &fpu->si_gsr);
 	err |= __put_user(fprs, &fpu->si_fprs);
 
 	return err;
@@ -572,7 +572,7 @@
 	save_and_clear_fpu();
 	
 	sigframe_size = NF_ALIGNEDSZ;
-	if (!(current->tss.fpsaved[0] & FPRS_FEF))
+	if (!(current->thread.fpsaved[0] & FPRS_FEF))
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
@@ -585,7 +585,7 @@
 		goto sigill;
 	}
 
-	if (current->tss.w_saved != 0) {
+	if (current->thread.w_saved != 0) {
 #ifdef DEBUG_SIGNALS
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
@@ -598,7 +598,7 @@
 	err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
 	err |= __put_user(regs->y, &sf->info.si_regs.y);
 	psr = tstate_to_psr (regs->tstate);
-	if(current->tss.fpsaved[0] & FPRS_FEF)
+	if(current->thread.fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sf->info.si_regs.psr);
 	for (i = 0; i < 16; i++)
@@ -738,7 +738,7 @@
 	err |= __put_user(regs->tpc, &((*gr) [SVR4_PC]));
 	err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
 	psr = tstate_to_psr (regs->tstate);
-	if(current->tss.fpsaved[0] & FPRS_FEF)
+	if(current->thread.fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &((*gr) [SVR4_PSR]));
 	err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
@@ -760,7 +760,7 @@
 	err |= __put_user((u32)(long)gw, &mc->gwin);
 	    
 	/* 2. Number of windows to restore at setcontext (): */
-	err |= __put_user(current->tss.w_saved, &gw->count);
+	err |= __put_user(current->thread.w_saved, &gw->count);
 
 	/* 3. Save each valid window
 	 *    Currently, it makes a copy of the windows from the kernel copy.
@@ -774,23 +774,23 @@
 	 *    to flush the user windows.
 	 */
 #if 0	 
-	for(window = 0; window < current->tss.w_saved; window++) {
+	for(window = 0; window < current->thread.w_saved; window++) {
 		err |= __put_user((int *) &(gw->win [window]),
 				  (int **)gw->winptr +window );
 		err |= copy_to_user(&gw->win [window],
-				    &current->tss.reg_window [window],
+				    &current->thread.reg_window [window],
 				    sizeof (svr4_rwindow_t));
 		err |= __put_user(0, (int *)gw->winptr + window);
 	}
 #endif	
 
 	/* 4. We just pay attention to the gw->count field on setcontext */
-	current->tss.w_saved = 0; /* So process is allowed to execute. */
+	current->thread.w_saved = 0; /* So process is allowed to execute. */
 
 	/* Setup the signal information.  Solaris expects a bunch of
 	 * information to be passed to the signal handler, we don't provide
 	 * that much currently, should use those that David already
-	 * is providing with tss.sig_desc
+	 * is providing with thread.sig_desc
 	 */
 	err |= __put_user(signr, &si->siginfo.signo);
 	err |= __put_user(SVR4_SINOINFO, &si->siginfo.code);
@@ -837,8 +837,8 @@
 	synchronize_user_stack();
 	save_and_clear_fpu();
 	
-	if (current->tss.w_saved){
-		printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
+	if (current->thread.w_saved){
+		printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->thread.w_saved);
 		do_exit (SIGSEGV);
 	}
 	err = clear_user(uc, sizeof (*uc));
@@ -863,7 +863,7 @@
 	err |= __put_user(0, &uc->mcontext.greg [SVR4_PSR]);
 #else
 	i = tstate_to_psr(regs->tstate) & ~PSR_EF;		   
-	if (current->tss.fpsaved[0] & FPRS_FEF)
+	if (current->thread.fpsaved[0] & FPRS_FEF)
 		i |= PSR_EF;
 	err |= __put_user(i, &uc->mcontext.greg [SVR4_PSR]);
 #endif
@@ -890,7 +890,7 @@
 /* Set the context for a svr4 application, this is Solaris way to sigreturn */
 asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
 {
-	struct thread_struct *tp = &current->tss;
+	struct thread_struct *tp = &current->thread;
 	svr4_gregset_t  *gr;
 	u32 pc, npc, psr;
 	sigset_t set;
@@ -990,7 +990,7 @@
 	save_and_clear_fpu();
 	
 	sigframe_size = RT_ALIGNEDSZ;
-	if (!(current->tss.fpsaved[0] & FPRS_FEF))
+	if (!(current->thread.fpsaved[0] & FPRS_FEF))
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
@@ -1003,7 +1003,7 @@
 		goto sigill;
 	}
 
-	if (current->tss.w_saved != 0) {
+	if (current->thread.w_saved != 0) {
 #ifdef DEBUG_SIGNALS
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
@@ -1016,7 +1016,7 @@
 	err |= __put_user(regs->tnpc, &sf->regs.npc);
 	err |= __put_user(regs->y, &sf->regs.y);
 	psr = tstate_to_psr (regs->tstate);
-	if(current->tss.fpsaved[0] & FPRS_FEF)
+	if(current->thread.fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sf->regs.psr);
 	for (i = 0; i < 16; i++)
@@ -1032,6 +1032,42 @@
 	} else {
 		err |= __put_user(0, &sf->fpu_save);
 	}
+
+	err = __put_user (info->si_signo, &sf->info.si_signo);
+	err |= __put_user (info->si_errno, &sf->info.si_errno);
+	err |= __put_user (info->si_code, &sf->info.si_code);
+	if (info->si_code < 0)
+		err |= __copy_to_user (sf->info._sifields._pad, info->_sifields._pad, SI_PAD_SIZE);
+	else {
+		i = info->si_signo;
+		if (info->si_code == SI_USER)
+			i = SIGRTMIN;
+		switch (i) {
+		case SIGPOLL:
+			err |= __put_user (info->si_band, &sf->info.si_band);
+			err |= __put_user (info->si_fd, &sf->info.si_fd);
+			break;
+		case SIGCHLD:
+			err |= __put_user (info->si_pid, &sf->info.si_pid);
+			err |= __put_user (info->si_uid, &sf->info.si_uid);
+			err |= __put_user (info->si_status, &sf->info.si_status);
+			err |= __put_user (info->si_utime, &sf->info.si_utime);
+			err |= __put_user (info->si_stime, &sf->info.si_stime);
+			break;
+		case SIGSEGV:
+		case SIGILL:
+		case SIGFPE:
+		case SIGBUS:
+		case SIGEMT:
+			err |= __put_user ((long)info->si_addr, &sf->info.si_addr);
+			err |= __put_user (info->si_trapno, &sf->info.si_trapno);
+			break;
+		default:
+			err |= __put_user (info->si_pid, &sf->info.si_pid);
+			err |= __put_user (info->si_uid, &sf->info.si_uid);
+			break;
+		}
+	}
 	
 	/* Setup sigaltstack */
 	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
@@ -1040,13 +1076,13 @@
 
 	switch (_NSIG_WORDS) {
 	case 4: seta.sig[7] = (oldset->sig[3] >> 32);
-	        seta.sig[6] = oldset->sig[3];
+		seta.sig[6] = oldset->sig[3];
 	case 3: seta.sig[5] = (oldset->sig[2] >> 32);
-	        seta.sig[4] = oldset->sig[2];
+		seta.sig[4] = oldset->sig[2];
 	case 2: seta.sig[3] = (oldset->sig[1] >> 32);
-	        seta.sig[2] = oldset->sig[1];
+		seta.sig[2] = oldset->sig[1];
 	case 1: seta.sig[1] = (oldset->sig[0] >> 32);
-	        seta.sig[0] = oldset->sig[0];
+		seta.sig[0] = oldset->sig[0];
 	}
 	err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t));
 
@@ -1113,7 +1149,7 @@
 	else {
 		if (ka->sa.sa_flags & SA_SIGINFO)
 			setup_rt_frame32(ka, regs, signr, oldset, info);
-		else if (current->tss.new_signal)
+		else if (current->thread.flags & SPARC_FLAG_NEWSIGNALS)
 			new_setup_frame32(ka, regs, signr, oldset);
 		else
 			setup_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset);
@@ -1256,13 +1292,13 @@
 			if(signr != SIGCHLD)
 				continue;
 
-                        /* sys_wait4() grabs the master kernel lock, so
-                         * we need not do so, that sucker should be
-                         * threaded and would not be that difficult to
-                         * do anyways.
-                         */
-                        while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-                                ;
+			/* sys_wait4() grabs the master kernel lock, so
+			 * we need not do so, that sucker should be
+			 * threaded and would not be that difficult to
+			 * do anyways.
+			 */
+			while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+				;
 			continue;
 		}
 		if(ka->sa.sa_handler == SIG_DFL) {
@@ -1312,10 +1348,10 @@
 				{
 					struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff);
 					unsigned int ins[8];
-                                                
+
 					while(rw &&
 					      !(((unsigned long) rw) & 0x3)) {
-					        copy_from_user(ins, &rw->ins[0], sizeof(ins));
+						copy_from_user(ins, &rw->ins[0], sizeof(ins));
 						printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
 						rw = (struct reg_window32 *)(unsigned long)ins[6];
 					}
@@ -1374,7 +1410,7 @@
 	/* Now see if we want to update the new state. */
 	if (ssptr) {
 		void *ss_sp;
-	               
+
 		if (get_user((long)ss_sp, &ssptr->the_stack))
 			goto out;
 		/* If the current stack was set with sigaltstack, don't
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.12/linux/arch/sparc64/kernel/smp.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/smp.c	Mon Aug  2 22:07:16 1999
@@ -53,7 +53,7 @@
 int smp_num_cpus = 1;
 int smp_threads_ready = 0;
 
-__initfunc(void smp_setup(char *str, int *ints))
+void __init smp_setup(char *str, int *ints)
 {
 	/* XXX implement me XXX */
 }
@@ -151,13 +151,17 @@
 	/* Clear this or we will die instantly when we
 	 * schedule back to this idler...
 	 */
-	current->tss.flags &= ~(SPARC_FLAG_NEWCHILD);
+	current->thread.flags &= ~(SPARC_FLAG_NEWCHILD);
+
+	/* Attach to the address space of init_task. */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
 
 	while(!smp_processors_ready)
 		membar("#LoadLoad");
 }
 
-extern int cpu_idle(void *unused);
+extern int cpu_idle(void);
 extern void init_IRQ(void);
 
 void initialize_secondary(void)
@@ -169,7 +173,7 @@
 	trap_init();
 	init_IRQ();
 	smp_callin();
-	return cpu_idle(NULL);
+	return cpu_idle();
 }
 
 void cpu_panic(void)
@@ -216,9 +220,17 @@
 			entry += phys_base - KERNBASE;
 			cookie += phys_base - KERNBASE;
 			kernel_thread(start_secondary, NULL, CLONE_PID);
-			p = task[++cpucount];
+			cpucount++;
+
+			p = init_task.prev_task;
+			init_tasks[cpucount] = p;
+
 			p->processor = i;
 			p->has_cpu = 1; /* we schedule the first task manually */
+
+			del_from_runqueue(p);
+			unhash_process(p);
+
 			callin_flag = 0;
 			for (no = 0; no < linux_num_cpus; no++)
 				if (linux_cpus[no].mid == i)
@@ -384,6 +396,9 @@
  * are flush_tlb_*() routines, and these run after flush_cache_*()
  * which performs the flushw.
  *
+ * XXX I diked out the fancy flush avoidance code for the
+ * XXX swapping cases for now until the new MM code stabilizes. -DaveM
+ *
  * The SMP TLB coherency scheme we use works as follows:
  *
  * 1) mm->cpu_vm_mask is a bit mask of which cpus an address
@@ -395,16 +410,16 @@
  *    cross calls.
  *
  *    One invariant is that when a cpu switches to a process, and
- *    that processes tsk->mm->cpu_vm_mask does not have the current
- *    cpu's bit set, that tlb context is flushed locally.
+ *    that processes tsk->active_mm->cpu_vm_mask does not have the
+ *    current cpu's bit set, that tlb context is flushed locally.
  *
  *    If the address space is non-shared (ie. mm->count == 1) we avoid
  *    cross calls when we want to flush the currently running process's
  *    tlb state.  This is done by clearing all cpu bits except the current
- *    processor's in current->mm->cpu_vm_mask and performing the flush
- *    locally only.  This will force any subsequent cpus which run this
- *    task to flush the context from the local tlb if the process migrates
- *    to another cpu (again).
+ *    processor's in current->active_mm->cpu_vm_mask and performing the
+ *    flush locally only.  This will force any subsequent cpus which run
+ *    this task to flush the context from the local tlb if the process
+ *    migrates to another cpu (again).
  *
  * 3) For shared address spaces (threads) and swapping we bite the
  *    bullet for most cases and perform the cross call.
@@ -422,13 +437,13 @@
  */
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
-	u32 ctx = mm->context & 0x3ff;
+	u32 ctx = CTX_HWBITS(mm->context);
 
-	if(mm == current->mm && atomic_read(&mm->count) == 1) {
-		if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-			mm->cpu_vm_mask = (1UL << smp_processor_id());
+	if (mm == current->active_mm &&
+	    atomic_read(&mm->mm_users) == 1 &&
+	    (mm->cpu_vm_mask == (1UL << smp_processor_id())))
 		goto local_flush_and_out;
-	}
+
 	smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
 
 local_flush_and_out:
@@ -438,15 +453,15 @@
 void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 			 unsigned long end)
 {
-	u32 ctx = mm->context & 0x3ff;
+	u32 ctx = CTX_HWBITS(mm->context);
 
 	start &= PAGE_MASK;
 	end   &= PAGE_MASK;
-	if(mm == current->mm && atomic_read(&mm->count) == 1) {
-		if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-			mm->cpu_vm_mask = (1UL << smp_processor_id());
+	if(mm == current->active_mm &&
+	   atomic_read(&mm->mm_users) == 1 &&
+	   (mm->cpu_vm_mask == (1UL << smp_processor_id())))
 		goto local_flush_and_out;
-	}
+
 	smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
 
 local_flush_and_out:
@@ -455,30 +470,15 @@
 
 void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
-	u32 ctx = mm->context & 0x3ff;
+	u32 ctx = CTX_HWBITS(mm->context);
 
 	page &= PAGE_MASK;
-	if(mm == current->mm && atomic_read(&mm->count) == 1) {
-		if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-			mm->cpu_vm_mask = (1UL << smp_processor_id());
+	if(mm == current->active_mm &&
+	   atomic_read(&mm->mm_users) == 1 &&
+	   (mm->cpu_vm_mask == (1UL << smp_processor_id()))) {
 		goto local_flush_and_out;
-	} else {
-		/* Try to handle two special cases to avoid cross calls
-		 * in common scenerios where we are swapping process
-		 * pages out.
-		 */
-		if(((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK) ||
-		   (mm->cpu_vm_mask == 0)) {
-			/* A dead context cannot ever become "alive" until
-			 * a task switch is done to it.
-			 */
-			return; /* It's dead, nothing to do. */
-		}
-		if(mm->cpu_vm_mask == (1UL << smp_processor_id())) {
-			__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
-			return; /* Only local flush is necessary. */
-		}
 	}
+
 	smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 
 local_flush_and_out:
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.12/linux/arch/sparc64/kernel/sparc64_ksyms.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.60 1999/07/03 22:11:12 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.62 1999/08/06 01:42:48 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -215,7 +215,6 @@
 
 /* Kernel thread creation. */
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(init_mm);
 
 /* prom symbols */
 EXPORT_SYMBOL(idprom);
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.3.12/linux/arch/sparc64/kernel/sys_sparc.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/kernel/sys_sparc.c	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.27 1999/06/02 12:06:34 jj Exp $
+/* $Id: sys_sparc.c,v 1.29 1999/08/04 07:04:10 jj Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -41,7 +41,9 @@
 
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
-	if(brk >= 0x80000000000UL)	/* VM hole */
+	if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) ||
+	   (brk - current->mm->brk > 0x80000000000UL &&
+	    brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */
 		return current->mm->brk;
 	return sys_brk(brk);
 }
@@ -170,7 +172,7 @@
 	}
 
 	retval = -EINVAL;
-	if (current->tss.flags & SPARC_FLAG_32BIT) {
+	if (current->thread.flags & SPARC_FLAG_32BIT) {
 		if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
 			goto out_putf;
 	} else {
@@ -178,7 +180,7 @@
 		    (addr < 0x80000000000UL &&
 		     addr > 0x80000000000UL-len))
 			goto out_putf;
-		if (addr >= 0x80000000000ULL && addr < 0xfffff80000000000UL) {
+		if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) {
 			/* VM hole */
 			retval = current->mm->brk;
 			goto out_putf;
@@ -281,40 +283,40 @@
 		return -EINVAL;
 	if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
 		if (old_p) {
-			if (!current->tss.utraps)
+			if (!current->thread.utraps)
 				put_user_ret(NULL, old_p, -EFAULT);
 			else
-				put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
+				put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
 		}
 		if (old_d)
 			put_user_ret(NULL, old_d, -EFAULT);
 		return 0;
 	}
 	lock_kernel();
-	if (!current->tss.utraps) {
-		current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
-		if (!current->tss.utraps) return -ENOMEM;
-		current->tss.utraps[0] = 1;
-		memset(current->tss.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
+	if (!current->thread.utraps) {
+		current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
+		if (!current->thread.utraps) return -ENOMEM;
+		current->thread.utraps[0] = 1;
+		memset(current->thread.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
 	} else {
-		if ((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] > 1) {
-			long *p = current->tss.utraps;
+		if ((utrap_handler_t)current->thread.utraps[type] != new_p && current->thread.utraps[0] > 1) {
+			long *p = current->thread.utraps;
 			
-			current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
-			if (!current->tss.utraps) {
-				current->tss.utraps = p;
+			current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
+			if (!current->thread.utraps) {
+				current->thread.utraps = p;
 				return -ENOMEM;
 			}
 			p[0]--;
-			current->tss.utraps[0] = 1;
-			memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
+			current->thread.utraps[0] = 1;
+			memcpy(current->thread.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
 		}
 	}
 	if (old_p)
-		put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
+		put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
 	if (old_d)
 		put_user_ret(NULL, old_d, -EFAULT);
-	current->tss.utraps[type] = (long)new_p;
+	current->thread.utraps[type] = (long)new_p;
 	unlock_kernel();
 	return 0;
 }
@@ -363,10 +365,10 @@
 	unsigned long pic, tmp;
 
 	read_pic(pic);
-	tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
-	__put_user(tmp, current->tss.user_cntd0);
-	tmp = (current->tss.kernel_cntd1 += (pic >> 32));
-	__put_user(tmp, current->tss.user_cntd1);
+	tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
+	__put_user(tmp, current->thread.user_cntd0);
+	tmp = (current->thread.kernel_cntd1 += (pic >> 32));
+	__put_user(tmp, current->thread.user_cntd1);
 	reset_pic();
 }
 
@@ -377,24 +379,24 @@
 
 	switch(opcode) {
 	case PERFCTR_ON:
-		current->tss.pcr_reg = arg2;
-		current->tss.user_cntd0 = (u64 *) arg0;
-		current->tss.user_cntd1 = (u64 *) arg1;
-		current->tss.kernel_cntd0 =
-			current->tss.kernel_cntd1 = 0;
+		current->thread.pcr_reg = arg2;
+		current->thread.user_cntd0 = (u64 *) arg0;
+		current->thread.user_cntd1 = (u64 *) arg1;
+		current->thread.kernel_cntd0 =
+			current->thread.kernel_cntd1 = 0;
 		write_pcr(arg2);
 		reset_pic();
-		current->tss.flags |= SPARC_FLAG_PERFCTR;
+		current->thread.flags |= SPARC_FLAG_PERFCTR;
 		break;
 
 	case PERFCTR_OFF:
 		err = -EINVAL;
-		if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) {
-			current->tss.user_cntd0 =
-				current->tss.user_cntd1 = NULL;
-			current->tss.pcr_reg = 0;
+		if ((current->thread.flags & SPARC_FLAG_PERFCTR) != 0) {
+			current->thread.user_cntd0 =
+				current->thread.user_cntd1 = NULL;
+			current->thread.pcr_reg = 0;
 			write_pcr(0);
-			current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+			current->thread.flags &= ~(SPARC_FLAG_PERFCTR);
 			err = 0;
 		}
 		break;
@@ -402,50 +404,50 @@
 	case PERFCTR_READ: {
 		unsigned long pic, tmp;
 
-		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
 		read_pic(pic);
-		tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
-		err |= __put_user(tmp, current->tss.user_cntd0);
-		tmp = (current->tss.kernel_cntd1 += (pic >> 32));
-		err |= __put_user(tmp, current->tss.user_cntd1);
+		tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
+		err |= __put_user(tmp, current->thread.user_cntd0);
+		tmp = (current->thread.kernel_cntd1 += (pic >> 32));
+		err |= __put_user(tmp, current->thread.user_cntd1);
 		reset_pic();
 		break;
 	}
 
 	case PERFCTR_CLRPIC:
-		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
-		current->tss.kernel_cntd0 =
-			current->tss.kernel_cntd1 = 0;
+		current->thread.kernel_cntd0 =
+			current->thread.kernel_cntd1 = 0;
 		reset_pic();
 		break;
 
 	case PERFCTR_SETPCR: {
 		u64 *user_pcr = (u64 *)arg0;
-		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
-		err |= __get_user(current->tss.pcr_reg, user_pcr);
-		write_pcr(current->tss.pcr_reg);
-		current->tss.kernel_cntd0 =
-			current->tss.kernel_cntd1 = 0;
+		err |= __get_user(current->thread.pcr_reg, user_pcr);
+		write_pcr(current->thread.pcr_reg);
+		current->thread.kernel_cntd0 =
+			current->thread.kernel_cntd1 = 0;
 		reset_pic();
 		break;
 	}
 
 	case PERFCTR_GETPCR: {
 		u64 *user_pcr = (u64 *)arg0;
-		if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
-		err |= __put_user(current->tss.pcr_reg, user_pcr);
+		err |= __put_user(current->thread.pcr_reg, user_pcr);
 		break;
 	}
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.12/linux/arch/sparc64/kernel/sys_sparc32.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.112 1999/06/29 12:34:02 davem Exp $
+/* $Id: sys_sparc32.c,v 1.117 1999/08/02 08:39:40 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1663,85 +1663,6 @@
 	return ret;
 }
 
-siginfo_t32 *
-siginfo64to32(siginfo_t32 *d, siginfo_t *s)
-{
-	memset (&d, 0, sizeof(siginfo_t32));
-	d->si_signo = s->si_signo;
-	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
-	if (s->si_signo >= SIGRTMIN) {
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
-	} else switch (s->si_signo) {
-	/* XXX: What about POSIX1.b timers */
-	case SIGCHLD:
-		d->si_pid = s->si_pid;
-		d->si_status = s->si_status;
-		d->si_utime = s->si_utime;
-		d->si_stime = s->si_stime;
-		break;
-	case SIGSEGV:
-	case SIGBUS:
-	case SIGFPE:
-	case SIGILL:
-		d->si_addr = (long)(s->si_addr);
-		/* XXX: Do we need to translate this from sparc64 to sparc32 traps? */
-		d->si_trapno = s->si_trapno;
-		break;
-	case SIGPOLL:
-		d->si_band = s->si_band;
-		d->si_fd = s->si_fd;
-		break;
-	default:
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		break;
-	}
-	return d;
-}
-
-siginfo_t *
-siginfo32to64(siginfo_t *d, siginfo_t32 *s)
-{
-	d->si_signo = s->si_signo;
-	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
-	if (s->si_signo >= SIGRTMIN) {
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
-	} else switch (s->si_signo) {
-	/* XXX: What about POSIX1.b timers */
-	case SIGCHLD:
-		d->si_pid = s->si_pid;
-		d->si_status = s->si_status;
-		d->si_utime = s->si_utime;
-		d->si_stime = s->si_stime;
-		break;
-	case SIGSEGV:
-	case SIGBUS:
-	case SIGFPE:
-	case SIGILL:
-		d->si_addr = (void *)A(s->si_addr);
-		/* XXX: Do we need to translate this from sparc32 to sparc64 traps? */
-		d->si_trapno = s->si_trapno;
-		break;
-	case SIGPOLL:
-		d->si_band = s->si_band;
-		d->si_fd = s->si_fd;
-		break;
-	default:
-		d->si_pid = s->si_pid;
-		d->si_uid = s->si_uid;
-		break;
-	}
-	return d;
-}
-
 extern asmlinkage int
 sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
 		    const struct timespec *uts, size_t sigsetsize);
@@ -1753,10 +1674,9 @@
 	sigset_t s;
 	sigset_t32 s32;
 	struct timespec t;
-	int ret;
+	int ret, err, i;
 	mm_segment_t old_fs = get_fs();
 	siginfo_t info;
-	siginfo_t32 info32;
 		
 	if (copy_from_user (&s32, uthese, sizeof(sigset_t32)))
 		return -EFAULT;
@@ -1776,8 +1696,43 @@
 	ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
 	set_fs (old_fs);
 	if (ret >= 0 && uinfo) {
-		if (copy_to_user (uinfo, siginfo64to32(&info32, &info), sizeof(siginfo_t32)))
-			return -EFAULT;
+		err = put_user (info.si_signo, &uinfo->si_signo);
+		err |= __put_user (info.si_errno, &uinfo->si_errno);
+		err |= __put_user (info.si_code, &uinfo->si_code);
+		if (info.si_code < 0)
+			err |= __copy_to_user (uinfo->_sifields._pad, info._sifields._pad, SI_PAD_SIZE);
+		else {
+			i = info.si_signo;
+			if (info.si_code == SI_USER)
+				i = SIGRTMIN;
+			switch (i) {
+			case SIGPOLL:
+				err |= __put_user (info.si_band, &uinfo->si_band);
+				err |= __put_user (info.si_fd, &uinfo->si_fd);
+				break;
+			case SIGCHLD:
+				err |= __put_user (info.si_pid, &uinfo->si_pid);
+				err |= __put_user (info.si_uid, &uinfo->si_uid);
+				err |= __put_user (info.si_status, &uinfo->si_status);
+				err |= __put_user (info.si_utime, &uinfo->si_utime);
+				err |= __put_user (info.si_stime, &uinfo->si_stime);
+				break;
+			case SIGSEGV:
+			case SIGILL:
+			case SIGFPE:
+			case SIGBUS:
+			case SIGEMT:
+				err |= __put_user ((long)info.si_addr, &uinfo->si_addr);
+				err |= __put_user (info.si_trapno, &uinfo->si_trapno);
+				break;
+			default:
+				err |= __put_user (info.si_pid, &uinfo->si_pid);
+				err |= __put_user (info.si_uid, &uinfo->si_uid);
+				break;
+			}
+		}
+		if (err)
+			ret = -EFAULT;
 	}
 	return ret;
 }
@@ -1789,14 +1744,12 @@
 sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
 {
 	siginfo_t info;
-	siginfo_t32 info32;
 	int ret;
 	mm_segment_t old_fs = get_fs();
 	
-	if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
+	if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
+	    copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
 		return -EFAULT;
-	/* XXX: Is this correct? */
-	siginfo32to64(&info, &info32);
 	set_fs (KERNEL_DS);
 	ret = sys_rt_sigqueueinfo(pid, sig, &info);
 	set_fs (old_fs);
@@ -2659,7 +2612,7 @@
         int ret;
 
 	if(sig < 0) {
-		current->tss.new_signal = 1;
+		current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
 		sig = -sig;
 	}
 
@@ -2703,7 +2656,7 @@
 	/* All tasks which use RT signals (effectively) use
 	 * new style signals.
 	 */
-	current->tss.new_signal = 1;
+	current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
 
         if (act) {
 		new_ka.ka_restorer = restorer;
@@ -2883,6 +2836,8 @@
         int error, base = 0;
         char *filename;
 
+	/* User register window flush is done by entry.S */
+
         /* Check for indirect call. */
         if((u32)regs->u_regs[UREG_G1] == 0)
                 base = 1;
@@ -2899,8 +2854,8 @@
 
 	if(!error) {
 		fprs_write(0);
-		current->tss.xfsr[0] = 0;
-		current->tss.fpsaved[0] = 0;
+		current->thread.xfsr[0] = 0;
+		current->thread.fpsaved[0] = 0;
 		regs->tstate &= ~TSTATE_PEF;
 	}
 out:
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.12/linux/arch/sparc64/kernel/sys_sunos32.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.28 1999/06/29 12:34:04 davem Exp $
+/* $Id: sys_sunos32.c,v 1.30 1999/07/30 09:35:31 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -557,9 +557,9 @@
 	struct pt_regs *regs;
 
 	lock_kernel();
-	regs = current->tss.kregs;
-	current->tss.sig_address = regs->tpc;
-	current->tss.sig_desc = regs->u_regs[UREG_G1];
+	regs = current->thread.kregs;
+	current->thread.sig_address = regs->tpc;
+	current->thread.sig_desc = regs->u_regs[UREG_G1];
 	send_sig(SIGSYS, current, 1);
 	printk("Process makes ni_syscall number %d, register dump:\n",
 	       (int) regs->u_regs[UREG_G1]);
@@ -1159,7 +1159,7 @@
 		if(!kmbuf)
 			break;
 		sp = (struct sparc_stackf32 *)
-			(current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL);
+			(current->thread.kregs->u_regs[UREG_FP] & 0xffffffffUL);
 		if(get_user(arg5, &sp->xxargs[0])) {
 			rval = -EFAULT;
 			break;
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.3.12/linux/arch/sparc64/kernel/systbls.S	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/kernel/systbls.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.54 1999/06/02 12:06:31 jj Exp $
+/* $Id: systbls.S,v 1.56 1999/07/31 00:06:17 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -59,7 +59,7 @@
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
 	.word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/	.word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
+/*210*/	.word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
 	.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
 /*220*/	.word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
 	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
@@ -112,15 +112,15 @@
 	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
 	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
 	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
 /*190*/	.word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
-/*200*/	.word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+/*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
 	.word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/	.word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
-	.word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/	.word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+/*210*/	.word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+	.word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/	.word sys_nis_syscall, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
 	.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
 /*230*/	.word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
 	.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.3.12/linux/arch/sparc64/kernel/traps.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/kernel/traps.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.60 1999/06/02 19:19:55 jj Exp $
+/* $Id: traps.c,v 1.61 1999/07/30 09:35:32 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -147,12 +147,12 @@
 			if(i)
 				printk(",");
 			if(!sdp->arg_is_string[i]) {
-				if (current->tss.flags & SPARC_FLAG_32BIT)
+				if (current->thread.flags & SPARC_FLAG_32BIT)
 					printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]);
 				else
 					printk("%016lx", regs->u_regs[UREG_I0 + i]);
 			} else {
-				if (current->tss.flags & SPARC_FLAG_32BIT)
+				if (current->thread.flags & SPARC_FLAG_32BIT)
 					strncpy_from_user(scall_strbuf,
 							  (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff),
 							  512);
@@ -178,7 +178,7 @@
 }
 #endif /* SYSCALL_TRACING */
 
-#if 0
+#if 1
 void rtrap_check(struct pt_regs *regs)
 {
 	register unsigned long pgd_phys asm("o1");
@@ -219,7 +219,7 @@
 
 	if((pgd_phys != __pa(current->mm->pgd)) ||
 	   ((pgd_cache != 0) &&
-	    (pgd_cache != pgd_val(current->mm->pgd[0]))) ||
+	    (pgd_cache != pgd_val(current->mm->pgd[0])<<11UL)) ||
 	   (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) ||
 #define KERN_HIGHBITS		((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
@@ -228,18 +228,17 @@
 #undef KERN_LOWBITS
 	   ((ctx != (current->mm->context & 0x3ff)) ||
 	    (ctx == 0) ||
-	    (current->tss.ctx != ctx))) {
+	    (CTX_HWBITS(current->mm->context) != ctx))) {
 		printk("SHIT[%s:%d]: "
-		       "(PP[%016lx] CACH[%016lx] CTX[%x] g1g3[%016lx] g2[%016lx]) ",
+		       "(PP[%016lx] CACH[%016lx] CTX[%lx] g1g3[%016lx] g2[%016lx]) ",
 		       current->comm, current->pid,
 		       pgd_phys, pgd_cache, ctx, g1_or_g3, g2);
 		printk("SHIT[%s:%d]: "
-		       "[PP[%016lx] CACH[%016lx] CTX[%x:%x]] PC[%016lx:%016lx]\n",
+		       "[PP[%016lx] CACH[%016lx] CTX[%lx]] PC[%016lx:%016lx]\n",
 		       current->comm, current->pid,
 		       __pa(current->mm->pgd),
 		       pgd_val(current->mm->pgd[0]),
 		       current->mm->context & 0x3ff,
-		       current->tss.ctx,
 		       regs->tpc, regs->tnpc);
 		show_regs(regs);
 #if 1
@@ -262,8 +261,8 @@
 	}
 	if (regs->tstate & TSTATE_PRIV)
 		die_if_kernel ("Kernel bad trap", regs);
-        current->tss.sig_desc = SUBSIG_BADTRAP(lvl - 0x100);
-        current->tss.sig_address = regs->tpc;
+        current->thread.sig_desc = SUBSIG_BADTRAP(lvl - 0x100);
+        current->thread.sig_address = regs->tpc;
         force_sig(SIGILL, current);
 	unlock_kernel ();
 }
@@ -289,8 +288,8 @@
 #endif
 		die_if_kernel("Iax", regs);
 	}
-	current->tss.sig_desc = SUBSIG_ILLINST;
-	current->tss.sig_address = regs->tpc;
+	current->thread.sig_desc = SUBSIG_ILLINST;
+	current->thread.sig_address = regs->tpc;
 	force_sig(SIGILL, current);
 	unlock_kernel();
 }
@@ -402,8 +401,8 @@
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 	} else {
-		current->tss.sig_address = regs->tpc;
-		current->tss.sig_desc = SUBSIG_FPERROR;
+		current->thread.sig_address = regs->tpc;
+		current->thread.sig_desc = SUBSIG_FPERROR;
 		send_sig(SIGFPE, current, 1);
 	}
 }
@@ -411,7 +410,7 @@
 void do_fpieee(struct pt_regs *regs)
 {
 #ifdef DEBUG_FPU
-	printk("fpieee %016lx\n", current->tss.xfsr[0]);
+	printk("fpieee %016lx\n", current->thread.xfsr[0]);
 #endif
 	do_fpe_common(regs);
 }
@@ -423,7 +422,7 @@
 	struct fpustate *f = FPUSTATE;
 	int ret = 0;
 
-	switch ((current->tss.xfsr[0] & 0x1c000)) {
+	switch ((current->thread.xfsr[0] & 0x1c000)) {
 	case (2 << 14): /* unfinished_FPop */
 	case (3 << 14): /* unimplemented_FPop */
 		ret = do_mathemu(regs, f);
@@ -431,7 +430,7 @@
 	}
 	if (ret) return;
 #ifdef DEBUG_FPU
-	printk("fpother %016lx\n", current->tss.xfsr[0]);
+	printk("fpother %016lx\n", current->thread.xfsr[0]);
 #endif
 	do_fpe_common(regs);
 }
@@ -440,8 +439,8 @@
 {
 	if(regs->tstate & TSTATE_PRIV)
 		die_if_kernel("Penguin overflow trap from kernel mode", regs);
-	current->tss.sig_address = regs->tpc;
-	current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
+	current->thread.sig_address = regs->tpc;
+	current->thread.sig_desc = SUBSIG_TAG; /* as good as any */
 	send_sig(SIGEMT, current, 1);
 }
 
@@ -540,7 +539,7 @@
 
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("Kernel illegal instruction", regs);
-	if(current->tss.flags & SPARC_FLAG_32BIT)
+	if(current->thread.flags & SPARC_FLAG_32BIT)
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
@@ -551,8 +550,8 @@
 				return;
 		}
 	}
-	current->tss.sig_address = pc;
-	current->tss.sig_desc = SUBSIG_ILLINST;
+	current->thread.sig_address = pc;
+	current->thread.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
 }
 
@@ -565,23 +564,23 @@
 
 		return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr);
 	} else {
-		current->tss.sig_address = regs->tpc;
-		current->tss.sig_desc = SUBSIG_PRIVINST;
+		current->thread.sig_address = regs->tpc;
+		current->thread.sig_desc = SUBSIG_PRIVINST;
 		send_sig(SIGBUS, current, 1);
 	}
 }
 
 void do_privop(struct pt_regs *regs)
 {
-	current->tss.sig_address = regs->tpc;
-	current->tss.sig_desc = SUBSIG_PRIVINST;
+	current->thread.sig_address = regs->tpc;
+	current->thread.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGILL, current, 1);
 }
 
 void do_privact(struct pt_regs *regs)
 {
-	current->tss.sig_address = regs->tpc;
-	current->tss.sig_desc = SUBSIG_PRIVINST;
+	current->thread.sig_address = regs->tpc;
+	current->thread.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGILL, current, 1);
 }
 
@@ -590,8 +589,8 @@
 {
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
-	current->tss.sig_address = pc;
-	current->tss.sig_desc = SUBSIG_PRIVINST;
+	current->thread.sig_address = pc;
+	current->thread.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGILL, current, 1);
 }
 
@@ -727,4 +726,11 @@
 
 void trap_init(void)
 {
+	/* Attach to the address space of init_task. */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+
+	/* NOTE: Other cpus have this done as they are started
+	 *       up on SMP.
+	 */
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c
--- v2.3.12/linux/arch/sparc64/kernel/unaligned.c	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/kernel/unaligned.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.16 1999/05/25 16:53:15 jj Exp $
+/* $Id: unaligned.c,v 1.18 1999/08/02 08:39:44 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -70,7 +70,7 @@
 		return 2;
 	else {
 		printk("Impossible unaligned trap. insn=%08x\n", insn);
-		die_if_kernel("Byte sized unaligned access?!?!", current->tss.kregs);
+		die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs);
 	}
 }
 
@@ -117,7 +117,7 @@
 		struct reg_window *win;
 		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 		value = win->locals[reg - 16];
-	} else if (current->tss.flags & SPARC_FLAG_32BIT) {
+	} else if (current->thread.flags & SPARC_FLAG_32BIT) {
 		struct reg_window32 *win32;
 		win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 		get_user(value, &win32->locals[reg - 16]);
@@ -137,7 +137,7 @@
 		struct reg_window *win;
 		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 		return &win->locals[reg - 16];
-	} else if (current->tss.flags & SPARC_FLAG_32BIT) {
+	} else if (current->thread.flags & SPARC_FLAG_32BIT) {
 		struct reg_window32 *win32;
 		win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 		return (unsigned long *)&win32->locals[reg - 16];
@@ -164,10 +164,10 @@
 	}
 }
 
-/* This is just to make gcc think panic does return... */
-static void unaligned_panic(char *str)
+/* This is just to make gcc think die_if_kernel does return... */
+static void unaligned_panic(char *str, struct pt_regs *regs)
 {
-	panic(str);
+	die_if_kernel(str, regs);
 }
 
 #define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({		\
@@ -380,7 +380,7 @@
 	if(!ok_for_kernel(insn) || dir == both) {
 		printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n",
 		       regs->tpc);
-		unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
+		unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs);
 
 		__asm__ __volatile__ ("\n"
 "kernel_unaligned_trap_fault:\n\t"
@@ -453,7 +453,7 @@
 		if (rd)
 			regs->u_regs[rd] = ret;
 	} else {
-		if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (current->thread.flags & SPARC_FLAG_32BIT) {
 			struct reg_window32 *win32;
 			win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 			put_user(ret, &win32->locals[rd - 16]);
@@ -480,9 +480,9 @@
 	int flag = (freg < 32) ? FPRS_DL : FPRS_DU;
 
 	save_and_clear_fpu();
-	current->tss.xfsr[0] &= ~0x1c000;
+	current->thread.xfsr[0] &= ~0x1c000;
 	if (freg & 3) {
-		current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+		current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 		do_fpother(regs);
 		return 0;
 	}
@@ -490,7 +490,7 @@
 		/* STQ */
 		u64 first = 0, second = 0;
 		
-		if (current->tss.fpsaved[0] & flag) {
+		if (current->thread.fpsaved[0] & flag) {
 			first = *(u64 *)&f->regs[freg];
 			second = *(u64 *)&f->regs[freg+2];
 		}
@@ -565,18 +565,18 @@
 				break;
 			}
 		}
-		if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
-			current->tss.fpsaved[0] = FPRS_FEF;
-			current->tss.gsr[0] = 0;
+		if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
+			current->thread.fpsaved[0] = FPRS_FEF;
+			current->thread.gsr[0] = 0;
 		}
-		if (!(current->tss.fpsaved[0] & flag)) {
+		if (!(current->thread.fpsaved[0] & flag)) {
 			if (freg < 32)
 				memset(f->regs, 0, 32*sizeof(u32));
 			else
 				memset(f->regs+32, 0, 32*sizeof(u32));
 		}
 		memcpy(f->regs + freg, data, size * 4);
-		current->tss.fpsaved[0] |= flag;
+		current->thread.fpsaved[0] |= flag;
 	}
 	advance(regs);
 	return 1;
@@ -609,7 +609,7 @@
 
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("lddfmna from kernel", regs);
-	if(current->tss.flags & SPARC_FLAG_32BIT)
+	if(current->thread.flags & SPARC_FLAG_32BIT)
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		asi = sfsr >> 16;
@@ -629,18 +629,18 @@
 		if (asi & 0x8) /* Little */
 			value = __swab64p(&value);
 		flag = (freg < 32) ? FPRS_DL : FPRS_DU;
-		if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
-			current->tss.fpsaved[0] = FPRS_FEF;
-			current->tss.gsr[0] = 0;
+		if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
+			current->thread.fpsaved[0] = FPRS_FEF;
+			current->thread.gsr[0] = 0;
 		}
-		if (!(current->tss.fpsaved[0] & flag)) {
+		if (!(current->thread.fpsaved[0] & flag)) {
 			if (freg < 32)
 				memset(f->regs, 0, 32*sizeof(u32));
 			else
 				memset(f->regs+32, 0, 32*sizeof(u32));
 		}
 		*(u64 *)(f->regs + freg) = value;
-		current->tss.fpsaved[0] |= flag;
+		current->thread.fpsaved[0] |= flag;
 	} else {
 daex:		data_access_exception(regs);
 		return;
@@ -661,7 +661,7 @@
 
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("stdfmna from kernel", regs);
-	if(current->tss.flags & SPARC_FLAG_32BIT)
+	if(current->thread.flags & SPARC_FLAG_32BIT)
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
@@ -672,7 +672,7 @@
 		    (asi < ASI_P))
 			goto daex;
 		save_and_clear_fpu();
-		if (current->tss.fpsaved[0] & flag)
+		if (current->thread.fpsaved[0] & flag)
 			value = *(u64 *)&f->regs[freg];
 		switch (asi) {
 		case ASI_P:
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S
--- v2.3.12/linux/arch/sparc64/kernel/winfixup.S	Sun Oct  4 10:22:43 1998
+++ linux/arch/sparc64/kernel/winfixup.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.27 1998/09/25 01:09:14 davem Exp $
+/* $Id: winfixup.S,v 1.28 1999/07/30 09:35:34 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -95,56 +95,56 @@
 	 * do not touch %g7 or %g2 so we handle the two cases fine.
 	 */
 spill_fixup:
-	lduh		[%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
 	andcc		%g1, SPARC_FLAG_32BIT, %g0
-	lduh		[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
 
 	sll		%g1, 3, %g3
 	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+	stx		%sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
 	sll		%g1, 7, %g3
 	bne,pt		%xcc, 1f
 	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	stx		%l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	stx		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+	stx		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
 
-	stx		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-	stx		%l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	stx		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-	stx		%l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	stx		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	stx		%l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-	stx		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
-	stx		%i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
-
-	stx		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
-	stx		%i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
-	stx		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
-	stx		%i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
-	stx		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+	stx		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+	stx		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+	stx		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+	stx		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+	stx		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+	stx		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+	stx		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
+	stx		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+
+	stx		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
+	stx		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
+	stx		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+	stx		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
+	stx		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
 	b,pt		%xcc, 2f
-	 stx		%i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
-1:	stw		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	 stx		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
+1:	stw		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
 
-	stw		%l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04]
-	stw		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	stw		%l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c]
-	stw		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-	stw		%l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14]
-	stw		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	stw		%l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c]
-	stw		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-
-	stw		%i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24]
-	stw		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	stw		%i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c]
-	stw		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	stw		%i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34]
-	stw		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-	stw		%i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c]
+	stw		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x04]
+	stw		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+	stw		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x0c]
+	stw		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+	stw		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x14]
+	stw		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+	stw		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x1c]
+	stw		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+
+	stw		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x24]
+	stw		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+	stw		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x2c]
+	stw		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+	stw		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x34]
+	stw		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+	stw		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x3c]
 2:	add		%g1, 1, %g1
 
-	sth		%g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+	stb		%g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
 	rdpr		%tstate, %g1
 	andcc		%g1, TSTATE_PRIV, %g0
 	saved
@@ -208,47 +208,47 @@
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
 spill_fixup_mna:
-	lduh		[%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
 	andcc		%g1, SPARC_FLAG_32BIT, %g0
-	lduh		[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
 	sll		%g1, 3, %g3
 	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+	stx		%sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
 
 	sll		%g1, 7, %g3
 	bne,pt		%xcc, 1f
 	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	stx		%l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	stx		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-	stx		%l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	stx		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-
-	stx		%l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	stx		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	stx		%l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-	stx		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
-	stx		%i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
-	stx		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
-	stx		%i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
-	stx		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
-
-	stx		%i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
-	stx		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
-	stx		%i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+	stx		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+	stx		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+	stx		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+	stx		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+	stx		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+
+	stx		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+	stx		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+	stx		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+	stx		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
+	stx		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+	stx		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
+	stx		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
+	stx		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+
+	stx		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
+	stx		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
+	stx		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
 	b,pt		%xcc, 2f
 	 add		%g1, 1, %g1
-1:	std		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	std		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	std		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-
-	std		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	std		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-	std		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	std		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	std		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+1:	std		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+	std		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+	std		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+
+	std		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+	std		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+	std		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+	std		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+	std		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
 	add		%g1, 1, %g1
-2:	sth		%g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+2:	stb		%g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
 	rdpr		%tstate, %g1
 
 	andcc		%g1, TSTATE_PRIV, %g0
@@ -315,47 +315,47 @@
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
 spill_fixup_dax:
-	lduh		[%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
 	andcc		%g1, SPARC_FLAG_32BIT, %g0
-	lduh		[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
 	sll		%g1, 3, %g3
 	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+	stx		%sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
 
 	sll		%g1, 7, %g3
 	bne,pt		%xcc, 1f
 	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	stx		%l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	stx		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-	stx		%l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	stx		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-
-	stx		%l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	stx		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	stx		%l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-	stx		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
-	stx		%i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
-	stx		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
-	stx		%i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
-	stx		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
-
-	stx		%i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
-	stx		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
-	stx		%i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+	stx		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+	stx		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+	stx		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+	stx		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+	stx		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+
+	stx		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+	stx		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+	stx		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+	stx		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
+	stx		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+	stx		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
+	stx		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
+	stx		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+
+	stx		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
+	stx		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
+	stx		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
 	b,pt		%xcc, 2f
 	 add		%g1, 1, %g1
-1:	std		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	std		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	std		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-
-	std		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	std		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-	std		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	std		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	std		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+1:	std		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+	std		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+	std		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+
+	std		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+	std		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+	std		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+	std		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+	std		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
 	add		%g1, 1, %g1
-2:	sth		%g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+2:	stb		%g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
 	rdpr		%tstate, %g1
 
 	andcc		%g1, TSTATE_PRIV, %g0
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S
--- v2.3.12/linux/arch/sparc64/lib/VIScopy.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/lib/VIScopy.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.20 1999/05/25 16:52:57 jj Exp $
+/* $Id: VIScopy.S,v 1.21 1999/07/30 09:35:35 davem Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -29,19 +29,19 @@
 #include <asm/asm_offsets.h>
 
 #define FPU_CLEAN_RETL								\
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o1;	\
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1;	\
 	VISExit									\
 	clr		%o0;							\
 	retl;									\
 	 wr		%o1, %g0, %asi;
 #define FPU_RETL								\
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o1;	\
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1;	\
 	VISExit									\
 	clr		%o0;							\
 	retl;									\
 	 wr		%o1, %g0, %asi;
 #define NORMAL_RETL								\
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o1;	\
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1;	\
 	clr		%o0;							\
 	retl;									\
 	 wr		%o1, %g0, %asi;
@@ -1009,7 +1009,7 @@
 		/* If this is copy_from_user(), zero out the rest of the
 		 * kernel buffer.
 		 */
-		ldub		[%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o4
+		ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o4
 		andcc		asi_src, 0x1, %g0
 		be,pt		%icc, 1f
 		 VISExit
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/lib/VIScsum.S linux/arch/sparc64/lib/VIScsum.S
--- v2.3.12/linux/arch/sparc64/lib/VIScsum.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/lib/VIScsum.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: VIScsum.S,v 1.4 1999/05/25 16:53:00 jj Exp $
+/* $Id: VIScsum.S,v 1.5 1999/07/30 09:35:36 davem Exp $
  * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -341,7 +341,7 @@
 	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
 	END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
 #ifdef __KERNEL__
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_current_ds], %g7
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g7
 #endif
 	and		%o1, 0x3f, %o1		/*  IEU0	Group			*/
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/lib/VISsave.S linux/arch/sparc64/lib/VISsave.S
--- v2.3.12/linux/arch/sparc64/lib/VISsave.S	Tue Oct 27 09:52:20 1998
+++ linux/arch/sparc64/lib/VISsave.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $
+/* $Id: VISsave.S,v 1.4 1999/07/30 09:35:37 davem Exp $
  * VISsave.S: Code for saving FPU register state for
  *            VIS routines. One should not call this directly,
  *            but use macros provided in <asm/visasm.h>.
@@ -19,35 +19,35 @@
 
 	.align		32
 VISenter:
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1
 	brnz,a,pn	%g1, 1f
 	 cmp		%g1, 1
-	stb		%g0, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
-	stx		%fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+	stb		%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
+	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
 9:	jmpl		%g7 + %g0, %g0
 	 nop
 1:	bne,pn		%icc, 2f
 
 	 srl		%g1, 1, %g1
-vis1:	ldub		[%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
-	stx		%fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+vis1:	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
+	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
 	or		%g3, %o5, %g3
-	stb		%g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+	stb		%g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
 	rd		%gsr, %g3
 	clr		%g1
 	ba,pt		%xcc, 3f
 
-	 stb		%g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr]
+	 stb		%g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
 2:	add		%g6, %g1, %g3
 	cmp		%o5, FPRS_DU
 	be,pn		%icc, 6f
 	 sll		%g1, 3, %g1
-	stb		%o5, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved]
+	stb		%o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved]
 	rd		%gsr, %g2
-	stb		%g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr]
+	stb		%g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr]
 
 	add		%g6, %g1, %g2
-	stx		%fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr]
+	stx		%fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr]
 	sll		%g1, 5, %g1
 3:	andcc		%o5, FPRS_DL|FPRS_DU, %g0
 	be,pn		%icc, 9b
@@ -69,10 +69,10 @@
 	jmpl		%g7 + %g0, %g0
 	 nop
 
-6:	ldub		[%g3 + AOFF_task_tss + AOFF_thread_fpsaved], %o5
+6:	ldub		[%g3 + AOFF_task_thread + AOFF_thread_fpsaved], %o5
 	or		%o5, FPRS_DU, %o5
 	add		%g6, AOFF_task_fpregs+0x80, %g2
-	stb		%o5, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved]
+	stb		%o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved]
 
 	sll		%g1, 5, %g1
 	add		%g6, AOFF_task_fpregs+0xc0, %g3
@@ -87,11 +87,11 @@
 
 	.align		32
 VISenterhalf:
-	ldub		[%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %g1
+	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1
 	brnz,a,pn	%g1, 1f
 	 cmp		%g1, 1
-	stb		%g0, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
-	stx		%fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+	stb		%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
+	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
 	clr		%o5
 	jmpl		%g7 + %g0, %g0
 	 wr		%g0, FPRS_FEF, %fprs
@@ -103,12 +103,12 @@
 2:	addcc		%g6, %g1, %g3
 	sll		%g1, 3, %g1
 	andn		%o5, FPRS_DU, %g2
-	stb		%g2, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved]
+	stb		%g2, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved]
 
 	rd		%gsr, %g2
-	stb		%g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr]
+	stb		%g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr]
 	add		%g6, %g1, %g2
-	stx		%fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr]
+	stx		%fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr]
 	sll		%g1, 5, %g1
 3:	andcc		%o5, FPRS_DL, %g0
 	be,pn		%icc, 4f
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.3.12/linux/arch/sparc64/lib/blockops.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/lib/blockops.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.17 1999/05/25 16:52:52 jj Exp $
+/* $Id: blockops.S,v 1.18 1999/07/30 09:35:37 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -29,7 +29,7 @@
 	.type		copy_page,@function
 copy_page: /* %o0=dest, %o1=src */
 	VISEntry
-	ldx		[%g6 + AOFF_task_mm], %o2
+	ldx		[%g6 + AOFF_task_active_mm], %o2
 	sub		%o0, %g4, %g1
 	sethi		%uhi(_PAGE_VALID), %g3
 	sub		%o1, %g4, %g2
@@ -107,7 +107,7 @@
 	.type		clear_page,@function
 clear_page:		/* %o0=dest */
 	VISEntryHalf
-	ldx		[%g6 + AOFF_task_mm], %o2
+	ldx		[%g6 + AOFF_task_active_mm], %o2
 	sub		%o0, %g4, %g1
 	sethi		%uhi(_PAGE_VALID), %g3
 	sllx		%g3, 32, %g3
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S
--- v2.3.12/linux/arch/sparc64/lib/checksum.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/lib/checksum.S	Mon Aug  2 22:07:16 1999
@@ -266,7 +266,7 @@
 	.globl	cpc_handler
 cpc_handler:
 	ldx	[%sp + 0x7ff + 128], %g1
-	ldub	[%g6 + AOFF_task_tss + AOFF_thread_current_ds], %g3
+	ldub	[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g3
 	sub	%g0, EFAULT, %g2
 	brnz,a,pt %g1, 1f
 	 st	%g2, [%g1]
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/fcmpeq.c linux/arch/sparc64/math-emu/fcmpeq.c
--- v2.3.12/linux/arch/sparc64/math-emu/fcmpeq.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/fcmpeq.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fcmpeq.c,v 1.5 1999/05/28 13:43:29 jj Exp $
+/* $Id: fcmpeq.c,v 1.6 1999/07/30 09:35:40 davem Exp $
  * arch/sparc64/math-emu/fcmpeq.c
  *
  * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -26,14 +26,14 @@
 	if (!FP_INHIBIT_RESULTS) {
 		rd = (void *)(((long)rd)&~3);
 		if (ret == -1) ret = 2;
-		fsr = current->tss.xfsr[0];
+		fsr = current->thread.xfsr[0];
 		switch (fccno) {
 		case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
 		case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
 		case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
 		case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
 		}
-		current->tss.xfsr[0] = fsr;
+		current->thread.xfsr[0] = fsr;
 	}
 	FP_HANDLE_EXCEPTIONS;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/fcmpq.c linux/arch/sparc64/math-emu/fcmpq.c
--- v2.3.12/linux/arch/sparc64/math-emu/fcmpq.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/fcmpq.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fcmpq.c,v 1.5 1999/05/28 13:43:33 jj Exp $
+/* $Id: fcmpq.c,v 1.6 1999/07/30 09:35:40 davem Exp $
  * arch/sparc64/math-emu/fcmpq.c
  *
  * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -26,14 +26,14 @@
 	if (!FP_INHIBIT_RESULTS) {
 		rd = (void *)(((long)rd)&~3);
 		if (ret == -1) ret = 2;
-		fsr = current->tss.xfsr[0];
+		fsr = current->thread.xfsr[0];
 		switch (fccno) {
 		case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
 		case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
 		case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
 		case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
 		}
-		current->tss.xfsr[0] = fsr;
+		current->thread.xfsr[0] = fsr;
 	}
 	FP_HANDLE_EXCEPTIONS;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/fsubd.c linux/arch/sparc64/math-emu/fsubd.c
--- v2.3.12/linux/arch/sparc64/math-emu/fsubd.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/fsubd.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fsubd.c,v 1.4 1999/05/28 13:45:04 jj Exp $
+/* $Id: fsubd.c,v 1.5 1999/08/02 14:08:04 jj Exp $
  * arch/sparc64/math-emu/fsubd.c
  *
  * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -17,9 +17,7 @@
 
 	FP_UNPACK_DP(A, rs1);
 	FP_UNPACK_DP(B, rs2);
-	if (B_c != FP_CLS_NAN)
-		B_s ^= 1;
-	FP_ADD_D(R, A, B);
+	FP_SUB_D(R, A, B);
 	FP_PACK_DP(rd, R);
 	FP_HANDLE_EXCEPTIONS;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/fsubq.c linux/arch/sparc64/math-emu/fsubq.c
--- v2.3.12/linux/arch/sparc64/math-emu/fsubq.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/fsubq.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fsubq.c,v 1.4 1999/05/28 13:45:09 jj Exp $
+/* $Id: fsubq.c,v 1.5 1999/08/02 14:08:06 jj Exp $
  * arch/sparc64/math-emu/fsubq.c
  *
  * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -17,9 +17,7 @@
 
 	FP_UNPACK_QP(A, rs1);
 	FP_UNPACK_QP(B, rs2);
-	if (B_c != FP_CLS_NAN)
-		B_s ^= 1;
-	FP_ADD_Q(R, A, B);
+	FP_SUB_Q(R, A, B);
 	FP_PACK_QP(rd, R);
 	FP_HANDLE_EXCEPTIONS;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/fsubs.c linux/arch/sparc64/math-emu/fsubs.c
--- v2.3.12/linux/arch/sparc64/math-emu/fsubs.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/fsubs.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fsubs.c,v 1.4 1999/05/28 13:45:12 jj Exp $
+/* $Id: fsubs.c,v 1.5 1999/08/02 14:08:07 jj Exp $
  * arch/sparc64/math-emu/fsubs.c
  *
  * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -17,9 +17,7 @@
 
 	FP_UNPACK_SP(A, rs1);
 	FP_UNPACK_SP(B, rs2);
-	if (B_c != FP_CLS_NAN)
-		B_s ^= 1;
-	FP_ADD_S(R, A, B);
+	FP_SUB_S(R, A, B);
 	FP_PACK_SP(rd, R);
 	FP_HANDLE_EXCEPTIONS;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/math.c linux/arch/sparc64/math-emu/math.c
--- v2.3.12/linux/arch/sparc64/math-emu/math.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/math.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: math.c,v 1.8 1999/05/28 13:43:11 jj Exp $
+/* $Id: math.c,v 1.9 1999/07/30 09:35:41 davem Exp $
  * arch/sparc64/math-emu/math.c
  *
  * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -75,7 +75,7 @@
  */
 static int record_exception(struct pt_regs *regs, int eflag)
 {
-	u64 fsr = current->tss.xfsr[0];
+	u64 fsr = current->thread.xfsr[0];
 	int would_trap;
 
 	/* Determine if this exception would have generated a trap. */
@@ -120,7 +120,7 @@
 	if(would_trap != 0)
 		fsr |= (1UL << 14);
 
-	current->tss.xfsr[0] = fsr;
+	current->thread.xfsr[0] = fsr;
 
 	/* If we will not trap, advance the program counter over
 	 * the instruction being handled.
@@ -148,7 +148,7 @@
 
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("FPQuad from kernel", regs);
-	if(current->tss.flags & SPARC_FLAG_32BIT)
+	if(current->thread.flags & SPARC_FLAG_32BIT)
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
@@ -201,33 +201,33 @@
 	if (type) {
 		void *rs1 = NULL, *rs2 = NULL, *rd = NULL;
 		
-		freg = (current->tss.xfsr[0] >> 14) & 0xf;
+		freg = (current->thread.xfsr[0] >> 14) & 0xf;
 		if (freg != (type >> 8))
 			goto err;
-		current->tss.xfsr[0] &= ~0x1c000;
+		current->thread.xfsr[0] &= ~0x1c000;
 		freg = ((insn >> 14) & 0x1f);
 		switch (type & 0x3) {
 		case 3: if (freg & 2) {
-				current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+				current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
 		case 1: rs1 = (void *)&f->regs[freg]; 
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
-			if (!(current->tss.fpsaved[0] & flags))
+			if (!(current->thread.fpsaved[0] & flags))
 				rs1 = (void *)&zero;
 			break;
 		}
 		freg = (insn & 0x1f);
 		switch ((type >> 2) & 0x3) {
 		case 3: if (freg & 2) {
-				current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+				current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
 		case 1: rs2 = (void *)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
-			if (!(current->tss.fpsaved[0] & flags))
+			if (!(current->thread.fpsaved[0] & flags))
 				rs2 = (void *)&zero;
 			break;
 		}
@@ -235,23 +235,23 @@
 		switch ((type >> 4) & 0x3) {
 		case 0: rd = (void *)(long)(freg & 3); break;
 		case 3: if (freg & 2) {
-				current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+				current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
 		case 1: rd = (void *)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
-			if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
-				current->tss.fpsaved[0] = FPRS_FEF;
-				current->tss.gsr[0] = 0;
+			if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
+				current->thread.fpsaved[0] = FPRS_FEF;
+				current->thread.gsr[0] = 0;
 			}
-			if (!(current->tss.fpsaved[0] & flags)) {
+			if (!(current->thread.fpsaved[0] & flags)) {
 				if (freg < 32)
 					memset(f->regs, 0, 32*sizeof(u32));
 				else
 					memset(f->regs+32, 0, 32*sizeof(u32));
 			}
-			current->tss.fpsaved[0] |= flags;
+			current->thread.fpsaved[0] |= flags;
 			break;
 		}
 		flags = func(rd, rs2, rs1);
@@ -259,7 +259,7 @@
 			return record_exception(regs, flags);
 
 		/* Success and no exceptions detected. */
-		current->tss.xfsr[0] &= ~(FSR_CEXC_MASK);
+		current->thread.xfsr[0] &= ~(FSR_CEXC_MASK);
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 		return 1;
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/op-1.h linux/arch/sparc64/math-emu/op-1.h
--- v2.3.12/linux/arch/sparc64/math-emu/op-1.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/op-1.h	Mon Aug  2 22:07:16 1999
@@ -120,31 +120,31 @@
 /* Basic.  Assuming the host word size is >= 2*FRACBITS, we can do the
    multiplication immediately.  */
 
-#define _FP_MUL_MEAT_1_imm(fs, R, X, Y)					\
+#define _FP_MUL_MEAT_1_imm(wfracbits, R, X, Y)				\
   do {									\
     R##_f = X##_f * Y##_f;						\
     /* Normalize since we know where the msb of the multiplicands	\
        were (bit B), we know that the msb of the of the product is	\
        at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
+    _FP_FRAC_SRS_1(R, wfracbits-1, 2*wfracbits);			\
   } while (0)
 
 /* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
 
-#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit)				\
+#define _FP_MUL_MEAT_1_wide(wfracbits, R, X, Y, doit)			\
   do {									\
     _FP_W_TYPE _Z_f0, _Z_f1;						\
     doit(_Z_f1, _Z_f0, X##_f, Y##_f);					\
     /* Normalize since we know where the msb of the multiplicands	\
        were (bit B), we know that the msb of the of the product is	\
        at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
+    _FP_FRAC_SRS_2(_Z, wfracbits-1, 2*wfracbits);			\
     R##_f = _Z_f0;							\
   } while (0)
 
 /* Finally, a simple widening multiply algorithm.  What fun!  */
 
-#define _FP_MUL_MEAT_1_hard(fs, R, X, Y)				\
+#define _FP_MUL_MEAT_1_hard(wfracbits, R, X, Y)				\
   do {									\
     _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1;		\
 									\
@@ -168,7 +168,7 @@
     _FP_FRAC_ADD_2(_z, _z, _a);						\
 									\
     /* normalize */							\
-    _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs);	\
+    _FP_FRAC_SRS_2(_z, wfracbits - 1, 2*wfracbits);			\
     R##_f = _z_f0;							\
   } while (0)
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/op-2.h linux/arch/sparc64/math-emu/op-2.h
--- v2.3.12/linux/arch/sparc64/math-emu/op-2.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/op-2.h	Mon Aug  2 22:07:16 1999
@@ -234,7 +234,7 @@
 
 /* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
 
-#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit)				\
+#define _FP_MUL_MEAT_2_wide(wfracbits, R, X, Y, doit)			\
   do {									\
     _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	\
 									\
@@ -255,7 +255,7 @@
     /* Normalize since we know where the msb of the multiplicands	\
        were (bit B), we know that the msb of the of the product is	\
        at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
+    _FP_FRAC_SRS_4(_z, wfracbits-1, 2*wfracbits);			\
     R##_f0 = _FP_FRAC_WORD_4(_z,0);					\
     R##_f1 = _FP_FRAC_WORD_4(_z,1);					\
   } while (0)
@@ -264,7 +264,7 @@
    Do only 3 multiplications instead of four. This one is for machines
    where multiplication is much more expensive than subtraction.  */
 
-#define _FP_MUL_MEAT_2_wide_3mul(fs, R, X, Y, doit)			\
+#define _FP_MUL_MEAT_2_wide_3mul(wfracbits, R, X, Y, doit)		\
   do {									\
     _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	\
     _FP_W_TYPE _d;							\
@@ -299,12 +299,12 @@
     /* Normalize since we know where the msb of the multiplicands	\
        were (bit B), we know that the msb of the of the product is	\
        at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	\
+    _FP_FRAC_SRS_4(_z, wfracbits-1, 2*wfracbits);			\
     R##_f0 = _FP_FRAC_WORD_4(_z,0);					\
     R##_f1 = _FP_FRAC_WORD_4(_z,1);					\
   } while (0)
 
-#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y)					\
+#define _FP_MUL_MEAT_2_gmp(wfracbits, R, X, Y)				\
   do {									\
     _FP_FRAC_DECL_4(_z);						\
     _FP_W_TYPE _x[2], _y[2];						\
@@ -316,11 +316,106 @@
     /* Normalize since we know where the msb of the multiplicands	\
        were (bit B), we know that the msb of the of the product is	\
        at either 2B or 2B-1.  */					\
-    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs);	\
+    _FP_FRAC_SRS_4(_z, wfracbits-1, 2*wfracbits);			\
     R##_f0 = _z_f[0];							\
     R##_f1 = _z_f[1];							\
   } while (0)
 
+/* Do at most 120x120=240 bits multiplication using double floating
+   point multiplication.  This is useful if floating point
+   multiplication has much bigger throughput than integer multiply.
+   It is supposed to work for _FP_W_TYPE_SIZE 64 and wfracbits
+   between 106 and 120 only.  
+   Caller guarantees that X and Y has (1LLL << (wfracbits - 1)) set.
+   SETFETZ is a macro which will disable all FPU exceptions and set rounding
+   towards zero,  RESETFE should optionally reset it back.  */
+
+#define _FP_MUL_MEAT_2_120_240_double(wfracbits, R, X, Y, setfetz, resetfe)	\
+  do {										\
+    static const double _const[] = {						\
+      /* 2^-24 */ 5.9604644775390625e-08,					\
+      /* 2^-48 */ 3.5527136788005009e-15,					\
+      /* 2^-72 */ 2.1175823681357508e-22,					\
+      /* 2^-96 */ 1.2621774483536189e-29,					\
+      /* 2^28 */ 2.68435456e+08,						\
+      /* 2^4 */ 1.600000e+01,							\
+      /* 2^-20 */ 9.5367431640625e-07,						\
+      /* 2^-44 */ 5.6843418860808015e-14,					\
+      /* 2^-68 */ 3.3881317890172014e-21,					\
+      /* 2^-92 */ 2.0194839173657902e-28,					\
+      /* 2^-116 */ 1.2037062152420224e-35};					\
+    double _a240, _b240, _c240, _d240, _e240, _f240, 				\
+	   _g240, _h240, _i240, _j240, _k240;					\
+    union { double d; UDItype i; } _l240, _m240, _n240, _o240,			\
+				   _p240, _q240, _r240, _s240;			\
+    UDItype _t240, _u240, _v240, _w240, _x240, _y240 = 0;			\
+										\
+    if (wfracbits < 106 || wfracbits > 120)					\
+      abort();									\
+										\
+    setfetz;									\
+										\
+    _e240 = (double)(long)(X##_f0 & 0xffffff);					\
+    _j240 = (double)(long)(Y##_f0 & 0xffffff);					\
+    _d240 = (double)(long)((X##_f0 >> 24) & 0xffffff);				\
+    _i240 = (double)(long)((Y##_f0 >> 24) & 0xffffff);				\
+    _c240 = (double)(long)(((X##_f1 << 16) & 0xffffff) | (X##_f0 >> 48));	\
+    _h240 = (double)(long)(((Y##_f1 << 16) & 0xffffff) | (Y##_f0 >> 48));	\
+    _b240 = (double)(long)((X##_f1 >> 8) & 0xffffff);				\
+    _g240 = (double)(long)((Y##_f1 >> 8) & 0xffffff);				\
+    _a240 = (double)(long)(X##_f1 >> 32);					\
+    _f240 = (double)(long)(Y##_f1 >> 32);					\
+    _e240 *= _const[3];								\
+    _j240 *= _const[3];								\
+    _d240 *= _const[2];								\
+    _i240 *= _const[2];								\
+    _c240 *= _const[1];								\
+    _h240 *= _const[1];								\
+    _b240 *= _const[0];								\
+    _g240 *= _const[0];								\
+    _s240.d =							      _e240*_j240;\
+    _r240.d =						_d240*_j240 + _e240*_i240;\
+    _q240.d =				  _c240*_j240 + _d240*_i240 + _e240*_h240;\
+    _p240.d =		    _b240*_j240 + _c240*_i240 + _d240*_h240 + _e240*_g240;\
+    _o240.d = _a240*_j240 + _b240*_i240 + _c240*_h240 + _d240*_g240 + _e240*_f240;\
+    _n240.d = _a240*_i240 + _b240*_h240 + _c240*_g240 + _d240*_f240;		\
+    _m240.d = _a240*_h240 + _b240*_g240 + _c240*_f240;				\
+    _l240.d = _a240*_g240 + _b240*_f240;					\
+    _k240 =   _a240*_f240;							\
+    _r240.d += _s240.d;								\
+    _q240.d += _r240.d;								\
+    _p240.d += _q240.d;								\
+    _o240.d += _p240.d;								\
+    _n240.d += _o240.d;								\
+    _m240.d += _n240.d;								\
+    _l240.d += _m240.d;								\
+    _k240 += _l240.d;								\
+    _s240.d -= ((_const[10]+_s240.d)-_const[10]);				\
+    _r240.d -= ((_const[9]+_r240.d)-_const[9]);					\
+    _q240.d -= ((_const[8]+_q240.d)-_const[8]);					\
+    _p240.d -= ((_const[7]+_p240.d)-_const[7]);					\
+    _o240.d += _const[7];							\
+    _n240.d += _const[6];							\
+    _m240.d += _const[5];							\
+    _l240.d += _const[4];							\
+    if (_s240.d != 0.0) _y240 = 1;						\
+    if (_r240.d != 0.0) _y240 = 1;						\
+    if (_q240.d != 0.0) _y240 = 1;						\
+    if (_p240.d != 0.0) _y240 = 1;						\
+    _t240 = (DItype)_k240;							\
+    _u240 = _l240.i;								\
+    _v240 = _m240.i;								\
+    _w240 = _n240.i;								\
+    _x240 = _o240.i;								\
+    R##_f1 = (_t240 << (128 - (wfracbits - 1)))					\
+	     | ((_u240 & 0xffffff) >> ((wfracbits - 1) - 104));			\
+    R##_f0 = ((_u240 & 0xffffff) << (168 - (wfracbits - 1)))			\
+    	     | ((_v240 & 0xffffff) << (144 - (wfracbits - 1)))			\
+    	     | ((_w240 & 0xffffff) << (120 - (wfracbits - 1)))			\
+    	     | ((_x240 & 0xffffff) >> ((wfracbits - 1) - 96))			\
+    	     | _y240;								\
+    resetfe;									\
+  } while (0)
 
 /*
  * Division algorithms:
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/op-4.h linux/arch/sparc64/math-emu/op-4.h
--- v2.3.12/linux/arch/sparc64/math-emu/op-4.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/op-4.h	Mon Aug  2 22:07:16 1999
@@ -232,7 +232,7 @@
 
 /* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
 
-#define _FP_MUL_MEAT_4_wide(fs, R, X, Y, doit)				    \
+#define _FP_MUL_MEAT_4_wide(wfracbits, R, X, Y, doit)			    \
   do {									    \
     _FP_FRAC_DECL_8(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	    \
     _FP_FRAC_DECL_2(_d); _FP_FRAC_DECL_2(_e); _FP_FRAC_DECL_2(_f);	    \
@@ -311,12 +311,12 @@
     /* Normalize since we know where the msb of the multiplicands	    \
        were (bit B), we know that the msb of the of the product is	    \
        at either 2B or 2B-1.  */					    \
-    _FP_FRAC_SRS_8(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	    \
+    _FP_FRAC_SRS_8(_z, wfracbits-1, 2*wfracbits);			    \
     __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),	    \
 		    _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));	    \
   } while (0)
 
-#define _FP_MUL_MEAT_4_gmp(fs, R, X, Y)					    \
+#define _FP_MUL_MEAT_4_gmp(wfracbits, R, X, Y)				    \
   do {									    \
     _FP_FRAC_DECL_8(_z);						    \
 									    \
@@ -325,7 +325,7 @@
     /* Normalize since we know where the msb of the multiplicands	    \
        were (bit B), we know that the msb of the of the product is	    \
        at either 2B or 2B-1.  */					    \
-    _FP_FRAC_SRS_8(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);	    \
+    _FP_FRAC_SRS_8(_z, wfracbits-1, 2*wfracbits);	 		    \
     __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),	    \
 		    _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));	    \
   } while (0)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/op-common.h linux/arch/sparc64/math-emu/op-common.h
--- v2.3.12/linux/arch/sparc64/math-emu/op-common.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/op-common.h	Mon Aug  2 22:07:16 1999
@@ -207,7 +207,7 @@
  * Main addition routine.  The input values should be cooked.
  */
 
-#define _FP_ADD(fs, wc, R, X, Y)					     \
+#define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP)				     \
 do {									     \
   switch (_FP_CLS_COMBINE(X##_c, Y##_c))				     \
   {									     \
@@ -284,7 +284,7 @@
     }									     \
 									     \
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):				     \
-    _FP_CHOOSENAN(fs, wc, R, X, Y);					     \
+    _FP_CHOOSENAN(fs, wc, R, X, Y, OP);					     \
     break;								     \
 									     \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):			     \
@@ -345,6 +345,13 @@
   }									     \
 } while (0)
 
+#define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+')
+#define _FP_SUB(fs, wc, R, X, Y)					     \
+  do {									     \
+    if (Y##_c != FP_CLS_NAN) Y##_s ^= 1;				     \
+    _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-');				     \
+  } while (0)
+
 
 /*
  * Main negation routine.  FIXME -- when we care about setting exception
@@ -382,7 +389,7 @@
     break;						\
 							\
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
-    _FP_CHOOSENAN(fs, wc, R, X, Y);			\
+    _FP_CHOOSENAN(fs, wc, R, X, Y, '*');		\
     break;						\
 							\
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
@@ -440,7 +447,7 @@
     break;						\
 							\
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):		\
-    _FP_CHOOSENAN(fs, wc, R, X, Y);			\
+    _FP_CHOOSENAN(fs, wc, R, X, Y, '/');		\
     break;						\
 							\
   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):	\
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/quad.h linux/arch/sparc64/math-emu/quad.h
--- v2.3.12/linux/arch/sparc64/math-emu/quad.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/quad.h	Mon Aug  2 22:07:16 1999
@@ -108,13 +108,9 @@
       _FP_PACK_RAW_4_P(Q,val,X);	\
   } while (0)
 
-#define FP_ISSIGNAN_Q(X)	_FP_ISSIGNAN(Q,4,X)
-#define FP_NEG_Q(R,X)		_FP_NEG(Q,4,R,X)
-#define FP_ADD_Q(R,X,Y)		_FP_ADD(Q,4,R,X,Y)
-/* single.h and double.h define FP_SUB_t this way too. However, _FP_SUB is
- * never defined in op-common.h! Fortunately nobody seems to use the FP_SUB_t 
- * macros: I suggest a combination of FP_NEG and FP_ADD :-> -- PMM 02/1998
- */
+#define FP_ISSIGNAN_Q(X)		_FP_ISSIGNAN(Q,4,X)
+#define FP_NEG_Q(R,X)			_FP_NEG(Q,4,R,X)
+#define FP_ADD_Q(R,X,Y)			_FP_ADD(Q,4,R,X,Y)
 #define FP_SUB_Q(R,X,Y)			_FP_SUB(Q,4,R,X,Y)
 #define FP_MUL_Q(R,X,Y)			_FP_MUL(Q,4,R,X,Y)
 #define FP_DIV_Q(R,X,Y)			_FP_DIV(Q,4,R,X,Y)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/math-emu/sfp-machine.h linux/arch/sparc64/math-emu/sfp-machine.h
--- v2.3.12/linux/arch/sparc64/math-emu/sfp-machine.h	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/math-emu/sfp-machine.h	Mon Aug  2 22:07:16 1999
@@ -29,9 +29,12 @@
 #define _FP_WS_TYPE		signed long
 #define _FP_I_TYPE		long
 
-#define _FP_MUL_MEAT_S(R,X,Y)	_FP_MUL_MEAT_1_imm(S,R,X,Y)
-#define _FP_MUL_MEAT_D(R,X,Y)	_FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y)	_FP_MUL_MEAT_2_wide_3mul(Q,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_S(R,X,Y)					\
+  _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
+#define _FP_MUL_MEAT_D(R,X,Y)					\
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)					\
+  _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
 
 #define _FP_DIV_MEAT_S(R,X,Y)	_FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv(D,R,X,Y)
@@ -53,7 +56,7 @@
  * CPU instruction emulation this should prefer Y.
  * (see SPAMv9 B.2.2 section).
  */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y)				\
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)			\
   do {								\
     if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)		\
 	&& !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))	\
@@ -71,7 +74,7 @@
 
 /* Obtain the current rounding mode. */
 #ifndef FP_ROUNDMODE
-#define FP_ROUNDMODE	((current->tss.xfsr[0] >> 30) & 0x3)
+#define FP_ROUNDMODE	((current->thread.xfsr[0] >> 30) & 0x3)
 #endif
 
 /* Exception flags. */
@@ -83,6 +86,6 @@
 
 #define FP_HANDLE_EXCEPTIONS return _fex
 
-#define FP_INHIBIT_RESULTS ((current->tss.xfsr[0] >> 23) & _fex)
+#define FP_INHIBIT_RESULTS ((current->thread.xfsr[0] >> 23) & _fex)
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c
--- v2.3.12/linux/arch/sparc64/mm/asyncd.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/mm/asyncd.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.8 1999/07/04 04:35:55 davem Exp $
+/*  $Id: asyncd.c,v 1.9 1999/07/30 09:35:43 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -91,7 +91,8 @@
 void async_fault(unsigned long address, int write, int taskid,
 		 void (*callback)(int,unsigned long,int,int))
 {
-	struct task_struct *tsk = task[taskid];
+#warning Need some fixing here... -DaveM
+	struct task_struct *tsk = current /* XXX task[taskid] */;
 	struct mm_struct *mm = tsk->mm;
 
 	stats.faults++;
@@ -111,7 +112,8 @@
 {
 	static unsigned last_address;
 	static int last_task, loop_counter;
-	struct task_struct *tsk = task[taskid];
+#warning Need some fixing here... -DaveM
+	struct task_struct *tsk = current /* XXX task[taskid] */;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte;
@@ -178,8 +180,8 @@
 	
 bad_area:	  
 	stats.failure++;
-	tsk->tss.sig_address = address;
-	tsk->tss.sig_desc = SUBSIG_NOMAPPING;
+	tsk->thread.sig_address = address;
+	tsk->thread.sig_desc = SUBSIG_NOMAPPING;
 	send_sig(SIGSEGV, tsk, 1);
 	return 1;
 }
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.3.12/linux/arch/sparc64/mm/fault.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/mm/fault.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.36 1999/07/04 04:35:56 davem Exp $
+/* $Id: fault.c,v 1.38 1999/08/02 08:39:50 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -84,10 +84,11 @@
 		printk(KERN_ALERT "Unable to handle kernel paging request "
 		       "at virtual address %016lx\n", (unsigned long)address);
 	}
-	printk(KERN_ALERT "tsk->mm->context = %016lx\n",
-	       (unsigned long) tsk->mm->context);
-	printk(KERN_ALERT "tsk->mm->pgd = %016lx\n",
-	       (unsigned long) tsk->mm->pgd);
+	printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n",
+	       (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
+	printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
+	       (tsk->mm ? (unsigned long) tsk->mm->pgd :
+		          (unsigned long) tsk->active_mm->pgd));
 	die_if_kernel("Oops", regs);
 }
 
@@ -159,11 +160,40 @@
 
 	down(&mm->mmap_sem);
 #ifdef DEBUG_LOCKUPS
-	if (regs->tpc == lastpc && address == lastaddr && write == lastwrite) {
+	if (regs->tpc == lastpc &&
+	    address == lastaddr &&
+	    write == lastwrite) {
 		lockcnt++;
 		if (lockcnt == 100000) {
-			printk("do_sparc64_fault: possible fault loop for %016lx %s\n", address, write ? "write" : "read");
+			unsigned char tmp;
+			register unsigned long tmp1 asm("o5");
+			register unsigned long tmp2 asm("o4");
+
+			printk("do_sparc64_fault[%s:%d]: possible fault loop for %016lx %s\n",
+			       current->comm, current->pid,
+			       address, write ? "write" : "read");
+			printk("do_sparc64_fault: CHECK[papgd[%016lx],pcac[%016lx]]\n",
+			       __pa(mm->pgd), pgd_val(mm->pgd[0])<<11UL);
+			__asm__ __volatile__(
+				"wrpr	%%g0, 0x494, %%pstate\n\t"
+				"mov	%3, %%g4\n\t"
+				"mov	%%g7, %0\n\t"
+				"ldxa	[%%g4] %2, %1\n\t"
+				"wrpr	%%g0, 0x096, %%pstate"
+				: "=r" (tmp1), "=r" (tmp2)
+				: "i" (ASI_DMMU), "i" (TSB_REG));
+			printk("do_sparc64_fault:    IS[papgd[%016lx],pcac[%016lx]]\n",
+			       tmp1, tmp2);
+			printk("do_sparc64_fault: CHECK[ctx(%016lx)] IS[ctx(%016lx)]\n",
+			       mm->context, spitfire_get_secondary_context());
+			__asm__ __volatile__("rd	%%asi, %0"
+					     : "=r" (tmp));
+			printk("do_sparc64_fault: CHECK[seg(%02x)] IS[seg(%02x)]\n",
+			       current->thread.current_ds.seg, tmp);
 			show_regs(regs);
+			__sti();
+			while(1)
+				barrier();
 		}
 	} else {
 		lastpc = regs->tpc;
@@ -282,8 +312,8 @@
 				return;
 			}
 		} else {
-			current->tss.sig_address = address;
-			current->tss.sig_desc = SUBSIG_NOMAPPING;
+			current->thread.sig_address = address;
+			current->thread.sig_desc = SUBSIG_NOMAPPING;
 			force_sig(SIGSEGV, current);
 			return;
 		}
@@ -293,8 +323,8 @@
 
 do_sigbus:
 	up(&mm->mmap_sem);
-	current->tss.sig_address = address;
-	current->tss.sig_desc = SUBSIG_MISCERROR;
+	current->thread.sig_address = address;
+	current->thread.sig_desc = SUBSIG_MISCERROR;
 	force_sig(SIGBUS, current);
 	if (regs->tstate & TSTATE_PRIV)
 		goto do_kernel_fault;
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c
--- v2.3.12/linux/arch/sparc64/mm/generic.c	Mon Mar 15 16:10:43 1999
+++ linux/arch/sparc64/mm/generic.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.8 1999/03/12 06:51:50 davem Exp $
+/* $Id: generic.c,v 1.9 1999/07/23 22:32:01 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -95,7 +95,8 @@
 						  space);
 				curend = address + 0x10000;
 				offset += 0x10000;
-			}
+			} else
+				offset += PAGE_SIZE;
 		} else
 			offset += PAGE_SIZE;
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.12/linux/arch/sparc64/mm/init.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/sparc64/mm/init.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.130 1999/06/29 12:34:06 davem Exp $
+/*  $Id: init.c,v 1.131 1999/07/30 09:35:45 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -42,7 +42,10 @@
 unsigned long phys_base;
 
 /* get_new_mmu_context() uses "cache + 1".  */
+spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED;
 unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
+#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
+unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
 
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext, __bss_start;
@@ -386,7 +389,7 @@
 				dvma_pages_current_offset;
 
 			/* Map the CPU's view. */
-			pgdp = pgd_offset(init_task.mm, addr);
+			pgdp = pgd_offset(&init_mm, addr);
 			pmdp = pmd_alloc_kernel(pgdp, addr);
 			ptep = pte_alloc_kernel(pmdp, addr);
 			pte = mk_pte(the_page, PAGE_KERNEL);
@@ -677,7 +680,7 @@
 			for (vaddr = trans[i].virt;
 			     vaddr < trans[i].virt + trans[i].size;
 			     vaddr += PAGE_SIZE) {
-				pgdp = pgd_offset(init_task.mm, vaddr);
+				pgdp = pgd_offset(&init_mm, vaddr);
 				if (pgd_none(*pgdp)) {
 					pmdp = sparc_init_alloc(&mempool,
 							 PMD_TABLE_SIZE);
@@ -739,7 +742,7 @@
 	int i;
 
 	if (!enter)
-		set_fs(current->tss.current_ds);
+		set_fs(current->thread.current_ds);
 
 	if (!prom_ditlb_set)
 		return;
@@ -957,9 +960,6 @@
 			     : : "r" (pstate));
 }
 
-#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
-unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
-
 /* Caller does TLB context flushing on local CPU if necessary.
  *
  * We must be careful about boundary cases so that we never
@@ -969,14 +969,16 @@
  */
 void get_new_mmu_context(struct mm_struct *mm)
 {
-	unsigned long ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK);
-	unsigned long new_ctx;
+	unsigned long ctx, new_ctx;
 	
+	spin_lock(&ctx_alloc_lock);
+	ctx = CTX_HWBITS(tlb_context_cache + 1);
 	if (ctx == 0)
 		ctx = 1;
-	if ((mm->context != NO_CONTEXT) &&
-	    !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK))
-		clear_bit(mm->context & ~(CTX_VERSION_MASK), mmu_context_bmap);
+	if (CTX_VALID(mm->context)) {
+		unsigned long nr = CTX_HWBITS(mm->context);
+		mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));
+	}
 	new_ctx = find_next_zero_bit(mmu_context_bmap, 1UL << CTX_VERSION_SHIFT, ctx);
 	if (new_ctx >= (1UL << CTX_VERSION_SHIFT)) {
 		new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
@@ -1003,12 +1005,13 @@
 			goto out;
 		}
 	}
-	set_bit(new_ctx, mmu_context_bmap);
+	mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63));
 	new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
 out:
 	tlb_context_cache = new_ctx;
+	spin_unlock(&ctx_alloc_lock);
+
 	mm->context = new_ctx;
-	mm->cpu_vm_mask = 0;
 }
 
 #ifndef __SMP__
@@ -1049,7 +1052,7 @@
 	pte_t *ptep;
 
 	while (start < end) {
-		pgdp = pgd_offset(init_task.mm, start);
+		pgdp = pgd_offset(&init_mm, start);
 		if (pgd_none(*pgdp)) {
 			pmdp = sparc_init_alloc(&mempool, PAGE_SIZE);
 			memset(pmdp, 0, PAGE_SIZE);
@@ -1073,7 +1076,7 @@
 void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
 			   int bus, int rdonly)
 {
-	pgd_t *pgdp = pgd_offset(init_task.mm, virt_addr);
+	pgd_t *pgdp = pgd_offset(&init_mm, virt_addr);
 	pmd_t *pmdp = pmd_offset(pgdp, virt_addr);
 	pte_t *ptep = pte_offset(pmdp, virt_addr);
 	pte_t pte;
@@ -1095,7 +1098,7 @@
 	pmd_t *pmdp;
 	pte_t *ptep;
 
-	pgdp = pgd_offset(init_task.mm, virt_addr);
+	pgdp = pgd_offset(&init_mm, virt_addr);
 	pmdp = pmd_offset(pgdp, virt_addr);
 	ptep = pte_offset(pmdp, virt_addr);
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.3.12/linux/arch/sparc64/mm/ultra.S	Sun Mar 28 09:07:47 1999
+++ linux/arch/sparc64/mm/ultra.S	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.32 1999/03/28 08:39:34 davem Exp $
+/* $Id: ultra.S,v 1.33 1999/08/02 08:39:49 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -136,36 +136,37 @@
 flush_icache_page:	/* %o0 = phys_page */
 	sethi		%hi(1 << 13), %o2	! IC_set bit
 	mov		1, %g1
-	srlx		%o0, 5, %o0		! phys-addr comparitor
+	srlx		%o0, 5, %o0
 	clr		%o1			! IC_addr
 	sllx		%g1, 36, %g1
 	sub		%g1, 1, %g2
-	andn		%g2, 0xff, %g2		! IC_tag mask
-	nop
+	or		%o0, %g1, %o0		! VALID+phys-addr comparitor
+	sllx		%g2, 1, %g2
 
+	andn		%g2, 0xfe, %g2		! IC_tag mask
 1:	ldda		[%o1] ASI_IC_TAG, %o4
 	and		%o5, %g2, %o5
 	cmp		%o5, %o0
 	be,pn		%xcc, iflush1
-	 nop
+	 add		%o1, 0x20, %g3
 2:	ldda		[%o1 + %o2] ASI_IC_TAG, %o4
 	and		%o5, %g2, %o5
-	cmp		%o5, %o0
 
+	cmp		%o5, %o0
 	be,pn		%xcc, iflush2
 	 nop
-3:	add		%o1, 0x20, %o1
-	cmp		%o1, %o2
+3:	cmp		%g3, %o2
 	bne,pt		%xcc, 1b
-	 nop
+	 mov		%g3, %o1
 	retl
 	 nop
+
 iflush1:stxa		%g0, [%o1] ASI_IC_TAG
-	ba,pt		%xcc, 2b
-	 flush		%g6
+	flush		%g6
+	ba,a,pt		%xcc, 2b
 iflush2:stxa		%g0, [%o1 + %o2] ASI_IC_TAG
-	ba,pt		%xcc, 3b
-	 flush		%g6
+	flush		%g6
+	ba,a,pt		%xcc, 3b
 
 #ifdef __SMP__
 	/* These are all called by the slaves of a cross call, at
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.3.12/linux/arch/sparc64/prom/p1275.c	Tue Oct 27 09:52:21 1998
+++ linux/arch/sparc64/prom/p1275.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $
+/* $Id: p1275.c,v 1.16 1999/08/02 12:05:57 jj Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -252,8 +252,8 @@
  * the counter is needed.  -DaveM
  */
 static int prom_entry_depth = 0;
-#ifdef __SMP__
 static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
+#ifdef __SMP__
 extern void smp_capture(void);
 extern void smp_release(void);
 #endif
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/solaris/ioctl.c linux/arch/sparc64/solaris/ioctl.c
--- v2.3.12/linux/arch/sparc64/solaris/ioctl.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/solaris/ioctl.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl.c,v 1.11 1999/05/27 00:36:25 davem Exp $
+/* $Id: ioctl.c,v 1.12 1999/07/23 01:57:03 davem Exp $
  * ioctl.c: Solaris ioctl emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -367,7 +367,6 @@
 static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg,
                                     int len, int *len_p)
 {
-        struct inode *ino;
 	int ret;
 		
 	switch (cmd & 0xff) {
@@ -459,7 +458,6 @@
 	mm_segment_t old_fs;
 	struct strioctl si;
 	struct inode *ino;
-        struct file *filp;
         struct sol_socket_struct *sock;
         struct module_info *mi;
 
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c
--- v2.3.12/linux/arch/sparc64/solaris/socksys.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/solaris/socksys.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.8 1998/08/26 10:28:28 davem Exp $
+/* $Id: socksys.c,v 1.9 1999/07/23 01:57:07 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- v2.3.12/linux/arch/sparc64/solaris/timod.c	Wed Jul 28 14:47:42 1999
+++ linux/arch/sparc64/solaris/timod.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.2 1999/05/12 11:11:55 davem Exp $
+/* $Id: timod.c,v 1.3 1999/08/02 12:06:01 jj Exp $
  * timod.c: timod emulation.
  *
  * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
@@ -33,9 +33,7 @@
 	u32 arg);
 asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 
-#ifdef __SMP__
 spinlock_t timod_pagelock = SPIN_LOCK_UNLOCKED;
-#endif
 static char * page = NULL ;
 
 #ifndef DEBUG_SOLARIS_KMALLOC
@@ -866,7 +864,7 @@
 
 	SOLD("entry");
 	lock_kernel();
-	if(fd >= current->files->max_fds) goto out;
+	if(fd >= NR_OPEN) goto out;
 
 	filp = current->files->fd[fd];
 	if(!filp) goto out;
@@ -933,7 +931,7 @@
 
 	SOLD("entry");
 	lock_kernel();
-	if(fd >= current->files->max_fds) goto out;
+	if(fd >= NR_OPEN) goto out;
 
 	filp = current->files->fd[fd];
 	if(!filp) goto out;
diff -u --recursive --new-file v2.3.12/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- v2.3.12/linux/arch/sparc64/vmlinux.lds	Tue Aug  4 16:03:35 1998
+++ linux/arch/sparc64/vmlinux.lds	Fri Aug  6 11:58:00 1999
@@ -39,8 +39,17 @@
   __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(8192);
   __init_end = .;
+  . = ALIGN(64);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
   __bss_start = .;
   .sbss      : { *(.sbss) *(.scommon) }
   .bss       :
diff -u --recursive --new-file v2.3.12/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c
--- v2.3.12/linux/drivers/acorn/block/fd1772.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/block/fd1772.c	Mon Aug  2 10:19:52 1999
@@ -116,6 +116,8 @@
  *     16/11/96 - Fiddled and frigged for 2.0.18
  *
  * DAG 30/01/99 - Started frobbing for 2.2.1
+ * DAG 20/06/99 - A little more frobbing:
+ *     Included include/asm/uaccess.h for get_user/put_user
  */
 
 #include <linux/sched.h>
@@ -142,6 +144,8 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/segment.h>
+#include <asm/uaccess.h>
+
 
 #define MAJOR_NR FLOPPY_MAJOR
 #define FLOPPY_DMA 0
@@ -1600,7 +1604,7 @@
 };
 
 
-int floppy_init(void)
+int fd1772_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/acorn/char/mouse_rpc.c linux/drivers/acorn/char/mouse_rpc.c
--- v2.3.12/linux/drivers/acorn/char/mouse_rpc.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/char/mouse_rpc.c	Mon Aug  2 10:19:52 1999
@@ -18,7 +18,7 @@
 #include <asm/io.h>
 #include <asm/iomd.h>
 
-#include "../../char/mouse.h"
+#include "../../char/busmouse.h"
 
 static short old_x, old_y, old_b;
 static int mousedev;
diff -u --recursive --new-file v2.3.12/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
--- v2.3.12/linux/drivers/acorn/net/ether3.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/net/ether3.c	Mon Aug  2 10:19:52 1999
@@ -100,9 +100,17 @@
  * The SEEQ8005 doesn't like us writing to it's registers
  * too quickly.
  */
-#define ether3_outb(v,r)	{ outb((v),(r)); udelay(1); }
-#define ether3_outw(v,r)	{ outw((v),(r)); udelay(1); }
+static inline void ether3_outb(int v, const int r)
+{
+	outb(v, r);
+	udelay(1);
+}
 
+static inline void ether3_outw(int v, const int r)
+{
+	outw(v, r);
+	udelay(1);
+}
 #define ether3_inb(r)		({ unsigned int __v = inb((r)); udelay(1); __v; })
 #define ether3_inw(r)		({ unsigned int __v = inw((r)); udelay(1); __v; })
 
diff -u --recursive --new-file v2.3.12/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- v2.3.12/linux/drivers/acorn/scsi/acornscsi.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/acornscsi.c	Mon Aug  2 10:19:52 1999
@@ -2982,7 +2982,7 @@
 
     p = string;
     
-    p += sprintf(string, "%s at port %X irq %d v%d.%d.%d"
+    p += sprintf(string, "%s at port %08lX irq %d v%d.%d.%d"
 #ifdef CONFIG_SCSI_ACORNSCSI_SYNC
     " SYNC"
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- v2.3.12/linux/drivers/acorn/scsi/fas216.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/fas216.c	Mon Aug  2 10:19:52 1999
@@ -100,11 +100,16 @@
 
 static void fas216_dumpstate(FAS216_Info *info)
 {
+	unsigned char is, stat, inst;
+
+	is   = inb(REG_IS(info));
+	stat = inb(REG_STAT(info));
+	inst = inb(REG_INST(info));
+	
 	printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"
 	       " INST=%02X IS=%02X CFIS=%02X",
 		inb(REG_CTCL(info)), inb(REG_CTCM(info)),
-		inb(REG_CMD(info)),  inb(REG_STAT(info)),
-		inb(REG_INST(info)), inb(REG_IS(info)),
+		inb(REG_CMD(info)),  stat, inst, is,
 		inb(REG_CFIS(info)));
 	printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",
 		inb(REG_CNTL1(info)), inb(REG_CNTL2(info)),
@@ -623,36 +628,18 @@
 {
 	unsigned int residual;
 	char *ptr;
-	int correction = 0;
 
 	fas216_checkmagic(info, "fas216_pio");
 
 	residual = info->scsi.SCp.this_residual;
 	ptr = info->scsi.SCp.ptr;
 
-	if (direction == DMA_OUT) {
-//	    	while (residual > 0) {
-//			if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) {
-				outb(*ptr++, REG_FF(info));
-				residual -= 1;
-//			}
-//			if (inb(REG_STAT(info)) & STAT_INT)
-//				break;
-//		}
-//		correction = inb(REG_CFIS(info)) & CFIS_CF;
-	} else {
-//	    	while (residual > 0) {
-//			if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) {
-				*ptr++ = inb(REG_FF(info));
-				residual -= 1;
-//			}
-//			if (inb(REG_STAT(info)) & STAT_INT)
-//				break;
-//		}
-	}
+	if (direction == DMA_OUT)
+		outb(*ptr++, REG_FF(info));
+	else
+		*ptr++ = inb(REG_FF(info));
 
-	ptr -= correction;
-	residual += correction;
+	residual -= 1;
 
 	if (residual == 0) {
 		if (info->scsi.SCp.buffers_residual) {
@@ -1035,26 +1022,59 @@
 #endif
 }
 
-static unsigned char fas216_get_msg_byte(FAS216_Info *info)
+static int fas216_wait_cmd(FAS216_Info *info, int cmd)
 {
 	int tout;
+	int stat;
 
-	outb(CMD_MSGACCEPTED, REG_CMD(info));
-	for (tout = 1000000; tout; tout --)
-		if (inb(REG_STAT(info)) & STAT_INT)
+	outb(cmd, REG_CMD(info));
+
+	for (tout = 1000; tout; tout -= 1) {
+		stat = inb(REG_STAT(info));
+		if (stat & STAT_INT)
 			break;
+		udelay(1);
+	}
+
+	return stat;
+}
+
+static int fas216_get_msg_byte(FAS216_Info *info)
+{
+	int stat;
+
+	stat = fas216_wait_cmd(info, CMD_MSGACCEPTED);
+
+	if ((stat & STAT_INT) == 0)
+		goto timedout;
+
+	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
+		goto unexpected_phase_change;
 
 	inb(REG_INST(info));
 
-	outb(CMD_TRANSFERINFO, REG_CMD(info));
+	stat = fas216_wait_cmd(info, CMD_TRANSFERINFO);
 
-	for (tout = 1000000; tout; tout --)
-		if (inb(REG_STAT(info)) & STAT_INT)
-			break;
+	if ((stat & STAT_INT) == 0)
+		goto timedout;
+
+	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
+		goto unexpected_phase_change;
 
 	inb(REG_INST(info));
 
 	return inb(REG_FF(info));
+
+timedout:
+	printk("scsi%d.%c: timed out waiting for message byte\n",
+		info->host->host_no, fas216_target(info));
+	return -1;
+
+unexpected_phase_change:
+	printk("scsi%d.%c: unexpected phase change: status = %02X\n",
+		info->host->host_no, fas216_target(info), stat);
+
+	return -2;
 }
 
 /* Function: void fas216_message(FAS216_Info *info)
@@ -1063,20 +1083,33 @@
  */
 static void fas216_message(FAS216_Info *info)
 {
-	unsigned char message[16];
-	unsigned int msglen = 1;
+	unsigned char *message = info->scsi.message;
+	unsigned int msglen = 1, i;
+	int msgbyte = 0;
 
 	fas216_checkmagic(info, "fas216_message");
 
 	message[0] = inb(REG_FF(info));
 
 	if (message[0] == EXTENDED_MESSAGE) {
-		message[1] = fas216_get_msg_byte(info);
+		msgbyte = fas216_get_msg_byte(info);
 
-		for (msglen = 2; msglen < message[1] + 2; msglen++)
-			message[msglen] = fas216_get_msg_byte(info);
+		if (msgbyte >= 0) {
+			message[1] = msgbyte;
+
+			for (msglen = 2; msglen < message[1] + 2; msglen++) {
+				msgbyte = fas216_get_msg_byte(info);
+
+				if (msgbyte >= 0)
+					message[msglen] = msgbyte;
+				else
+					break;
+			}
+		}
 	}
 
+	info->scsi.msglen = msglen;
+
 #ifdef DEBUG_MESSAGES
 	{
 		int i;
@@ -1098,12 +1131,18 @@
 
 	switch (message[0]) {
 	case COMMAND_COMPLETE:
+		if (msglen != 1)
+			goto unrecognised;
+
 		printk(KERN_ERR "scsi%d.%c: command complete with no "
 			"status in MESSAGE_IN?\n",
 			info->host->host_no, fas216_target(info));
 		break;
 
 	case SAVE_POINTERS:
+		if (msglen != 1)
+			goto unrecognised;
+
 		/*
 		 * Save current data pointer to SAVED data pointer
 		 * SCSI II standard says that we must not acknowledge
@@ -1122,6 +1161,9 @@
 		break;
 
 	case RESTORE_POINTERS:
+		if (msglen != 1)
+			goto unrecognised;
+
 		/*
 		 * Restore current data pointer from SAVED data pointer
 		 */
@@ -1134,10 +1176,16 @@
 		break;
 
 	case DISCONNECT:
+		if (msglen != 1)
+			goto unrecognised;
+
 		info->scsi.phase = PHASE_MSGIN_DISCONNECT;
 		break;
 
 	case MESSAGE_REJECT:
+		if (msglen != 1)
+			goto unrecognised;
+
 		switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
 		case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
 			fas216_handlesync(info, message);
@@ -1158,13 +1206,19 @@
 		break;
 
 	case SIMPLE_QUEUE_TAG:
-		/* handled above */
+		if (msglen < 2)
+			goto unrecognised;
+
+		/* handled above - print a warning since this is untested */
 		printk("scsi%d.%c: reconnect queue tag %02X\n",
 			info->host->host_no, fas216_target(info),
 			message[1]);
 		break;
 
 	case EXTENDED_MESSAGE:
+		if (msglen < 3)
+			goto unrecognised;
+
 		switch (message[2]) {
 		case EXTENDED_SDTR:	/* Sync transfer negociation request/reply */
 			fas216_handlesync(info, message);
@@ -1175,28 +1229,38 @@
 			break;
 
 		default:
-			printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n",
-				info->host->host_no, fas216_target(info),
-				message[2]);
-			goto reject_message;
+			goto unrecognised;
 		}
 		break;
 
 	default:
-		printk("scsi%d.%c: unrecognised message %02X, rejecting\n",
-			info->host->host_no, fas216_target(info),
-			message[0]);
-		goto reject_message;
+		goto unrecognised;
 	}
 	outb(CMD_MSGACCEPTED, REG_CMD(info));
 	return;
 
+unrecognised:
+	printk("scsi%d.%c: unrecognised message, rejecting\n",
+		info->host->host_no, fas216_target(info));
+	printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info));
+	for (i = 0; i < msglen; i++)
+		printk("%s%02X", i & 31 ? " " : "\n  ", message[i]);
+	printk("\n");
+
 reject_message:
+	/*
+	 * Something strange seems to be happening here -
+	 * I can't use SETATN since the chip gives me an
+	 * invalid command interrupt when I do.  Weird.
+	 */
+outb(CMD_NOP, REG_CMD(info));
+fas216_dumpstate(info);
 	outb(CMD_SETATN, REG_CMD(info));
-	outb(CMD_MSGACCEPTED, REG_CMD(info));
 	msgqueue_flush(&info->scsi.msgs);
 	msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
 	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+fas216_dumpstate(info);
+	outb(CMD_MSGACCEPTED, REG_CMD(info));
 }
 
 /* Function: void fas216_send_command(FAS216_Info *info)
@@ -1269,156 +1333,182 @@
 	printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n",
 		info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase);
 #endif
-	switch (ssr & IS_BITS) {
-	case IS_MSGBYTESENT:		/* select with ATN and stop steps completed	*/
-	case IS_COMPLETE:			/* last action completed		*/
-		outb(CMD_NOP, REG_CMD(info));
+
+	switch (info->scsi.phase) {
+	case PHASE_SELECTION:
+		if ((ssr & IS_BITS) != 1)
+			goto bad_is;
+		break;
+
+	case PHASE_SELSTEPS:
+		switch (ssr & IS_BITS) {
+		case IS_SELARB:
+		case IS_MSGBYTESENT:
+			goto bad_is;
+
+		case IS_NOTCOMMAND:
+		case IS_EARLYPHASE:
+			if ((stat & STAT_BUSMASK) == STAT_MESGIN)
+				break;
+			goto bad_is;
+
+		case IS_COMPLETE:
+			break;
+		}
+
+	default:
+		break;
+	}
+
+	outb(CMD_NOP, REG_CMD(info));
 
 #define STATE(st,ph) ((ph) << 3 | (st))
-		/* This table describes the legal SCSI state transitions,
-		 * as described by the SCSI II spec.
-		 */
-		switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
-							/* Reselmsgin   -> Data In	*/
-		case STATE(STAT_DATAIN, PHASE_RECONNECTED):
-			fas216_finish_reconnect(info);
-		case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
-		case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
-		case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
-		case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
-		case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
-			fas216_starttransfer(info, DMA_IN, 0);
-			return;
-
-		case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
-			fas216_starttransfer(info, DMA_OUT, 0);
-			return;
-
-							/* Reselmsgin   -> Data Out     */
-		case STATE(STAT_DATAOUT, PHASE_RECONNECTED):
-			fas216_finish_reconnect(info);
-		case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
-		case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
-		case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
-		case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
-			fas216_starttransfer(info, DMA_OUT, 1);
-			return;
-
-							/* Reselmsgin   -> Status       */
-		case STATE(STAT_STATUS, PHASE_RECONNECTED):
-			fas216_finish_reconnect(info);
-			goto status;
-		case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
-		case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
-			fas216_stoptransfer(info);
-		case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
-		case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
-		case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
-		case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
-		status:
-			outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
-			info->scsi.phase = PHASE_STATUS;
-			return;
-
-		case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
-		case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
-			fas216_stoptransfer(info);
-		case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
-		case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
-			info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
-			outb(CMD_TRANSFERINFO, REG_CMD(info));
-			info->scsi.phase = PHASE_MSGIN;
-			return;
-
-							/* Reselmsgin   -> Message In   */
-		case STATE(STAT_MESGIN, PHASE_RECONNECTED):
-		case STATE(STAT_MESGIN, PHASE_MSGIN):
-			info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
-			outb(CMD_TRANSFERINFO, REG_CMD(info));
-			return;
+	/* This table describes the legal SCSI state transitions,
+	 * as described by the SCSI II spec.
+	 */
+	switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
+						/* Reselmsgin   -> Data In	*/
+	case STATE(STAT_DATAIN, PHASE_RECONNECTED):
+		fas216_finish_reconnect(info);
+	case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
+		fas216_starttransfer(info, DMA_IN, 0);
+		return;
 
-							/* Reselmsgin   -> Command      */
-		case STATE(STAT_COMMAND, PHASE_RECONNECTED):
-			fas216_finish_reconnect(info);
-		case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
-		case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
-			fas216_send_command(info);
-			info->scsi.phase = PHASE_COMMAND;
-			return;
-							/* Selection    -> Message Out  */
-		case STATE(STAT_MESGOUT, PHASE_SELECTION):
-			fas216_send_messageout(info, 1);
-			return;
-							/* Any          -> Message Out  */
-		case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
-			fas216_send_messageout(info, 0);
-			return;
-
-		/* Error recovery rules.
-		 *   These either attempt to abort or retry the operation.
-		 * TODO: we need more of these
-		 */
-		case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
-			/* error - we've sent out all the command bytes
-			 * we have.
-			 * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
-			 * to include the command bytes sent for this to work
-			 * correctly.
-			 */
-			printk(KERN_ERR "scsi%d.%c: "
-				"target trying to receive more command bytes\n",
-				info->host->host_no, fas216_target(info));
-			outb(CMD_SETATN, REG_CMD(info));
-			outb(15, REG_STCL(info));
-			outb(0, REG_STCM(info));
-			outb(0, REG_STCH(info));
-			outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info));
-			msgqueue_flush(&info->scsi.msgs);
-			msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
-			info->scsi.phase = PHASE_MSGOUT_EXPECT;
-			return;
+	case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
+		fas216_starttransfer(info, DMA_OUT, 0);
+		return;
 
-							/* Selection    -> Message Out  */
-		case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
-		case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out  -> Message Out  */
-			/* If we get another message out phase, this
-			 * usually means some parity error occurred.
-			 * Resend complete set of messages.  If we have
-			 * more than 1 byte to send, we need to assert
-			 * ATN again.
-			 */
-			if (msgqueue_msglength(&info->scsi.msgs) > 1)
-				outb(CMD_SETATN, REG_CMD(info));
+						/* Reselmsgin   -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_RECONNECTED):
+		fas216_finish_reconnect(info);
+	case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
+		fas216_starttransfer(info, DMA_OUT, 1);
+		return;
 
-			fas216_send_messageout(info, 0);
-			return;
-		}
+						/* Reselmsgin   -> Status       */
+	case STATE(STAT_STATUS, PHASE_RECONNECTED):
+		fas216_finish_reconnect(info);
+		goto status;
+	case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
+	case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
+		fas216_stoptransfer(info);
+	case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
+	case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
+	case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
+	case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
+	status:
+		outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
+		info->scsi.phase = PHASE_STATUS;
+		return;
 
-		if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
-			printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
-				info->host->host_no, fas216_target(info),
-				fas216_bus_phase(stat));
-			msgqueue_flush(&info->scsi.msgs);
+	case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
+		fas216_stoptransfer(info);
+	case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
+		info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
+		outb(CMD_FLUSHFIFO, REG_CMD(info));
+		outb(CMD_TRANSFERINFO, REG_CMD(info));
+		info->scsi.phase = PHASE_MSGIN;
+		return;
+
+						/* Reselmsgin   -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_RECONNECTED):
+	case STATE(STAT_MESGIN, PHASE_MSGIN):
+		info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
+		outb(CMD_TRANSFERINFO, REG_CMD(info));
+		return;
+
+						/* Reselmsgin   -> Command      */
+	case STATE(STAT_COMMAND, PHASE_RECONNECTED):
+		fas216_finish_reconnect(info);
+	case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
+	case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
+		fas216_send_command(info);
+		info->scsi.phase = PHASE_COMMAND;
+		return;
+						/* Selection    -> Message Out  */
+	case STATE(STAT_MESGOUT, PHASE_SELECTION):
+		fas216_send_messageout(info, 1);
+		return;
+						/* Any          -> Message Out  */
+	case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
+		fas216_send_messageout(info, 0);
+		return;
+
+	/* Error recovery rules.
+	 *   These either attempt to abort or retry the operation.
+	 * TODO: we need more of these
+	 */
+	case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
+		/* error - we've sent out all the command bytes
+		 * we have.
+		 * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
+		 * to include the command bytes sent for this to work
+		 * correctly.
+		 */
+		printk(KERN_ERR "scsi%d.%c: "
+			"target trying to receive more command bytes\n",
+			info->host->host_no, fas216_target(info));
+		outb(CMD_SETATN, REG_CMD(info));
+		outb(15, REG_STCL(info));
+		outb(0, REG_STCM(info));
+		outb(0, REG_STCH(info));
+		outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info));
+		msgqueue_flush(&info->scsi.msgs);
+		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		return;
+
+						/* Selection    -> Message Out  */
+	case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
+	case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out  -> Message Out  */
+		/* If we get another message out phase, this
+		 * usually means some parity error occurred.
+		 * Resend complete set of messages.  If we have
+		 * more than 1 byte to send, we need to assert
+		 * ATN again.
+		 */
+		if (msgqueue_msglength(&info->scsi.msgs) > 1)
 			outb(CMD_SETATN, REG_CMD(info));
-			msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
-			info->scsi.phase = PHASE_MSGOUT_EXPECT;
-			info->scsi.aborting = 1;
-			outb(CMD_TRANSFERINFO, REG_CMD(info));
-			return;
-		}
-		printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
-			info->host->host_no, fas216_target(info),
-			fas216_bus_phase(stat),
-			fas216_drv_phase(info));
-		print_debug_list();
+
+		fas216_send_messageout(info, 0);
 		return;
+	}
 
-	default:
-		printk("scsi%d.%c: bus service at step %d?\n",
+	if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
+		printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
 			info->host->host_no, fas216_target(info),
-			ssr & IS_BITS);
-		print_debug_list();
+			fas216_bus_phase(stat));
+		msgqueue_flush(&info->scsi.msgs);
+		outb(CMD_SETATN, REG_CMD(info));
+		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		info->scsi.aborting = 1;
+		outb(CMD_TRANSFERINFO, REG_CMD(info));
+		return;
 	}
+	printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
+		info->host->host_no, fas216_target(info),
+		fas216_bus_phase(stat),
+		fas216_drv_phase(info));
+	print_debug_list();
+	return;
+
+bad_is:
+	printk("scsi%d.%c: bus service at step %d?\n",
+		info->host->host_no, fas216_target(info),
+		ssr & IS_BITS);
+	print_debug_list();
+
+	fas216_done(info, DID_ERROR);
 }
 
 /* Function: void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
@@ -1895,7 +1985,7 @@
 }
 
 /* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1,
- *				       Scsi_Cmnd **SCpntp2, int result)
+ *				       Scsi_Cmnd **SCpntp2, int result, int no_report)
  * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
  * Params   : SCpntp1 - pointer to command to return
  *	      SCpntp2 - pointer to command to check
@@ -1904,7 +1994,7 @@
  *	      structure as *SCpntp2.
  */
 static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2,
-				int result)
+				int result, int no_report)
 {
 	Scsi_Cmnd *SCpnt = *SCpntp1;
 
@@ -1912,7 +2002,8 @@
 		*SCpntp1 = NULL;
 
 		SCpnt->result = result;
-		SCpnt->scsi_done(SCpnt);
+		if (!no_report || SCpnt != *SCpntp2)
+			SCpnt->scsi_done(SCpnt);
 	}
 
 	if (SCpnt == *SCpntp2)
@@ -2199,6 +2290,7 @@
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
 	Scsi_Cmnd *SCptr;
 	int result = 0;
+	int synchronous = reset_flags & SCSI_RESET_SYNCHRONOUS;
 
 	fas216_checkmagic(info, "fas216_reset");
 
@@ -2258,10 +2350,10 @@
 	/*
 	 * Signal all commands in progress have been reset
 	 */
-	fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16);
+	fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16, synchronous);
 
 	while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL)
-		fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16);
+		fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16, synchronous);
 
 	if (SCpnt) {
 		/*
@@ -2274,7 +2366,8 @@
 		queue_removecmd(&info->queues.issue, SCpnt);
 
 		SCpnt->result = DID_RESET << 16;
-		SCpnt->scsi_done(SCpnt);
+		if (!synchronous)
+			SCpnt->scsi_done(SCpnt);
 	}
 
 	return result | SCSI_RESET_SUCCESS;
diff -u --recursive --new-file v2.3.12/linux/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h
--- v2.3.12/linux/drivers/acorn/scsi/fas216.h	Thu Jun 17 01:11:35 1999
+++ linux/drivers/acorn/scsi/fas216.h	Mon Aug  2 10:19:52 1999
@@ -237,6 +237,8 @@
 
 		unsigned int	async_stp;		/* Async transfer STP value		*/
 		unsigned char	msgin_fifo;		/* bytes in fifo at time of message in	*/
+		unsigned char	message[256];		/* last message received from device	*/
+		unsigned int	msglen;			/* length of last message received	*/
 
 		unsigned char	disconnectable:1;	/* this command can be disconnected	*/
 		unsigned char	aborting:1;		/* aborting command			*/
diff -u --recursive --new-file v2.3.12/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.12/linux/drivers/block/Config.in	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/Config.in	Thu Aug  5 18:48:45 1999
@@ -43,7 +43,6 @@
           bool '     Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO
           if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
             bool '       Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS
-            bool '       Generic ATA-66 support (DANGEROUS)' CONFIG_IDEDMA_ULTRA_66
             define_bool IDEDMA_PCI_EXPERIMENTAL y
           else
             define_bool IDEDMA_PCI_EXPERIMENTAL n
@@ -61,6 +60,7 @@
              "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
           bool '       HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
         fi
+        bool '     HPT366 chipset support' CONFIG_BLK_DEV_HPT366
         bool '     Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
         if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
              "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
@@ -80,6 +80,7 @@
             bool '       Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE
           fi
         fi
+        bool '     SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
         if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
           bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
           bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
@@ -206,9 +207,11 @@
      "$CONFIG_BLK_DEV_CMD640" = "y" -o \
      "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
      "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT366" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
      "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
+     "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
   define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
diff -u --recursive --new-file v2.3.12/linux/drivers/block/MAKEDEV-IDE45 linux/drivers/block/MAKEDEV-IDE45
--- v2.3.12/linux/drivers/block/MAKEDEV-IDE45	Thu May 13 11:00:08 1999
+++ linux/drivers/block/MAKEDEV-IDE45	Wed Dec 31 16:00:00 1969
@@ -1,99 +0,0 @@
-#!/bin/sh
-#
-#	Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu>
-#
-#	The song goes, "I did it the hard way..........."
-#
-
-if [ ! -f /dev/hdi ]; then \
-	echo "Making IDE4 Primary Devices hdi's"; \
-	mknod /dev/hdi b 56 0; \
-	mknod /dev/hdi1 b 56 1; \
-	mknod /dev/hdi2 b 56 2; \
-	mknod /dev/hdi3 b 56 3; \
-	mknod /dev/hdi4 b 56 4; \
-	mknod /dev/hdi5 b 56 5; \
-	mknod /dev/hdi6 b 56 6; \
-	mknod /dev/hdi7 b 56 7; \
-	mknod /dev/hdi8 b 56 8; \
-	mknod /dev/hdi9 b 56 9; \
-	mknod /dev/hdi10 b 56 10; \
-	mknod /dev/hdi11 b 56 11; \
-	mknod /dev/hdi12 b 56 12; \
-	mknod /dev/hdi13 b 56 13; \
-	mknod /dev/hdi14 b 56 14; \
-	mknod /dev/hdi15 b 56 15; \
-	mknod /dev/hdi16 b 56 16; \
-	chown root.disk /dev/hdi*; \
-	chmod 660 /dev/hdi*; \
-fi
-
-if [ ! -f /dev/hdj ]; then \
-	echo "Making IDE4 Secondary Devices hdj's"; \
-	mknod /dev/hdj b 56 64; \
-	mknod /dev/hdj1 b 56 65; \
-	mknod /dev/hdj2 b 56 66; \
-	mknod /dev/hdj3 b 56 67; \
-	mknod /dev/hdj4 b 56 68; \
-	mknod /dev/hdj5 b 56 69; \
-	mknod /dev/hdj6 b 56 70; \
-	mknod /dev/hdj7 b 56 71; \
-	mknod /dev/hdj8 b 56 72; \
-	mknod /dev/hdj9 b 56 73; \
-	mknod /dev/hdj10 b 56 74; \
-	mknod /dev/hdj11 b 56 75; \
-	mknod /dev/hdj12 b 56 76; \
-	mknod /dev/hdj13 b 56 77; \
-	mknod /dev/hdj14 b 56 78; \
-	mknod /dev/hdj15 b 56 79; \
-	mknod /dev/hdj16 b 56 80; \
-	chown root.disk /dev/hdj*; \
-	chmod 660 /dev/hdj*; \
-fi
-
-if [ ! -f /dev/hdk ]; then \
-	echo "Making IDE5 Primary Devices hdk's"; \
-	mknod /dev/hdk b 57 0; \
-	mknod /dev/hdk1 b 57 1; \
-	mknod /dev/hdk2 b 57 2; \
-	mknod /dev/hdk3 b 57 3; \
-	mknod /dev/hdk4 b 57 4; \
-	mknod /dev/hdk5 b 57 5; \
-	mknod /dev/hdk6 b 57 6; \
-	mknod /dev/hdk7 b 57 7; \
-	mknod /dev/hdk8 b 57 8; \
-	mknod /dev/hdk9 b 57 9; \
-	mknod /dev/hdk10 b 57 10; \
-	mknod /dev/hdk11 b 57 11; \
-	mknod /dev/hdk12 b 57 12; \
-	mknod /dev/hdk13 b 57 13; \
-	mknod /dev/hdk14 b 57 14; \
-	mknod /dev/hdk15 b 57 15; \
-	mknod /dev/hdk16 b 57 16; \
-	chown root.disk /dev/hdk*; \
-	chmod 660 /dev/hdk*; \
-fi
-
-if [ ! -f /dev/hdl ]; then \
-	echo "Making IDE5 Secondary Devices hdl's"; \
-	mknod /dev/hdl b 57 64; \
-	mknod /dev/hdl1 b 57 65; \
-	mknod /dev/hdl2 b 57 66; \
-	mknod /dev/hdl3 b 57 67; \
-	mknod /dev/hdl4 b 57 68; \
-	mknod /dev/hdl5 b 57 69; \
-	mknod /dev/hdl6 b 57 70; \
-	mknod /dev/hdl7 b 57 71; \
-	mknod /dev/hdl8 b 57 72; \
-	mknod /dev/hdl9 b 57 73; \
-	mknod /dev/hdl10 b 57 74; \
-	mknod /dev/hdl11 b 57 75; \
-	mknod /dev/hdl12 b 57 76; \
-	mknod /dev/hdl13 b 57 77; \
-	mknod /dev/hdl14 b 57 78; \
-	mknod /dev/hdl15 b 57 79; \
-	mknod /dev/hdl16 b 57 80; \
-	chown root.disk /dev/hdl*; \
-	chmod 660 /dev/hdl*; \
-fi
-
diff -u --recursive --new-file v2.3.12/linux/drivers/block/MAKEDEV-IDE67 linux/drivers/block/MAKEDEV-IDE67
--- v2.3.12/linux/drivers/block/MAKEDEV-IDE67	Thu May 13 11:00:08 1999
+++ linux/drivers/block/MAKEDEV-IDE67	Wed Dec 31 16:00:00 1969
@@ -1,99 +0,0 @@
-#!/bin/sh
-#
-#	Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu>
-#
-#	The song goes, "I did it the hard way..........."
-#
-
-if [ ! -f /dev/hdm ]; then \
-	echo "Making IDE6 Primary Devices hdm's"; \
-	mknod /dev/hdm b 88 0; \
-	mknod /dev/hdm1 b 88 1; \
-	mknod /dev/hdm2 b 88 2; \
-	mknod /dev/hdm3 b 88 3; \
-	mknod /dev/hdm4 b 88 4; \
-	mknod /dev/hdm5 b 88 5; \
-	mknod /dev/hdm6 b 88 6; \
-	mknod /dev/hdm7 b 88 7; \
-	mknod /dev/hdm8 b 88 8; \
-	mknod /dev/hdm9 b 88 9; \
-	mknod /dev/hdm10 b 88 10; \
-	mknod /dev/hdm11 b 88 11; \
-	mknod /dev/hdm12 b 88 12; \
-	mknod /dev/hdm13 b 88 13; \
-	mknod /dev/hdm14 b 88 14; \
-	mknod /dev/hdm15 b 88 15; \
-	mknod /dev/hdm16 b 88 16; \
-	chown root.disk /dev/hdm*; \
-	chmod 660 /dev/hdm*; \
-fi
-
-if [ ! -f /dev/hdn ]; then \
-	echo "Making IDE6 Secondary Devices hdn's"; \
-	mknod /dev/hdn b 88 64; \
-	mknod /dev/hdn1 b 88 65; \
-	mknod /dev/hdn2 b 88 66; \
-	mknod /dev/hdn3 b 88 67; \
-	mknod /dev/hdn4 b 88 68; \
-	mknod /dev/hdn5 b 88 69; \
-	mknod /dev/hdn6 b 88 70; \
-	mknod /dev/hdn7 b 88 71; \
-	mknod /dev/hdn8 b 88 72; \
-	mknod /dev/hdn9 b 88 73; \
-	mknod /dev/hdn10 b 88 74; \
-	mknod /dev/hdn11 b 88 75; \
-	mknod /dev/hdn12 b 88 76; \
-	mknod /dev/hdn13 b 88 77; \
-	mknod /dev/hdn14 b 88 78; \
-	mknod /dev/hdn15 b 88 79; \
-	mknod /dev/hdn16 b 88 80; \
-	chown root.disk /dev/hdn*; \
-	chmod 660 /dev/hdn*; \
-fi
-
-if [ ! -f /dev/hdo ]; then \
-	echo "Making IDE7 Primary Devices hdo's"; \
-	mknod /dev/hdo b 89 0; \
-	mknod /dev/hdo1 b 89 1; \
-	mknod /dev/hdo2 b 89 2; \
-	mknod /dev/hdo3 b 89 3; \
-	mknod /dev/hdo4 b 89 4; \
-	mknod /dev/hdo5 b 89 5; \
-	mknod /dev/hdo6 b 89 6; \
-	mknod /dev/hdo7 b 89 7; \
-	mknod /dev/hdo8 b 89 8; \
-	mknod /dev/hdo9 b 89 9; \
-	mknod /dev/hdo10 b 89 10; \
-	mknod /dev/hdo11 b 89 11; \
-	mknod /dev/hdo12 b 89 12; \
-	mknod /dev/hdo13 b 89 13; \
-	mknod /dev/hdo14 b 89 14; \
-	mknod /dev/hdo15 b 89 15; \
-	mknod /dev/hdo16 b 89 16; \
-	chown root.disk /dev/hdo*; \
-	chmod 660 /dev/hdo*; \
-fi
-
-if [ ! -f /dev/hdp ]; then \
-	echo "Making IDE7 Secondary Devices hdp's"; \
-	mknod /dev/hdp b 89 64; \
-	mknod /dev/hdp1 b 89 65; \
-	mknod /dev/hdp2 b 89 66; \
-	mknod /dev/hdp3 b 89 67; \
-	mknod /dev/hdp4 b 89 68; \
-	mknod /dev/hdp5 b 89 69; \
-	mknod /dev/hdp6 b 89 70; \
-	mknod /dev/hdp7 b 89 71; \
-	mknod /dev/hdp8 b 89 72; \
-	mknod /dev/hdp9 b 89 73; \
-	mknod /dev/hdp10 b 89 74; \
-	mknod /dev/hdp11 b 89 75; \
-	mknod /dev/hdp12 b 89 76; \
-	mknod /dev/hdp13 b 89 77; \
-	mknod /dev/hdp14 b 89 78; \
-	mknod /dev/hdp15 b 89 79; \
-	mknod /dev/hdp16 b 89 80; \
-	chown root.disk /dev/hdp*; \
-	chmod 660 /dev/hdp*; \
-fi
-
diff -u --recursive --new-file v2.3.12/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.12/linux/drivers/block/Makefile	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/Makefile	Thu Aug  5 18:48:45 1999
@@ -94,116 +94,136 @@
   endif
 endif
 
-ifeq ($(CONFIG_BLK_DEV_HD),y)
-L_OBJS += hd.o
+#
+# IDE-STUFF
+#
+
+ifeq ($(CONFIG_BLK_DEV_AEC6210),y)
+IDE_OBJS += aec6210.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_RZ1000),y)
-IDE_OBJS += rz1000.o
+ifeq ($(CONFIG_BLK_DEV_ALI14XX),y)
+IDE_OBJS += ali14xx.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_CMD640),y)
-IDE_OBJS += cmd640.o
+ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
+IDE_OBJS += alim15x3.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y)
-IDE_OBJS += ide-pmac.o
+ifeq ($(CONFIG_BLK_DEV_BUDDHA),y)
+IDE_OBJS += buddha.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
-IDE_OBJS += ide-pci.o
+ifeq ($(CONFIG_BLK_DEV_CMD640),y)
+IDE_OBJS += cmd640.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
-IDE_OBJS += ide-dma.o
+ifeq ($(CONFIG_BLK_DEV_CMD646),y)
+IDE_OBJS += cmd646.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_CY82C693),y)
+IDE_OBJS += cy82c693.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_DTC2278),y)
 IDE_OBJS += dtc2278.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_HT6560B),y)
-IDE_OBJS += ht6560b.o
+ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y)
+IDE_OBJS += falconide.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_QD6580),y)
-IDE_OBJS += qd6580.o
+ifeq ($(CONFIG_BLK_DEV_GAYLE),y)
+IDE_OBJS += gayle.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_UMC8672),y)
-IDE_OBJS += umc8672.o
+ifeq ($(CONFIG_BLK_DEV_HD),y)
+L_OBJS += hd.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_ALI14XX),y)
-IDE_OBJS += ali14xx.o
+ifeq ($(CONFIG_BLK_DEV_HPT34X),y)
+IDE_OBJS += hpt34x.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_PDC4030),y)
-IDE_OBJS += pdc4030.o
+ifeq ($(CONFIG_BLK_DEV_HPT366),y)
+IDE_OBJS += hpt366.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_TRM290),y)
-IDE_OBJS += trm290.o
+ifeq ($(CONFIG_BLK_DEV_HT6560B),y)
+IDE_OBJS += ht6560b.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_OPTI621),y)
-IDE_OBJS += opti621.o
+ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
+IDE_OBJS += ide-dma.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
+IDE_OBJS += ide-pci.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y)
+IDE_OBJS += ide-pmac.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y)
+IDE_OBJS += macide.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_NS87415),y)
 IDE_OBJS += ns87415.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_VIA82C586),y)
-IDE_OBJS += via82c586.o
+ifeq ($(CONFIG_BLK_DEV_OPTI621),y)
+IDE_OBJS += opti621.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_GAYLE),y)
-IDE_OBJS += gayle.o
+ifeq ($(CONFIG_BLK_DEV_PDC202XX),y)
+IDE_OBJS += pdc202xx.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_FALCON_IDE),y)
-IDE_OBJS += falconide.o
+ifeq ($(CONFIG_BLK_DEV_PDC4030),y)
+IDE_OBJS += pdc4030.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_MAC_IDE),y)
-IDE_OBJS += macide.o
+ifeq ($(CONFIG_BLK_DEV_PIIX),y)
+IDE_OBJS += piix.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_BUDDHA),y)
-IDE_OBJS += buddha.o
+ifeq ($(CONFIG_BLK_DEV_QD6580),y)
+IDE_OBJS += qd6580.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_CMD646),y)
-IDE_OBJS += cmd646.o
+ifeq ($(CONFIG_BLK_DEV_RZ1000),y)
+IDE_OBJS += rz1000.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_SL82C105),y)
-IDE_OBJS += sl82c105.o
+ifeq ($(CONFIG_BLK_DEV_SIS5513),y)
+IDE_OBJS += sis5513.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
-IDE_OBJS += alim15x3.o
+ifeq ($(CONFIG_BLK_DEV_SL82C105),y)
+IDE_OBJS += sl82c105.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_CY82C693),y)
-IDE_OBJS += cy82c693.o
+ifeq ($(CONFIG_BLK_DEV_TRM290),y)
+IDE_OBJS += trm290.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_PIIX),y)
-IDE_OBJS += piix.o
+ifeq ($(CONFIG_BLK_DEV_UMC8672),y)
+IDE_OBJS += umc8672.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_PDC202XX),y)
-IDE_OBJS += pdc202xx.o
+ifeq ($(CONFIG_BLK_DEV_VIA82C586),y)
+IDE_OBJS += via82c586.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_AEC6210),y)
-IDE_OBJS += aec6210.o
+ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y)
+IDE_OBJS += icside.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_HPT34X),y)
-IDE_OBJS += hpt34x.o
+ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y)
+IDE_OBJS += rapide.o
 endif
 
 ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
diff -u --recursive --new-file v2.3.12/linux/drivers/block/README.buddha linux/drivers/block/README.buddha
--- v2.3.12/linux/drivers/block/README.buddha	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/README.buddha	Mon Aug  9 12:32:28 1999
@@ -0,0 +1,210 @@
+
+The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by
+Geert Uytterhoeven based on the following specifications:
+
+------------------------------------------------------------------------
+
+Register map of the Buddha IDE controller and the
+Buddha-part of the Catweasel Zorro-II version
+
+The Autoconfiguration has been implemented just as Commodore
+described  in  their  manuals, no tricks have been used (for
+example leaving some address lines out of the equations...).
+If you want to configure the board yourself (for example let
+a  Linux  kernel  configure the card), look at the Commodore
+Docs.  Reading the nibbles should give this information:
+
+Vendor number: 4626 ($1212)
+product number: 0 (42 for Catweasel Z-II)
+Serial number: 0
+Rom-vector: $1000
+
+The  card  should be a Z-II board, size 64K, not for freemem
+list, Rom-Vektor is valid, no second Autoconfig-board on the
+same card, no space preferrence, supports "Shutup_forever".
+
+Setting  the  base address should be done in two steps, just
+as  the Amiga Kickstart does:  The lower nibble of the 8-Bit
+address is written to $4a, then the whole Byte is written to
+$48, while it doesn't matter how often you're writing to $4a
+as  long as $48 is not touched.  After $48 has been written,
+the  whole card disappears from $e8 and is mapped to the new
+addrress just written.  Make shure $4a is written befor $48,
+otherwise your chance is only 1:16 to find the board :-).
+
+The local memory-map is even active when mapped to $e8:
+
+$0-$7e		Autokonfig-space, see Z-II docs.
+
+$80-$7fd	reserved
+
+$7fe		Speed-select Register: Read & Write
+		(description see further down)
+
+$800-$8ff	IDE-Select 0 (Port 0, Register set 0)
+
+$900-$9ff	IDE-Select 1 (Port 0, Register set 1)
+
+$a00-$aff	IDE-Select 2 (Port 1, Register set 0)
+
+$b00-$bff	IDE-Select 3 (Port 1, Register set 1)
+
+$c00-$cff	IDE-Select 4 (Port 2, Register set 0,
+                          Catweasel only!)
+
+$d00-$dff	IDE-Select 5 (Port 3, Register set 1,
+			      Catweasel only!)
+
+$e00-$eff	local expansion port, on Catweasel Z-II the 
+		Catweasel registers are also mapped here.
+		Never touch, use multidisk.device!
+		
+$f00		read only, Byte-access: Bit 7 shows the 
+		level of the IRQ-line of IDE port 0. 
+
+$f01-$f3f	mirror of $f00
+
+$f40		read only, Byte-access: Bit 7 shows the 
+		level of the IRQ-line of IDE port 1. 
+
+$f41-$f7f	mirror of $f40
+
+$f80		read only, Byte-access: Bit 7 shows the 
+		level of the IRQ-line of IDE port 2. 
+		(Catweasel only!)
+
+$f81-$fbf	mirror of $f80
+
+$fc0		write-only: Writing any value to this
+		register enables IRQs to be passed from the 
+		IDE ports to the Zorro bus. This mechanism 
+		has been implemented to be compatible with 
+		harddisks that are either defective or have
+		a buggy firmware and pull the IRQ line up 
+		while starting up. If interrupts would 
+		always be passed to the bus, the computer 
+		might not start up. Once enabled, this flag 
+		can not be disabled again. The level of the 
+		flag can not be determined by software 
+		(what for? Write to me if it's necessary!).
+
+$fc1-$fff	mirror of $fc0
+
+$1000-$ffff	Buddha-Rom with offset $1000 in the rom
+		chip. The addresses $0 to $fff of the rom 
+		chip cannot be read. Rom is Byte-wide and
+		mapped to even addresses.
+
+The  IDE ports issue an INT2.  You can read the level of the
+IRQ-lines  of  the  IDE-ports by reading from the three (two
+for  Buddha-only)  registers  $f00, $f40 and $f80.  This way
+more  than one I/O request can be handled and you can easily
+determine  what  driver  has  to serve the INT2.  Buddha and
+Catweasel  expansion  boards  can issue an INT6.  A seperate
+memory  map  is available for the I/O module and the sysop's
+I/O module.
+
+The IDE ports are fed by the address lines A2 to A4, just as
+the  Amiga  1200  and  Amiga  4000  IDE ports are.  This way
+existing  drivers  can be easily ported to Buddha.  A move.l
+polls  two  words  out of the same address of IDE port since
+every  word  is  mirrored  once.  movem is not possible, but
+it's  not  necessary  either,  because  you can only speedup
+68000  systems  with  this  technique.   A 68020 system with
+fastmem is faster with move.l.
+
+If you're using the mirrored registers of the IDE-ports with
+A6=1,  the Buddha doesn't care about the speed that you have
+selected  in  the  speed  register (see further down).  With
+A6=1  (for example $840 for port 0, register set 0), a 780ns
+access  is being made.  These registers should be used for a
+command   access   to  the  harddisk/CD-Rom,  since  command
+accesses  are Byte-wide and have to be made slower according
+to the ATA-X3T9 manual.
+
+Now  for the speed-register:  The register is byte-wide, and
+only  the  upper  three  bits are used (Bits 7 to 5).  Bit 4
+must  always  be set to 1 to be compatible with later Buddha
+versions  (if  I'll  ever  update this one).  I presume that
+I'll  never use the lower four bits, but they have to be set
+to 1 by definition.
+  The  values in this table have to be shifted 5 bits to the
+left and or'd with $1f (this sets the lower 5 bits).
+
+All  the timings have in common:  Select and IOR/IOW rise at
+the  same  time.   IOR  and  IOW have a propagation delay of
+about  30ns  to  the clocks on the Zorro bus, that's why the
+values  are no multiple of 71.  One clock-cycle is 71ns long
+(exactly 70,5 at 14,18 Mhz on PAL systems).
+
+value 0 (Default after reset)
+
+497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles)
+(same timing as the Amiga 1200 does on it's IDE port without
+accelerator card)
+
+value 1
+
+639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles)
+
+value 2
+
+781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles)
+
+value 3
+
+355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
+
+value 4
+
+355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles)
+
+value 5
+
+355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles)
+
+value 6
+
+1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles)
+
+value 7
+
+355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
+
+When accessing IDE registers with A6=1 (for example $84x),
+the timing will always be mode 0 8-bit compatible, no matter
+what you have selected in the speed register:
+
+781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. 
+
+All  the  timings with a very short select-signal (the 355ns
+fast  accesses)  depend  on the accelerator card used in the
+system:  Sometimes two more clock cycles are inserted by the
+bus  interface,  making  the  whole access 497ns long.  This
+doesn't  affect  the  reliability  of the controller nor the
+performance  of  the  card,  since  this doesn't happen very
+often.
+
+All  the  timings  are  calculated  and  only  confirmed  by
+measurements  that allowed me to count the clock cycles.  If
+the  system  is clocked by an oscillator other than 28,37516
+Mhz  (for  example  the  NTSC-frequency  28,63636 Mhz), each
+clock  cycle is shortened to a bit less than 70ns (not worth
+mentioning).   You  could think of a small performance boost
+by  overclocking  the  system,  but  you would either need a
+multisync  monitor,  or  a  graphics card, and your internal
+diskdrive would go crazy, that's why you shouldn't tune your
+Amiga this way.
+
+Giving  you  the  possibility  to  write  software  that  is
+compatible  with both the Buddha and the Catweasel Z-II, The
+Buddha  acts  just  like  a  Catweasel  Z-II  with no device
+connected  to  the  third  IDE-port.   The IRQ-register $f80
+always  shows a "no IRQ here" on the Buddha, and accesses to
+the  third  IDE  port  are  going into data's Nirwana on the
+Buddha.
+
+			    Jens Schönfeld february 19th, 1997
+					updated may 27th, 1997
+			     eMail: sysop@nostlgic.tng.oche.de
+
diff -u --recursive --new-file v2.3.12/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.3.12/linux/drivers/block/acsi.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/acsi.c	Mon Aug  9 12:32:28 1999
@@ -253,17 +253,8 @@
 static char				*CurrentBuffer;
 
 
-#define SET_TIMER()							\
-	do {								\
-		del_timer( &acsi_timer );				\
-		acsi_timer.expires = jiffies + ACSI_TIMEOUT;		\
-		add_timer( &acsi_timer );				\
-	} while(0)
-
-#define CLEAR_TIMER()							\
-	do {								\
-		del_timer( &acsi_timer );				\
-	} while(0)
+#define SET_TIMER()	mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT)
+#define CLEAR_TIMER()	del_timer(&acsi_timer)
 
 static unsigned long	STramMask;
 #define STRAM_ADDR(a)	(((a) & STramMask) == 0)
@@ -425,8 +416,8 @@
 
 {
 	if (INT_LEVEL < 6) {
-		unsigned long maxjif;
-		for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); )
+		unsigned long maxjif = jiffies + timeout;
+		while (time_before(jiffies, maxjif))
 			if (!(mfp.par_dt_reg & 0x20)) return( 1 );
 	}
 	else {
@@ -442,8 +433,8 @@
 
 {
 	if (INT_LEVEL < 6) {
-		unsigned long maxjif;
-		for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); )
+		unsigned long maxjif = jiffies + timeout;
+		while (time_before(jiffies, maxjif))
 			if (mfp.par_dt_reg & 0x20) return( 1 );
 	}
 	else {
@@ -502,7 +493,7 @@
 #endif
 	
 	rwflag = rwflag ? 0x100 : 0;
-	paddr = VTOP( buffer );
+	paddr = virt_to_phys( buffer );
 
 	acsi_delay_end(COMMAND_DELAY);
 	DISABLE_IRQ();
@@ -610,7 +601,7 @@
 	if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 );
 	if (!acsi_wait_for_IRQ( 10 )) return( 0 );
 	acsi_getstatus();
-	dma_cache_maintenance( VTOP(buffer), 16, 0 );
+	dma_cache_maintenance( virt_to_phys(buffer), 16, 0 );
 	
 	return( 1 );
 }	
@@ -809,7 +800,7 @@
 		return;
 	}
 
-	dma_cache_maintenance( VTOP(CurrentBuffer), CurrentNSect*512, 0 );
+	dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 );
 	if (CurrentBuffer == acsi_buffer)
 		copy_from_acsibuffer();
 
@@ -1030,7 +1021,7 @@
 	 * consecutive buffers and thus can be done with a single command.
 	 */
 	buffer      = CURRENT->buffer;
-	pbuffer     = VTOP(buffer);
+	pbuffer     = virt_to_phys(buffer);
 	nsect       = CURRENT->current_nr_sectors;
 	CurrentNReq = 1;
 
@@ -1052,7 +1043,7 @@
 			unsigned long pendadr, pnewadr;
 			pendadr = pbuffer + nsect*512;
 			while( (bh = bh->b_reqnext) ) {
-				pnewadr = VTOP(bh->b_data);
+				pnewadr = virt_to_phys(bh->b_data);
 				if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break;
 				nsect += bh->b_size >> 9;
 				pendadr = pnewadr + bh->b_size;
@@ -1814,7 +1805,7 @@
 		unregister_blkdev( MAJOR_NR, "ad" );
 		return -ENOMEM;
 	}
-	phys_acsi_buffer = VTOP( acsi_buffer );
+	phys_acsi_buffer = virt_to_phys( acsi_buffer );
 	STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000;
 	
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
diff -u --recursive --new-file v2.3.12/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c
--- v2.3.12/linux/drivers/block/acsi_slm.c	Tue May 11 23:33:00 1999
+++ linux/drivers/block/acsi_slm.c	Mon Aug  9 12:32:28 1999
@@ -413,8 +413,8 @@
 
 	CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun );
 	cmd = slmprint_cmd;
-	paddr = VTOP( SLMBuffer );
-	dma_cache_maintenance( paddr, VTOP(BufferP)-paddr, 1 );
+	paddr = virt_to_phys( SLMBuffer );
+	dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 );
 	DISABLE_IRQ();
 
 	/* Low on A1 */
@@ -466,7 +466,7 @@
 	addr = get_dma_addr();
 	stat = acsi_getstatus();
 	SLMError = (stat < 0)             ? SLMSTAT_ACSITO :
-		       (addr < VTOP(BufferP)) ? SLMSTAT_NOTALL :
+		       (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL :
 									    stat;
 
 	dma_wd.dma_mode_status = 0x80;
diff -u --recursive --new-file v2.3.12/linux/drivers/block/aec6210.c linux/drivers/block/aec6210.c
--- v2.3.12/linux/drivers/block/aec6210.c	Wed May 26 16:55:40 1999
+++ linux/drivers/block/aec6210.c	Thu Aug  5 18:48:45 1999
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/block/aec6210.c	Version 0.01	Nov 17, 1998
+ * linux/drivers/block/aec6210.c		Version 0.01	Nov 17, 1998
  *
- * Copyright (C) 1998	Andre Hedrick (hedrick@astro.dyer.vanderbilt.edu)
+ * Copyright (C) 1998-99	Andre Hedrick
  *
  *  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
@@ -31,7 +31,6 @@
  *                 NO-Devices
  *                 40: 00 00 00 00 00 00 00 00 02 05 a6 00 00 02 00 02
  *                 50: ff ff ff ff 00 06 00 00 00 00 00 00 00 00 00 00
-
  */
 
 #include <linux/types.h>
@@ -54,10 +53,8 @@
 __initfunc(unsigned int pci_init_aec6210 (struct pci_dev *dev, const char *name))
 {
 	if (dev->rom_address) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-			dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n",
-			name, dev->rom_address);
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->rom_address);
 	}
 	return dev->irq;
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.3.12/linux/drivers/block/ataflop.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/ataflop.c	Mon Aug  9 12:32:28 1999
@@ -215,11 +215,10 @@
  * restored upon disk change by floppy_revalidate() if valid (as seen by
  * default_params[].blocks > 0 - a bit in unit[].flags might be used for this?)
  */
-static struct atari_disk_type default_params[FD_MAX_UNITS] = {
-	{ NULL,  0, 0, 0, 0},  };
+static struct atari_disk_type default_params[FD_MAX_UNITS];
 
 static int floppy_sizes[256];
-static int floppy_blocksizes[256] = { 0, };
+static int floppy_blocksizes[256];
 
 /* current info on each unit */
 static struct atari_floppy_struct {
@@ -331,26 +330,6 @@
 					 * will give up. */
 
 
-#define	START_MOTOR_OFF_TIMER(delay)				\
-    do {							\
-        motor_off_timer.expires = jiffies + (delay);		\
-        add_timer( &motor_off_timer );				\
-        MotorOffTrys = 0;					\
-	} while(0)
-
-#define	START_CHECK_CHANGE_TIMER(delay)				\
-    do {							\
-        timer_table[FLOPPY_TIMER].expires = jiffies + (delay);	\
-        timer_active |= (1 << FLOPPY_TIMER);			\
-	} while(0)
-
-#define	START_TIMEOUT()						\
-    mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT)
-
-#define	STOP_TIMEOUT()						\
-    del_timer(&timeout_timer)
-
-
 /*
  * The driver is trying to determine the correct media format
  * while Probing is set. fd_rwsec_done() clears it after a
@@ -420,6 +399,31 @@
 	{ NULL, NULL, 0, 0, fd_times_out };
 
 
+static inline void
+start_motor_off_timer(void)
+{
+	mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY);
+	MotorOffTrys = 0;
+}
+
+static inline void
+start_check_change_timer(void)
+{
+	timer_table[FLOPPY_TIMER].expires = jiffies + CHECK_CHANGE_DELAY;
+	timer_active |= (1 << FLOPPY_TIMER);
+}
+
+static inline void
+start_timeout(void)
+{
+	mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT);
+}
+
+static inline void
+stop_timeout(void)
+{
+	del_timer(&timeout_timer);
+}
 
 /* Select the side to use. */
 
@@ -497,19 +501,12 @@
 
 static void fd_motor_off_timer( unsigned long dummy )
 {
-/*	unsigned long flags; */
 	unsigned char status;
-	int		      delay;
 
-	del_timer( &motor_off_timer );
-	
 	if (SelectedDrive < 0)
 		/* no drive selected, needn't deselect anyone */
 		return;
 
-/*	save_flags(flags);
-	cli(); */
-	
 	if (stdma_islocked())
 		goto retry;
 
@@ -519,21 +516,18 @@
 		/* motor already turned off by FDC -> deselect drives */
 		MotorOn = 0;
 		fd_deselect();
-/*		restore_flags(flags); */
 		return;
 	}
 	/* not yet off, try again */
 
   retry:
-/*	restore_flags(flags); */
 	/* Test again later; if tested too often, it seems there is no disk
 	 * in the drive and the FDC will leave the motor on forever (or,
 	 * at least until a disk is inserted). So we'll test only twice
 	 * per second from then on...
 	 */
-	delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
-		        (++MotorOffTrys, HZ/20) : HZ/2;
-	START_MOTOR_OFF_TIMER( delay );
+	mod_timer(&motor_off_timer,
+		  jiffies + (MotorOffTrys++ < FD_MOTOR_OFF_MAXTRY ? HZ/20 : HZ/2));
 }
 
 
@@ -571,7 +565,7 @@
 	}
 	restore_flags(flags);
 
-	START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+	start_check_change_timer();
 }
 
  
@@ -603,8 +597,7 @@
 	unsigned char status;
 	void (*handler)( int );
 
-	handler = FloppyIRQHandler;
-	FloppyIRQHandler = NULL;
+	handler = xchg(&FloppyIRQHandler, NULL);
 
 	if (handler) {
 		nop();
@@ -805,7 +798,7 @@
 
 	NeedSeek = 1;
 	MotorOn = 1;
-	START_TIMEOUT();
+	start_timeout();
 	/* wait for IRQ */
 }
 
@@ -813,7 +806,7 @@
 static void fd_calibrate_done( int status )
 {
 	DPRINT(("fd_calibrate_done()\n"));
-	STOP_TIMEOUT();
+	stop_timeout();
     
 	/* set the correct speed now */
 	if (ATARIHW_PRESENT(FDCSPEED))
@@ -853,7 +846,7 @@
 
 	MotorOn = 1;
 	set_head_settle_flag();
-	START_TIMEOUT();
+	start_timeout();
 	/* wait for IRQ */
 }
 
@@ -861,7 +854,7 @@
 static void fd_seek_done( int status )
 {
 	DPRINT(("fd_seek_done()\n"));
-	STOP_TIMEOUT();
+	stop_timeout();
 	
 	/* set the correct speed */
 	if (ATARIHW_PRESENT(FDCSPEED))
@@ -900,7 +893,7 @@
 	DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' ));
 	if (ReqCmd == WRITE) {
 		if (ATARIHW_PRESENT(EXTD_DMA)) {
-			paddr = (unsigned long)VTOP(ReqData);
+			paddr = virt_to_phys(ReqData);
 		}
 		else {
 			copy_buffer( ReqData, DMABuffer );
@@ -913,7 +906,8 @@
 		if (read_track)
 			paddr = PhysTrackBuffer;
 		else
-			paddr = ATARIHW_PRESENT(EXTD_DMA) ? VTOP(ReqData) : PhysDMABuffer;
+			paddr = ATARIHW_PRESENT(EXTD_DMA) ? 
+				virt_to_phys(ReqData) : PhysDMABuffer;
 		rwflag = 0;
 	}
 
@@ -978,14 +972,12 @@
 		 * search for the first non-existent sector and need 1 sec to
 		 * recognise that it isn't present :-(
 		 */
-		del_timer (&readtrack_timer);
-		readtrack_timer.expires =
-		  jiffies + HZ/5 + (old_motoron ? 0 : HZ);
-		       /* 1 rot. + 5 rot.s if motor was off  */
 		MultReadInProgress = 1;
-		add_timer( &readtrack_timer );
+		mod_timer(&readtrack_timer,
+			  /* 1 rot. + 5 rot.s if motor was off  */
+			  jiffies + HZ/5 + (old_motoron ? 0 : HZ));
 	}
-	START_TIMEOUT();
+	start_timeout();
 }
 
     
@@ -996,8 +988,6 @@
 	save_flags(flags);  
 	cli();
 
-	del_timer( &readtrack_timer );
-
 	if (!MultReadInProgress) {
 		/* This prevents a race condition that could arise if the
 		 * interrupt is triggered while the calling of this timer
@@ -1045,8 +1035,7 @@
 		/* not yet finished, wait another tenth rotation */
 		restore_flags(flags);
 		DPRINT(("fd_readtrack_check(): not yet finished\n"));
-		readtrack_timer.expires = jiffies + HZ/5/10;
-		add_timer( &readtrack_timer );
+		mod_timer(&readtrack_timer, jiffies + HZ/5/10);
 	}
 }
 
@@ -1068,7 +1057,7 @@
 {
 	unsigned int track;
 
-	STOP_TIMEOUT();
+	stop_timeout();
 	
 	/* Correct the track if stretch != 0 */
 	if (SUDT->stretch) {
@@ -1150,7 +1139,7 @@
 		if (!read_track) {
 			void *addr;
 			addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;
-			dma_cache_maintenance( VTOP(addr), 512, 0 );
+			dma_cache_maintenance( virt_to_phys(addr), 512, 0 );
 			if (!ATARIHW_PRESENT( EXTD_DMA ))
 				copy_buffer (addr, ReqData);
 		} else {
@@ -1237,7 +1226,7 @@
 	dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag(); 
 
 	MotorOn = 1;
-	START_TIMEOUT();
+	start_timeout();
 	/* wait for interrupt */
 }
 
@@ -1246,7 +1235,7 @@
 {
 	DPRINT(("fd_writetrack_done()\n"));
 
-	STOP_TIMEOUT();
+	stop_timeout();
 
 	if (status & FDCSTAT_WPROT) {
 		printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );
@@ -1304,7 +1293,7 @@
 		SET_IRQ_HANDLER( finish_fdc_done );
 		FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK);
 		MotorOn = 1;
-		START_TIMEOUT();
+		start_timeout();
 		/* we must wait for the IRQ here, because the ST-DMA
 		   is released immediately afterwards and the interrupt
 		   may be delivered to the wrong driver. */
@@ -1317,19 +1306,18 @@
 	unsigned long flags;
 
 	DPRINT(("finish_fdc_done entered\n"));
-	STOP_TIMEOUT();
+	stop_timeout();
 	NeedSeek = 0;
 
 	if ((timer_active & (1 << FLOPPY_TIMER)) &&
-	    timer_table[FLOPPY_TIMER].expires < jiffies + 5)
+	    time_before(timer_table[FLOPPY_TIMER].expires, jiffies + 5))
 		/* If the check for a disk change is done too early after this
 		 * last seek command, the WP bit still reads wrong :-((
 		 */
 		timer_table[FLOPPY_TIMER].expires = jiffies + 5;
 	else
-		START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
-	del_timer( &motor_off_timer );
-	START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+		start_check_change_timer();
+	start_motor_off_timer();
 
 	save_flags(flags);
 	cli();
@@ -1828,10 +1816,10 @@
 	FDC_WRITE (FDCREG_TRACK, 0xff00);
 	FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 );
 
-	for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; time_before(jiffies, timeout); ) {
+	timeout = jiffies + 2*HZ+HZ/2;
+	while (time_before(jiffies, timeout))
 		if (!(mfp.par_dt_reg & 0x20))
 			break;
-	}
 
 	status = FDC_READ( FDCREG_STATUS );
 	ok = (status & FDCSTAT_TR00) != 0;
@@ -1892,9 +1880,9 @@
 	}
 	
 	if (cnt > 0) {
-		START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+		start_motor_off_timer();
 		if (cnt == 1) fd_select_drive( 0 );
-		START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+		start_check_change_timer();
 	}
 }
 
@@ -2045,8 +2033,8 @@
 		return -ENOMEM;
 	}
 	TrackBuffer = DMABuffer + 512;
-	PhysDMABuffer = (unsigned long) VTOP(DMABuffer);
-	PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer);
+	PhysDMABuffer = virt_to_phys(DMABuffer);
+	PhysTrackBuffer = virt_to_phys(TrackBuffer);
 	BufferDrive = BufferSide = BufferTrack = -1;
 
 	for (i = 0; i < FD_MAX_UNITS; i++) {
diff -u --recursive --new-file v2.3.12/linux/drivers/block/cmd646.c linux/drivers/block/cmd646.c
--- v2.3.12/linux/drivers/block/cmd646.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/cmd646.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: cmd646.c,v 1.14 1999/07/03 08:56:09 davem Exp $
+/* $Id: cmd646.c,v 1.15 1999/07/23 01:48:37 davem Exp $
  * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Note, this driver is not used at all on other systems because
  *           there the "BIOS" has done all of the following already.
diff -u --recursive --new-file v2.3.12/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.12/linux/drivers/block/cpqarray.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/cpqarray.c	Thu Aug  5 15:04:42 1999
@@ -631,7 +631,7 @@
 	irq = pdev->irq;
 
 	for(i=0; i<6; i++)
-		addr[i] = pdev->base_address[i];
+		addr[i] = pdev->resource[i].flags;
 
 	(void) pcibios_read_config_word(bus, device_fn,
 					PCI_COMMAND,&command);
@@ -665,7 +665,7 @@
 	 */
 	for(i=0; i<6; i++)
 		if (!(addr[i] & 0x1)) {
-			c->paddr = addr[i];
+			c->paddr = pdev->resource[i].start;
 			break;
 		}
 	c->vaddr = remap_pci_mem(c->paddr, 128);
diff -u --recursive --new-file v2.3.12/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.12/linux/drivers/block/floppy.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/floppy.c	Fri Aug  6 11:43:09 1999
@@ -330,7 +330,6 @@
 
 #define SEL_DLY (2*HZ/100)
 
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 /*
  * this struct defines the different floppy drive types.
  */
@@ -4063,10 +4062,13 @@
 	{ "L40SX", 0, &print_unex, 0, 0 } };
 
 #define FLOPPY_SETUP
-void __init floppy_setup(char *str, int *ints)
+void __init floppy_setup(char *str)
 {
 	int i;
 	int param;
+	int ints[11];
+
+	str = get_options(str,ARRAY_SIZE(ints),ints);
 	if (str) {
 		for (i=0; i< ARRAY_SIZE(config_params); i++){
 			if (strcmp(str,config_params[i].name) == 0){
@@ -4358,8 +4360,6 @@
 
 #ifdef MODULE
 
-extern char *get_options(char *str, int *ints);
-
 char *floppy=NULL;
 
 static void __init parse_floppy_cfg_string(char *cfg)
@@ -4374,18 +4374,17 @@
 			cfg++;
 		}
 		if(*ptr)
-			floppy_setup(get_options(ptr,ints),ints);
+			floppy_setup(ptr);
 	}
 }
 
-static void __init mod_setup(char *pattern, void (*setup)(char *, int *))
+static void __init mod_setup(char *pattern, void (*setup)(char *))
 {
 	unsigned long i;
 	char c;
 	int j;
 	int match;
 	char buffer[100];
-	int ints[11];
 	int length = strlen(pattern)+1;
 
 	match=0;
@@ -4400,7 +4399,7 @@
 			if (!c || c == ' ' || c == '\t'){
 				if (j){
 					buffer[j] = '\0';
-					setup(get_options(buffer,ints),ints);
+					setup(buffer);
 				}
 				j=0;
 			} else
diff -u --recursive --new-file v2.3.12/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.3.12/linux/drivers/block/genhd.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/genhd.c	Fri Aug  6 10:49:54 1999
@@ -85,6 +85,10 @@
 	 * This requires special handling here.
 	 */
 	switch (hd->major) {
+		case IDE9_MAJOR:
+			unit += 2;
+		case IDE8_MAJOR:
+			unit += 2;
 		case IDE7_MAJOR:
 			unit += 2;
 		case IDE6_MAJOR:
@@ -1383,7 +1387,7 @@
 		resetup_one_dev(dev, drive);
 }
 
-void __init device_setup(void)
+static int __init device_setup(void)
 {
 	extern void console_map_init(void);
 	extern void cpqarray_init(void);
@@ -1441,7 +1445,10 @@
 #ifdef CONFIG_MD_BOOT
         md_setup_drive();
 #endif
+	return 0;
 }
+
+__initcall(device_setup);
 
 #ifdef CONFIG_PROC_FS
 int get_partition_list(char * page)
diff -u --recursive --new-file v2.3.12/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v2.3.12/linux/drivers/block/hd.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/hd.c	Mon Aug  2 11:12:00 1999
@@ -21,6 +21,7 @@
  *  Removed 99% of above. Use Mark's ide driver for those options.
  *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
  *
+ *  Modified 1995 Russell King for ARM processor.
  */
   
 /* Uncomment the following if you want verbose error reports. */
@@ -49,6 +50,12 @@
 #define MAJOR_NR HD_MAJOR
 #include <linux/blk.h>
 
+#ifdef __arm__
+#undef  HD_IRQ
+#include <asm/irq.h>
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
 static int revalidate_hddisk(kdev_t, int);
 
 #define	HD_DELAY	0
@@ -64,14 +71,14 @@
 static void recal_intr(void);
 static void bad_rw_intr(void);
 
-static char recalibrate[MAX_HD] = { 0, };
-static char special_op[MAX_HD] = { 0, };
-static int access_count[MAX_HD] = {0, };
-static char busy[MAX_HD] = {0, };
+static char recalibrate[MAX_HD];
+static char special_op[MAX_HD];
+static int access_count[MAX_HD];
+static char busy[MAX_HD];
 static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
 
-static int reset = 0;
-static int hd_error = 0;
+static int reset;
+static int hd_error;
 
 #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
 
@@ -86,13 +93,14 @@
 static struct hd_i_struct hd_info[] = { HD_TYPE };
 static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
 #else
-static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
-static int NR_HD = 0;
+static struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
 #endif
 
-static struct hd_struct hd[MAX_HD<<6]={{0,0},};
-static int hd_sizes[MAX_HD<<6] = {0, };
-static int hd_blocksizes[MAX_HD<<6] = {0, };
+static struct hd_struct hd[MAX_HD<<6];
+static int hd_sizes[MAX_HD<<6];
+static int hd_blocksizes[MAX_HD<<6];
+static int hd_hardsectsizes[MAX_HD<<6];
 
 #if (HD_DELAY > 0)
 unsigned long last_req;
@@ -611,7 +619,7 @@
 					(long *) arg);
 
 		case BLKRRPART: /* Re-read partition tables */
-			if (!capable(CAP_SYS_ADMIN)) 
+			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			return revalidate_hddisk(inode->i_rdev, 1);
 
@@ -746,6 +754,17 @@
 		}
 	}
 #endif /* __i386__ */
+#ifdef __arm__
+	if (!NR_HD) {
+		/* We don't know anything about the drive.  This means
+		 * that you *MUST* specify the drive parameters to the
+		 * kernel yourself.
+		 */
+		printk("hd: no drives specified - use hd=cyl,head,sectors"
+			" on kernel command line\n");
+	}
+#endif
+
 	for (drive=0 ; drive < NR_HD ; drive++) {
 		hd[drive<<6].nr_sects = hd_info[drive].head *
 			hd_info[drive].sect * hd_info[drive].cyl;
@@ -764,9 +783,12 @@
 	}
 	hd_gendisk.nr_real = NR_HD;
 
-	for(drive=0; drive < (MAX_HD << 6); drive++)
+	for(drive=0; drive < (MAX_HD << 6); drive++) {
 		hd_blocksizes[drive] = 1024;
+		hd_hardsectsizes[drive] = 512;
+	}
 	blksize_size[MAJOR_NR] = hd_blocksizes;
+	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
 }
 
 static struct file_operations hd_fops = {
diff -u --recursive --new-file v2.3.12/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c
--- v2.3.12/linux/drivers/block/hpt34x.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/hpt34x.c	Thu Aug  5 18:48:45 1999
@@ -1,8 +1,7 @@
 /*
- * linux/drivers/block/hpt34x.c		Version 0.24	July 3, 1999
+ * linux/drivers/block/hpt34x.c		Version 0.25	July 11, 1999
  *
  * Copyright (C) 1998-99	Andre Hedrick
- *					(hedrick@astro.dyer.vanderbilt.edu)
  *
  * 00:12.0 Unknown mass storage controller:
  * Triones Technologies, Inc.
@@ -118,9 +117,14 @@
 		return ((int) ide_dma_off_quietly);
 #endif /* HPT343_DISABLE_ALL_DMAING */
 
-	if (id->dma_ultra & 0x0004) {
+	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 &= ~0x0F00;
+			drive->id->dma_ultra &= ~0xFF00;
 			drive->id->dma_ultra |= 0x0404;
 			drive->id->dma_mword &= ~0x0F00;
 			drive->id->dma_1word &= ~0x0F00;
@@ -128,7 +132,7 @@
 		speed = XFER_UDMA_2;
 	} else if (id->dma_ultra & 0x0002) {
 		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0x0F00;
+			drive->id->dma_ultra &= ~0xFF00;
 			drive->id->dma_ultra |= 0x0202;
 			drive->id->dma_mword &= ~0x0F00;
 			drive->id->dma_1word &= ~0x0F00;
@@ -136,7 +140,7 @@
 		speed = XFER_UDMA_1;
 	} else if (id->dma_ultra & 0x0001) {
 		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0x0F00;
+			drive->id->dma_ultra &= ~0xFF00;
 			drive->id->dma_ultra |= 0x0101;
 			drive->id->dma_mword &= ~0x0F00;
 			drive->id->dma_1word &= ~0x0F00;
@@ -190,7 +194,8 @@
 
 	(void) hpt34x_tune_chipset(drive, speed);
 
-	return ((int)	((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
+			((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);
@@ -337,47 +342,10 @@
 
 __initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name))
 {
-	int i;
 	unsigned short cmd;
-	unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
-#if 0
-	unsigned char misc10 = inb(hpt34xIoBase + 0x0010);
-	unsigned char misc11 = inb(hpt34xIoBase + 0x0011);
-#endif
 
 	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-
-	dev->base_address[0] = (hpt34xIoBase + 0x20);
-	dev->base_address[1] = (hpt34xIoBase + 0x34);
-	dev->base_address[2] = (hpt34xIoBase + 0x28);
-	dev->base_address[3] = (hpt34xIoBase + 0x3c);
-
-	for(i=0; i<4; i++)
-		dev->base_address[i] |= 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->base_address[0]);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]);
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-#if 0
-	outb(misc10|0x78, (hpt34xIoBase + 0x0010));
-	outb(misc11, (hpt34xIoBase + 0x0011));
-#endif
-
-#ifdef DEBUG
-	printk("%s: 0x%02x 0x%02x\n",
-		(pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name,
-		inb(hpt34xIoBase + 0x0010),
-		inb(hpt34xIoBase + 0x0011));
-#endif
-
 	if (cmd & PCI_COMMAND_MEMORY) {
 		if (dev->rom_address) {
 			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
@@ -385,6 +353,25 @@
 		}
 		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);
 	}
 	return dev->irq;
diff -u --recursive --new-file v2.3.12/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c
--- v2.3.12/linux/drivers/block/hpt366.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/hpt366.c	Fri Aug  6 11:16:54 1999
@@ -0,0 +1,492 @@
+/*
+ * linux/drivers/block/hpt366.c		Version 0.11	August 04, 1999
+ *
+ * Copyright (C) 1999			Andre Hedrick
+ *
+ * drive_number
+ *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+const char *bad_ata66_4[] = {
+	"WDC AC310200R",
+	"QUANTUM FIREBALLP KA13.6",
+	NULL
+};
+
+const char *bad_ata66_3[] = {
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata33[] = {
+	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+	"Maxtor 90510D4",
+	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+	NULL
+};
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	unsigned int	chipset_settings;
+};
+
+struct chipset_bus_clock_list_entry forty_base [] = {
+
+	{	XFER_UDMA_4	,	0x900fd943	},
+	{	XFER_UDMA_3	,	0x900ad943	},
+	{	XFER_UDMA_2	,	0x900bd943	},
+	{	XFER_UDMA_1	,	0x9008d943	},
+	{	XFER_UDMA_0	,	0x9008d943	},
+
+	{	XFER_MW_DMA_2	,	0xa008d943	},
+	{	XFER_MW_DMA_1	,	0xa010d955	},
+	{	XFER_MW_DMA_0	,	0xa010d9fc	},
+
+	{	XFER_PIO_4	,	0xc008d963	},
+	{	XFER_PIO_3	,	0xc010d974	},
+	{	XFER_PIO_2	,	0xc010d997	},
+	{	XFER_PIO_1	,	0xc010d9c7	},
+	{	XFER_PIO_0	,	0xc018d9d9	},
+	{	0		,	0x0120d9d9	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base [] = {
+
+	{	XFER_UDMA_4	,	0x90c9a731	},
+	{	XFER_UDMA_3	,	0x90cfa731	},
+	{	XFER_UDMA_2	,	0x90caa731	},
+	{	XFER_UDMA_1	,	0x90cba731	},
+	{	XFER_UDMA_0	,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2	,	0xa0c8a731	},
+	{	XFER_MW_DMA_1	,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0	,	0xa0c8a797	},
+
+	{	XFER_PIO_4	,	0xc0c8a731	},
+	{	XFER_PIO_3	,	0xc0c8a742	},
+	{	XFER_PIO_2	,	0xc0d0a753	},
+	{	XFER_PIO_1	,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0	,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0		,	0x0120a7a7	}
+};
+
+struct chipset_bus_clock_list_entry twenty_five_base [] = {
+
+	{	XFER_UDMA_4	,	0x90c98521	},
+	{	XFER_UDMA_3	,	0x90cf8521	},
+	{	XFER_UDMA_2	,	0x90cf8521	},
+	{	XFER_UDMA_1	,	0x90cb8521	},
+	{	XFER_UDMA_0	,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2	,	0xa0ca8521	},
+	{	XFER_MW_DMA_1	,	0xa0ca8532	},
+	{	XFER_MW_DMA_0	,	0xa0ca8575	},
+
+	{	XFER_PIO_4	,	0xc0ca8521	},
+	{	XFER_PIO_3	,	0xc0ca8532	},
+	{	XFER_PIO_2	,	0xc0ca8542	},
+	{	XFER_PIO_1	,	0xc0d08572	},
+	{	XFER_PIO_0	,	0xc0d08585	},
+	{	0		,	0x01208585	}
+};
+
+#define HPT366_DEBUG_DRIVE_INFO		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);
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	while (*list) {
+		if (!strcmp(*list++,id->model)) {
+#ifdef DEBUG
+			printk("%s: Broken ASIC, BackSpeeding (U)DMA for %s\n", drive->name, id->model);
+#endif /* DEBUG */
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed)
+			return chipset_table->chipset_settings;
+	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;
+	unsigned int reg1	= 0;
+	unsigned int reg2	= 0;
+
+	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:
+			reg2 = pci_bus_clock_list(speed, forty_base);
+			break;
+		case 0x85:
+			reg2 = pci_bus_clock_list(speed, twenty_five_base);
+			break;
+		case 0xa7:
+		default:
+			reg2 = pci_bus_clock_list(speed, thirty_three_base);
+			break;
+	}
+
+	if (drive->id->dword_io & 1)
+		reg2 |= 0x80000000;
+	else
+		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),
+		drive_number, reg1, reg2, err);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+	return(err);
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte speed		= 0x00;
+
+	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;
+		}
+		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 {
+		return ((int) ide_dma_off_quietly);
+	}
+
+	(void) hpt366_tune_chipset(drive, speed);
+
+	return ((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);
+}
+
+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;
+
+	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0) {
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	} else {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 :
+			   (drive->id->tPIO & 2) ? 0x02 :
+			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+	switch(timing) {
+		case 4: speed = XFER_PIO_4;break;
+		case 3: speed = XFER_PIO_3;break;
+		case 2: speed = XFER_PIO_2;break;
+		case 1: speed = XFER_PIO_1;break;
+		default:
+			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+			break;
+	}
+	(void) hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt366_tune_drive (ide_drive_t *drive, byte pio)
+{
+	byte speed;
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4;break;
+		case 3:		speed = XFER_PIO_3;break;
+		case 2:		speed = XFER_PIO_2;break;
+		case 1:		speed = XFER_PIO_1;break;
+		default:	speed = XFER_PIO_0;break;
+	}
+	(void) hpt366_tune_chipset(drive, speed);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_dma_action_t dma_func = ide_dma_on;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, 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 */
+				dma_func = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive);
+				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;
+			}
+			/* Consult the list of known "good" drives */
+			dma_func = config_chipset_for_dma(drive);
+			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:
+
+		config_chipset_for_pio(drive);
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ *
+ * This is specific to the HPT343 UDMA bios-less chipset
+ * and HPT345 UDMA bios chipset (stamped HPT363)
+ * by HighPoint|Triones Technologies, Inc.
+ */
+
+int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	byte reg50h = 0, reg52h = 0;
+
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+#if 0
+		case ide_dma_lostirq:
+			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
+			printk("%s: (ide_dma_lostirq) reg52h=0x%02x\n", drive->name, reg52h);
+			break;
+		case ide_dma_timeout:
+			(void) ide_dmaproc(ide_dma_off_quietly, drive);
+			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
+			printk("%s: (ide_dma_timeout) reg52h=0x%02x\n", drive->name, reg52h);
+			if (reg52h & 0x04) {
+				pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
+				pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0xff);
+				pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h);
+			}
+			pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
+			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
+			printk("%s: (ide_dma_timeout) reg50h=0x%02x reg52h=0x%02x :: again\n", drive->name, reg50h, reg52h);
+			(void) ide_dmaproc(ide_dma_on, drive);
+			if (reg52h & 0x04)
+				(void) ide_dmaproc(ide_dma_off, drive);
+			return 1;
+#endif
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+
+__initfunc(unsigned int pci_init_hpt366 (struct pci_dev *dev, const char *name))
+{
+	byte ata66 = 0;
+
+	pci_read_config_byte(dev, 0x5a, &ata66);
+	if (dev->rom_address)
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | 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));
+	return dev->irq;
+}
+
+__initfunc(void ide_init_hpt366 (ide_hwif_t *hwif))
+{
+	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;
+	}
+}
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.3.12/linux/drivers/block/ide-cd.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/block/ide-cd.c	Mon Aug  9 12:34:22 1999
@@ -2,7 +2,7 @@
  * linux/drivers/block/ide-cd.c
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
  * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998, 1999 Jens Axboe
+ * Copyright (C) 1998, 1999 Jens Axboe <axboe@image.dk>
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
@@ -243,11 +243,23 @@
  *                         Useful when using ide-cd in conjunction with
  *                         ide-scsi. TODO: non-modular way of doing the
  *                         same.
+ *
+ * 4.54  Aug 5, 1999	- Support for MMC2 class commands through the generic
+ *			  packet interface to cdrom.c.
+ *			- Unified audio ioctl support, most of it.
+ *			- cleaned up various deprecated verify_area().
+ *			- Added ide_cdrom_packet() as the interface for
+ *			  the Uniform generic_packet().
+ *			- bunch of other stuff, will fill in logs later.
+ *			- report 1 slot for non-changers, like the other
+ *			  cd-rom drivers. don't report select disc for
+ *			  non-changers as well.
+ *			- mask out audio playing, if the device can't do it.
  *                         
  *
  *************************************************************************/
-
-#define IDECD_VERSION "4.53"
+ 
+#define IDECD_VERSION "4.54"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -517,8 +529,8 @@
 				int *stat_ret)
 {
 	struct request *rq = HWGROUP(drive)->rq;
-	int stat, err, sense_key, cmd;
-
+	int stat, cmd, err, sense_key;
+	
 	/* Check for errors. */
 	stat = GET_STAT();
 	*stat_ret = stat;
@@ -526,8 +538,8 @@
 	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
-	/* Got an error. */
-	err = IN_BYTE (IDE_ERROR_REG);
+	/* Get the IDE error register. */
+	err = GET_ERR();
 	sense_key = err >> 4;
 
 	if (rq == NULL)
@@ -1170,8 +1182,6 @@
 cdrom_lockdoor (ide_drive_t *drive, int lockflag,
 		struct atapi_request_sense *reqbuf);
 
-
-
 /* Interrupt routine for packet command completion. */
 static void cdrom_pc_intr (ide_drive_t *drive)
 {
@@ -1385,14 +1395,15 @@
 		if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && drive->usage &&
 		    (pc->c[0] != REQUEST_SENSE &&
 		     pc->c[0] != ALLOW_MEDIUM_REMOVAL &&
-		     pc->c[0] != START_STOP)) {
+		     pc->c[0] != START_STOP &&
+		     pc->c[0] != MODE_SENSE_10 &&
+		     pc->c[0] != MODE_SELECT_10)) {
 			(void) cdrom_lockdoor (drive, 1, NULL);
 		}
 		return 0;
 	}
 }
 
-
 /****************************************************************************
  * cdrom driver request routine.
  */
@@ -1518,7 +1529,7 @@
 	struct atapi_request_sense my_reqbuf;
 	int stat;
 	struct packet_command pc;
-
+	
 	if (reqbuf == NULL)
 		reqbuf = &my_reqbuf;
 
@@ -1564,45 +1575,18 @@
 {
 	struct packet_command pc;
 
-	if (CDROM_CONFIG_FLAGS (drive)->no_eject==1 && ejectflag==0)
+	if (CDROM_CONFIG_FLAGS (drive)->no_eject && !ejectflag)
 		return -EDRIVE_CANT_DO_THIS;
+	
+	/* reload fails on some drives, if the tray is locked */
+	if (CDROM_STATE_FLAGS (drive)->door_locked && ejectflag)
+		return 0;
 
 	memset (&pc, 0, sizeof (pc));
 	pc.sense_data = reqbuf;
 
 	pc.c[0] = START_STOP;
-	pc.c[4] = 2 + (ejectflag != 0);
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_pause (ide_drive_t *drive, int pauseflag,
-	     struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.c[0] = SCMD_PAUSE_RESUME;
-	pc.c[8] = !pauseflag;
-	return cdrom_queue_packet_command (drive, &pc);
-}
-
-
-static int
-cdrom_startstop (ide_drive_t *drive, int startflag,
-		 struct atapi_request_sense *reqbuf)
-{
-	struct packet_command pc;
-
-	memset (&pc, 0, sizeof (pc));
-	pc.sense_data = reqbuf;
-
-	pc.c[0] = START_STOP;
-	pc.c[1] = 1;
-	pc.c[4] = startflag;
+	pc.c[4] = 0x02 + (ejectflag != 0);
 	return cdrom_queue_packet_command (drive, &pc);
 }
 
@@ -1611,8 +1595,8 @@
 		     struct atapi_request_sense *reqbuf)
 {
 	struct {
-		unsigned lba;
-		unsigned blocklen;
+		__u32 lba;
+		__u32 blocklen;
 	} capbuf;
 
 	int stat;
@@ -1892,7 +1876,7 @@
 cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end,
 		      struct atapi_request_sense *reqbuf)
 {
-	int i, stat;
+	int i, stat = 0;
 	struct atapi_request_sense my_reqbuf;
 
 	if (reqbuf == NULL)
@@ -2048,7 +2032,6 @@
 	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
@@ -2090,6 +2073,24 @@
 		 NULL);
 }
 
+/* the generic packet interface to cdrom.c */
+static int ide_cdrom_packet(struct cdrom_device_info *cdi,
+			    struct cdrom_generic_command *cgc)
+{
+	struct packet_command pc;
+	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+
+	/* here we queue the commands from the uniform CD-ROM
+	   layer. the packet must be complete, as we do not
+	   touch it at all. */
+	memset(&pc, 0, sizeof(pc));
+	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;
+}
+
 
 static
 int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
@@ -2168,19 +2169,16 @@
 
 		toc = info->toc;
 
-		stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra));
-		if (stat) return stat;
-
-		copy_from_user (&ra, (void *)arg, sizeof (ra));
+		if (copy_from_user(&ra, (void *)arg, sizeof (ra)))
+			return -EFAULT;
 
 		if (ra.nframes < 0 || ra.nframes > toc->capacity)
 			return -EINVAL;
 		else if (ra.nframes == 0)
 			return 0;
 
-		stat = verify_area (VERIFY_WRITE, (char *)ra.buf,
-				    ra.nframes * CD_FRAMESIZE_RAW);
-		if (stat) return stat;
+		if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes * CD_FRAMESIZE_RAW))
+			return -EFAULT;
 
 		if (ra.addr_format == CDROM_MSF)
 			lba = msf_to_lba (ra.addr.msf.minute,
@@ -2208,8 +2206,7 @@
 				 buf, this_nblocks * CD_FRAMESIZE_RAW, NULL);
 			if (stat) break;
 
-			copy_to_user (ra.buf, buf,
-				     this_nblocks * CD_FRAMESIZE_RAW);
+			__copy_to_user(ra.buf, buf,this_nblocks * CD_FRAMESIZE_RAW);
 			ra.buf += this_nblocks * CD_FRAMESIZE_RAW;
 			ra.nframes -= this_nblocks;
 			lba += this_nblocks;
@@ -2224,11 +2221,8 @@
  		char buffer[16];
  		int stat;
  
- 		stat = verify_area (VERIFY_READ, (void *) arg,
- 				    sizeof (char));
- 		if (stat) return stat;
- 
- 		copy_from_user (&spindown, (void *) arg, sizeof(char));
+ 		if (copy_from_user(&spindown, (void *) arg, sizeof(char)))
+			return -EFAULT;
  
  		stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer,
  					 sizeof (buffer), NULL);
@@ -2245,17 +2239,14 @@
  		char buffer[16];
  		int stat;
  
- 		stat = verify_area (VERIFY_WRITE, (void *) arg,
-                                    sizeof (char));
- 		if (stat) return stat;
- 
  		stat = cdrom_mode_sense (drive, PAGE_CDROM, 0, buffer,
                                          sizeof (buffer), NULL);
  		if (stat) return stat;
  
  		spindown = buffer[11] & 0x0f;
  
- 		copy_to_user ((void *) arg, &spindown, sizeof (char));
+		if (copy_to_user((void *) arg, &spindown, sizeof (char)))
+			return -EFAULT;
  
  		return 0;
  	}
@@ -2268,14 +2259,14 @@
 
 		memset (&pc, 0, sizeof (pc));
 
-		stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c));
-		if (stat) return stat;
-		copy_from_user (&pc.c, (void *) arg, sizeof (pc.c));
+		if (copy_from_user(&pc.c, (void *) arg, sizeof (pc.c)))
+			return -EFAULT;
+		
 		arg += sizeof (pc.c);
 
-		stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len));
-		if (stat) return stat;
-		copy_from_user (&len, (void *) arg , sizeof (len));
+		if (copy_from_user (&len, (void *) arg , sizeof (len)))
+			return -EFAULT;
+
 		arg += sizeof (len);
 
 		lena = len;
@@ -2438,70 +2429,6 @@
 		return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
 	}
 
-	case CDROMVOLCTRL: {
-		struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg;
-		char buffer[24], mask[24];
-		int stat;
-
-		stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer,
-					 sizeof (buffer), NULL);
-		if (stat) return stat;
-		stat = cdrom_mode_sense (drive, PAGE_AUDIO, 1, mask,
-					 sizeof (buffer), NULL);
-		if (stat) return stat;
-
-		buffer[1] = buffer[2] = 0;
-
-		buffer[17] = volctrl->channel0 & mask[17];
-		buffer[19] = volctrl->channel1 & mask[19];
-		buffer[21] = volctrl->channel2 & mask[21];
-		buffer[23] = volctrl->channel3 & mask[23];
-
-		return cdrom_mode_select (drive, PAGE_AUDIO, buffer,
-					  sizeof (buffer), NULL);
-	}
-
-	case CDROMVOLREAD: {
-		struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg;
-		char buffer[24];
-		int stat;
-
-		stat = cdrom_mode_sense (drive, PAGE_AUDIO, 0, buffer,
-					 sizeof (buffer), NULL);
-		if (stat) return stat;
-
-		volctrl->channel0 = buffer[17];
-		volctrl->channel1 = buffer[19];
-		volctrl->channel2 = buffer[21];
-		volctrl->channel3 = buffer[23];
-
-		return 0;
-	}
-
-	case CDROMSTART:
-		return cdrom_startstop (drive, 1, NULL);
-
-	case CDROMSTOP: {
-#ifdef IHAVEADOLPHIN
-               /*  Certain Drives require this.  Most don't
-                   and will produce errors upon CDROMSTOP
-                   pit says the Dolphin needs this.  If you
-                   own a dolphin, just define IHAVEADOLPHIN somewhere */
-                int stat;
-                stat = cdrom_startstop (drive, 0, NULL);
-                if (stat) return stat;
-                return cdrom_eject (drive, 1, NULL);
-#endif /* end of IHAVEADOLPHIN  */
-               return cdrom_startstop (drive, 0, NULL);
-	}
-
-	case CDROMPAUSE:
-		return cdrom_pause (drive, 1, NULL);
-
-	case CDROMRESUME:
-		return cdrom_pause (drive, 0, NULL);
-
-
 	default:
 		return -EINVAL;
 	}
@@ -2534,7 +2461,6 @@
 	return cdrom_eject (drive, !position, NULL);
 }
 
-
 static
 int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
 {
@@ -2835,9 +2761,11 @@
 	ide_cdrom_dev_ioctl,   /* dev_ioctl */
 	CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED
 	| CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN
-	| CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET 
-	| CDC_IOCTLS | CDC_DRIVE_STATUS,  /* capability */
-	0 /* n_minors */
+	| CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS
+	| CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD
+	| CDC_DVD_R| CDC_DVD_RAM | CDC_GENERIC_PACKET, /* capability */
+	0, /* n_minors */
+	ide_cdrom_packet
 };
 
 static int ide_cdrom_register (ide_drive_t *drive, int nslots)
@@ -2853,6 +2781,25 @@
 	*(int *)&devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
+	
+	/* set capability mask to match the probe. */
+	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
+		devinfo->mask |= CDC_CD_R;
+	if (!CDROM_CONFIG_FLAGS (drive)->cd_rw)
+		devinfo->mask |= CDC_CD_RW;
+	if (!CDROM_CONFIG_FLAGS (drive)->dvd)
+		devinfo->mask |= CDC_DVD;
+	if (!CDROM_CONFIG_FLAGS (drive)->dvd_r)
+		devinfo->mask |= CDC_DVD_R;
+	if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram)
+		devinfo->mask |= CDC_DVD_RAM;
+	if (!CDROM_CONFIG_FLAGS (drive)->is_changer)
+		devinfo->mask |= CDC_SELECT_DISC;
+	if (!CDROM_CONFIG_FLAGS (drive)->audio_play)
+		devinfo->mask |= CDC_PLAY_AUDIO;
+	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
+		devinfo->mask |= CDC_CLOSE_TRAY;
+		
 	return register_cdrom (devinfo);
 }
 
@@ -2860,7 +2807,7 @@
 static
 int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 {
-	int stat, nslots = 0, attempts = 3;
+	int stat, nslots = 1, attempts = 3;
  	struct {
 		char pad[8];
 		struct atapi_capabilities_page cap;
@@ -2891,7 +2838,11 @@
 	if (buf.cap.dvd_ram_write)
 		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
 	if (buf.cap.dvd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_rw = 1;
+		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
+	if (buf.cap.audio_play)
+		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+	if (buf.cap.mechtype == 0)
+		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
 
 #if ! STANDARD_ATAPI
 	if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) {
@@ -2931,10 +2882,10 @@
         	drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed,
 		(CDROM_CONFIG_FLAGS (drive)->dvd) ? "DVD-ROM" : "CD-ROM");
 
-	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_rw)
+	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
         	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-RAM" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_rw)? "/RW" : "");
+        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "AM" : "");
 
         if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
         	printk (" CD%s%s", 
@@ -3060,9 +3011,11 @@
 	CDROM_CONFIG_FLAGS (drive)->test_write = 0;
 	CDROM_CONFIG_FLAGS (drive)->dvd = 0;
 	CDROM_CONFIG_FLAGS (drive)->dvd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_rw = 0;
+	CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0;
 	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
 	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
+	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
+	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
 	
 	/* limit transfer size per interrupt. */
 	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
@@ -3195,7 +3148,6 @@
 		(MKDEV (HWIF (drive)->major,
 			(drive->select.b.unit)<<PARTN_BITS));
 }
-
 
 static
 int ide_cdrom_cleanup(ide_drive_t *drive)
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.3.12/linux/drivers/block/ide-cd.h	Tue Jun 22 14:41:40 1999
+++ linux/drivers/block/ide-cd.h	Mon Aug  9 12:42:03 1999
@@ -85,21 +85,25 @@
 #define MECHANISM_STATUS        0xbd
 #define READ_CD                 0xbe
 
-/* DVD Opcodes */
-#define DVD_GET_PERFORMANCE	0xac
-
+/* MMC2/MTFuji Opcodes */
+#define BLANK			0xa1
+#define CLOSE_TRACK		0x5b
+#define ERASE			0x2c
+#define FORMAT_UNIT		0x04
+#define GET_CONFIGURATION	0x46
+#define GET_EVENT		0xa4
+#define GET_PERFORMANCE		0xac
+#define READ_BUFFER		0x3c
+#define READ_DISC_INFO		0x51
 
 /* Page codes for mode sense/set */
-
 #define PAGE_READERR            0x01
 #define PAGE_CDROM              0x0d
 #define PAGE_AUDIO              0x0e
 #define PAGE_CAPABILITIES       0x2a
 #define PAGE_ALL                0x3f
 
-
 /* ATAPI sense keys (from table 140 of ATAPI 2.6) */
-
 #define NO_SENSE                0x00
 #define RECOVERED_ERROR         0x01
 #define NOT_READY               0x02
@@ -111,38 +115,36 @@
 #define ABORTED_COMMAND         0x0b
 #define MISCOMPARE              0x0e
 
-/* We want some additional flags for CDROM drives.
-   To save space in the ide_drive_t struct, use some fields which
-   doesn't make sense for CDROMs -- `bios_cyl' and `bios_head'. */
-
 /* Configuration flags.  These describe the capabilities of the drive.
    They generally do not change after initialization, unless we learn
    more about the drive from stuff failing. */
 struct ide_cd_config_flags {
-	__u8 drq_interrupt    : 1; /* Device sends an interrupt when ready
-				      for a packet command. */
-	__u8 no_doorlock      : 1; /* Drive cannot lock the door. */
-	__u8 no_eject         : 1; /* Drive cannot eject the disc. */
-	__u8 nec260           : 1; /* Drive is a pre-1.2 NEC 260 drive. */
-	__u8 playmsf_as_bcd   : 1; /* PLAYMSF command takes BCD args. */
-	__u8 tocaddr_as_bcd   : 1; /* TOC addresses are in BCD. */
-	__u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */
-	__u8 subchan_as_bcd   : 1; /* Subchannel info is in BCD. */
-	__u8 is_changer       : 1; /* Drive is a changer. */
-	__u8 cd_r             : 1; /* Drive can write to CD-R media . */
-	__u8 cd_rw            : 1; /* Drive can write to CD-R/W media . */
-	__u8 dvd              : 1; /* Drive is a DVD-ROM */
-	__u8 dvd_r            : 1; /* Drive can write DVD-RAM */
-	__u8 dvd_rw           : 1; /* Drive can write DVD-R/W */
-	__u8 test_write       : 1; /* Drive can fake writes */
-	__u8 supp_disc_present: 1; /* Changer can report exact contents
-				      of slots. */
-	__u8 limit_nframes    : 1; /* Drive does not provide data in
-				      multiples of SECTOR_SIZE when more
-				      than one interrupt is needed. */
-	__u8 seeking          : 1; /* Seeking in progress */
-	__u8 reserved         : 6;
-	byte max_speed; 	   /* Max speed of the drive */
+	__u8 drq_interrupt	: 1; /* Device sends an interrupt when ready
+					for a packet command. */
+	__u8 no_doorlock	: 1; /* Drive cannot lock the door. */
+	__u8 no_eject		: 1; /* Drive cannot eject the disc. */
+	__u8 nec260		: 1; /* Drive is a pre-1.2 NEC 260 drive. */
+	__u8 playmsf_as_bcd	: 1; /* PLAYMSF command takes BCD args. */
+	__u8 tocaddr_as_bcd	: 1; /* TOC addresses are in BCD. */
+	__u8 toctracks_as_bcd	: 1; /* TOC track numbers are in BCD. */
+	__u8 subchan_as_bcd	: 1; /* Subchannel info is in BCD. */
+	__u8 is_changer		: 1; /* Drive is a changer. */
+	__u8 cd_r		: 1; /* Drive can write to CD-R media . */
+	__u8 cd_rw		: 1; /* Drive can write to CD-R/W media . */
+	__u8 dvd		: 1; /* Drive is a DVD-ROM */
+	__u8 dvd_r		: 1; /* Drive can write DVD-R */
+	__u8 dvd_ram		: 1; /* Drive can write DVD-RAM */
+	__u8 test_write		: 1; /* Drive can fake writes */
+	__u8 supp_disc_present	: 1; /* Changer can report exact contents
+					of slots. */
+	__u8 limit_nframes	: 1; /* Drive does not provide data in
+					multiples of SECTOR_SIZE when more
+					than one interrupt is needed. */
+	__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;
+	byte max_speed;		     /* Max speed of the drive */
 };
 #define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
 
@@ -518,9 +520,11 @@
 
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 mech_state    : 3;
-	__u8 reserved1     : 5;
+	__u8 door_open     : 1;
+	__u8 reserved1     : 4;
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
-	__u8 reserved1     : 5;
+	__u8 reserved1     : 4;
+	__u8 door_open     : 1;
 	__u8 mech_state    : 3;
 #else
 #error "Please fix <asm/byteorder.h>"
@@ -653,13 +657,13 @@
 	{ MODE_SENSE_10, "Mode Sense" },
 	{ LOAD_UNLOAD, "Load/Unload CD" },
 	{ READ_12, "Read(12)" },
+	{ GET_PERFORMANCE, "Get Performance" },
 	{ READ_CD_MSF, "Read CD MSF" },
 	{ SCAN, "Scan" },
 	{ SET_CD_SPEED, "Set CD Speed" },
 	{ PLAY_CD, "Play CD" },
 	{ MECHANISM_STATUS, "Mechanism Status" },
 	{ READ_CD, "Read CD" },
-	{ DVD_GET_PERFORMANCE, "Get Performance" },
 };
 
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.3.12/linux/drivers/block/ide-dma.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/ide-dma.c	Fri Aug  6 10:41:47 1999
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-dma.c	Version 4.09  April 23, 1999
+ *  linux/drivers/block/ide-dma.c	Version 4.09	April 23, 1999
  *
  *  Copyright (c) 1999  Andre Hedrick
  *  May be copied or modified under the terms of the GNU General Public License
@@ -357,12 +357,11 @@
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive))
 			return hwif->dmaproc(ide_dma_off, drive);
-#ifdef CONFIG_IDEDMA_ULTRA_66
+
 		/* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */
-		if ((id->field_valid & 4) && (id->word93 & 0x2000))
+		if ((id->field_valid & 4) && (hwif->udma_four) && (id->word93 & 0x2000))
 			if ((id->dma_ultra & (id->dma_ultra >> 11) & 3))
 				return hwif->dmaproc(ide_dma_on, drive);
-#endif /* CONFIG_IDEDMA_ULTRA_66 */
 		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
 		if (id->field_valid & 4)	/* UltraDMA */
 			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
@@ -443,6 +442,12 @@
 		case ide_dma_bad_drive:
 		case ide_dma_good_drive:
 			return check_drive_lists(drive, (func == ide_dma_good_drive));
+		case ide_dma_lostirq:
+		case ide_dma_timeout:
+			/*
+			 * printk("ide_dmaproc: chipset supported func only: %d\n", func);
+			 */
+			return 1;
 		default:
 			printk("ide_dmaproc: unsupported func: %d\n", func);
 			return 1;
@@ -510,7 +515,7 @@
 /*
  * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
  */
-__initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name))
+unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
 {
 	unsigned long	dma_base = 0;
 	struct pci_dev	*dev = hwif->pci_dev;
@@ -518,7 +523,7 @@
 	if (hwif->mate && hwif->mate->dma_base) {
 		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
 	} else {
-		dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+		dma_base = dev->resource[4].start;
 		if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) {
 			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
 			dma_base = 0;
@@ -532,10 +537,6 @@
 
 		switch(dev->device) {
 			case PCI_DEVICE_ID_CMD_643:
-				/*
-				 * Lets attempt to use the same Ali tricks
-				 * to fix CMD643.....
-				 */
 #ifdef CONFIG_BLK_DEV_ALI15X3
 			case PCI_DEVICE_ID_AL_M5219:
 			case PCI_DEVICE_ID_AL_M5229:
@@ -550,9 +551,19 @@
 				}
 				break;
 			default:
-				if (inb(dma_base+2) & 0x80) {
-					printk("%s: simplex device:  DMA disabled\n", name);
-					dma_base = 0;
+				/*
+				 * If the device claims "simplex" DMA,
+				 * this means only one of the two interfaces
+				 * can be trusted with DMA at any point in time.
+				 * So we should enable DMA only on one of the
+				 * two interfaces.
+				 */
+				if ((inb(dma_base+2) & 0x80)) {	/* simplex device? */
+					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
+					    (hwif->mate && hwif->mate->dma_base)) {
+						printk("%s: simplex device:  DMA disabled\n", name);
+						dma_base = 0;
+					}
 				}
 		}
 	}
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.3.12/linux/drivers/block/ide-floppy.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide-floppy.c	Thu Aug  5 14:34:01 1999
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/block/ide-floppy.c	Version 0.8		Dec   7, 1997
+ * linux/drivers/block/ide-floppy.c	Version 0.9		Jul   4, 1999
  *
- * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
  */
 
 /*
@@ -26,9 +26,12 @@
  *                       Issue START command only if TEST UNIT READY fails.
  *                       Add work-around for IOMEGA ZIP revision 21.D.
  *                       Remove idefloppy_get_capabilities().
+ * Ver 0.9   Jul  4 99   Fix a bug which might have caused the number of
+ *                        bytes requested on each interrupt to be zero.
+ *                        Thanks to <shanos@es.co.nz> for pointing this out.
  */
 
-#define IDEFLOPPY_VERSION "0.8"
+#define IDEFLOPPY_VERSION "0.9"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -997,7 +1000,7 @@
 	pc->retries++;
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
@@ -1521,9 +1524,19 @@
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
 		set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
-	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 &&
-	    ((strcmp(drive->id->fw_rev, "21.D") == 0) ||
-	     (strcmp(drive->id->fw_rev, "23.D") == 0))) {
+	/*
+	 *	We used to check revisions here. At this point however
+	 *	I'm giving up. Just assume they are all broken, its easier.
+	 *
+	 *	The actual reason for the workarounds was likely
+	 *	a driver bug after all rather than a firmware bug,
+	 *	and the workaround below used to hide it. It should
+	 *	be fixed as of version 1.9, but to be on the safe side
+	 *	we'll leave the limitation below for the 2.2.x tree.
+	 */
+
+	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
+	{
 		for (i = 0; i < 1 << PARTN_BITS; i++)
 			max_sectors[major][minor + i] = 64;
 	}
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.12/linux/drivers/block/ide-pci.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/ide-pci.c	Mon Aug  9 10:23:09 1999
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-pci.c	Version 1.03  May 1, 1999
+ *  linux/drivers/block/ide-pci.c	Version 1.04	July 27, 1999
  *
  *  Copyright (c) 1998-1999  Andre Hedrick
  *
@@ -52,6 +52,7 @@
 #define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
 #define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
 #define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
 #define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
 #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})
@@ -106,11 +107,14 @@
 #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
 #endif
@@ -166,6 +170,26 @@
 #define	INIT_HPT34X	NULL
 #endif
 
+#ifdef CONFIG_BLK_DEV_HPT366
+extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
+extern void ide_init_hpt366(ide_hwif_t *);
+#define PCI_HPT366	&pci_init_hpt366
+#define INIT_HPT366	&ide_init_hpt366
+#else
+#define PCI_HPT366	NULL
+#define INIT_HPT366	IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_SIS5513
+extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
+extern void ide_init_sis5513(ide_hwif_t *);
+#define PCI_SIS5513	&pci_init_sis5513
+#define INIT_SIS5513	&ide_init_sis5513
+#else
+#define PCI_SIS5513	NULL
+#define INIT_SIS5513	NULL
+#endif
+
 #define INIT_SAMURAI	NULL
 #define INIT_CX5530	NULL
 
@@ -183,71 +207,85 @@
 	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 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	NULL,		INIT_VIA82C586,	DMA_VIA82C586,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	NULL,		NULL,		NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	NULL,		INIT_CMD646,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC6210,	NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	NULL,		INIT_W82C105,	NULL,		{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	INIT_ALI15X3,	NULL,		{{0x09,0x20,0x20}, {0x09,0x10,0x10}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CX5530,	"CX5530",	NULL,		INIT_CX5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
+	{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",	NULL,		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;
 
 /*
  * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
  * settings of split-mirror pci-config space, place chipset into init-mode,
  * and/or preserve an interrupt if the card is not native ide support.
  */
-__initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const char *name))
+static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
 {
 	switch(dev->device) {
 		case PCI_DEVICE_ID_TTI_HPT343:
 			{
-				int i;
 				unsigned short pcicmd = 0;
-				unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
 
 				pci_write_config_byte(dev, 0x80, 0x00);
-				dev->base_address[0] = (hpt34xIoBase + 0x20);
-				dev->base_address[1] = (hpt34xIoBase + 0x34);
-				dev->base_address[2] = (hpt34xIoBase + 0x28);
-				dev->base_address[3] = (hpt34xIoBase + 0x3c);
-				for(i=0; i<4; i++)
-					dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
-
 				pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
 				if (!(pcicmd & PCI_COMMAND_MEMORY)) {
+					/*
+					 * FIXME - this is too ugly, and looks senseless.
+					 * Why not just use resource[4]?
+					 *
+					 * This was a cleaner/quicker way to get the ioports
+					 * that the are not decode do to a flaw in the chipset
+					 * design.
+					 */
+
+					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);
 				}
 			}
+		case PCI_DEVICE_ID_TTI_HPT366:
 		case PCI_DEVICE_ID_PROMISE_20246:
 		case PCI_DEVICE_ID_PROMISE_20262:
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
@@ -262,7 +300,7 @@
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
-__initfunc(static ide_hwif_t *ide_match_hwif (unsigned long io_base, byte bootable, const char *name))
+static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
 {
 	int h;
 	ide_hwif_t *hwif;
@@ -324,7 +362,7 @@
 	return NULL;
 }
 
-__initfunc(static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name))
+static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
 {
 	byte reg, progif = 0;
 
@@ -346,11 +384,15 @@
 	/*
 	 * Setup base registers for IDE command/control spaces for each interface:
 	 */
-	for (reg = 0; reg < 4; reg++)
-		if (!dev->base_address[reg]) {
+	for (reg = 0; reg < 4; reg++) {
+		struct resource *res = dev->resource + reg;
+		if (!(res->flags & PCI_BASE_ADDRESS_SPACE_IO))
+			continue;
+		if (!res->start) {
 			printk("%s: Missing I/O address #%d\n", name, reg);
 			return 1;
 		}
+	}
 	return 0;
 }
 
@@ -364,7 +406,7 @@
  * we "know" about, this information is in the ide_pci_device_t struct;
  * for all other chipsets, we just assume both interfaces are enabled.
  */
-__initfunc(static void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d))
+static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
 	unsigned short pcicmd = 0, tried_config = 0;
@@ -446,9 +488,12 @@
 		ide_pci_enablebit_t *e = &(d->enablebits[port]);
 		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
 			continue;	/* port not enabled */
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port))
+			return;
 		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
-			ctl  = dev->base_address[(2*port)+1] & PCI_BASE_ADDRESS_IO_MASK;
-			base = dev->base_address[2*port] & ~7;
+			/* FIXME! This really should check that it really gets the IO/MEM part right! */
+			ctl  = dev->resource[(2*port)+1].start;
+			base = dev->resource[2*port].start;
 		}
 		if ((ctl && !base) || (base && !ctl)) {
 			printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port);
@@ -484,13 +529,12 @@
 			hwif->irq = hwif->channel ? 15 : 14;
 			goto bypass_umc_dma;
 		}
-
+		if ((!d->sixtysix) && (hwif->udma_four))
+			hwif->udma_four = 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X))
 			autodma = 0;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262))
-			hwif->udma_four = 1;
 		if (autodma)
 			hwif->autodma = 1;
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
@@ -499,6 +543,7 @@
 #ifdef CONFIG_BLK_DEV_HPT34X
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
 #endif /* CONFIG_BLK_DEV_HPT34X */
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
 		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
 			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
@@ -534,11 +579,49 @@
 		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
 }
 
+__initfunc(static void hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d))
+{
+	struct pci_dev *dev2;
+	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);
+	}
+
+	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) {
+		printk("%s: IDE controller on PCI bus %02x dev %02x\n",
+			d2->name, dev2->bus->number, dev2->devfn);
+		ide_setup_pci_device(dev2, d2);
+	}
+}
+
 /*
  * ide_scan_pcibus() gets invoked at boot time from ide.c.
  * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
  */
-__initfunc(void ide_scan_pcibus (void))
+void __init ide_scan_pcibus (void)
 {
 	struct pci_dev		*dev;
 	ide_pci_devid_t		devid;
@@ -558,6 +641,8 @@
 			continue;	/* CY82C693 is more than only a IDE controller */
 		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
 			continue;	/* UM8886A/BF pair */
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
+			hpt366_device_order_fixup(dev, d);
 		else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
 			if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
 				printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.12/linux/drivers/block/ide-pmac.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/block/ide-pmac.c	Mon Aug  9 10:23:09 1999
@@ -230,8 +230,8 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
-__initfunc(static void
-pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif))
+static void __init 
+pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif)
 {
 	hwif->dma_base = (unsigned long) ioremap(np->addrs[1].address, 0x200);
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.12/linux/drivers/block/ide-probe.c	Thu Jul  8 15:42:19 1999
+++ linux/drivers/block/ide-probe.c	Thu Aug  5 18:48:45 1999
@@ -20,7 +20,7 @@
  * Version 1.04		fixed buggy treatments of known flash memory cards
  *
  * Version 1.05		fix for (hwif->chipset == ide_pdc4030)
- *			added ide6/7
+ *			added ide6/7/8/9
  *			allowed for secondary flash card to be detectable
  *			 with new flag : drive->ata_flash : 1;
  */
@@ -762,6 +762,12 @@
 #endif
 #if MAX_HWIFS > 7
 	case IDE7_MAJOR: rfn = &do_ide7_request; break;
+#endif
+#if MAX_HWIFS > 8
+	case IDE8_MAJOR: rfn = &do_ide8_request; break;
+#endif
+#if MAX_HWIFS > 9
+	case IDE9_MAJOR: rfn = &do_ide9_request; break;
 #endif
 	default:
 		printk("%s: request_fn NOT DEFINED\n", hwif->name);
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.3.12/linux/drivers/block/ide-tape.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/block/ide-tape.c	Thu Aug  5 18:48:45 1999
@@ -3583,8 +3583,8 @@
 	/*
 	 *  These two ide-pci host adapters appear to need this disabled.
 	 */
-	if ((hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+	if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+	    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
 		drive->dsc_overlap = 0;
 	} else
 #endif  /* CONFIG_BLK_DEV_IDEPCI */
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.12/linux/drivers/block/ide.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/block/ide.c	Mon Aug  9 12:32:28 1999
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 6.19  January 29, 1999
+ *  linux/drivers/block/ide.c		Version 6.20	July 10, 1999
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -93,19 +93,28 @@
  * Version 6.17		fix for newest EZ-Drive problem
  * Version 6.18		default unpartitioned-disk translation now "BIOS LBA"
  * Version 6.19		Re-design for a UNIFORM driver for all platforms,
- *			model based on suggestions from Russell King and
- *			Geert Uytterhoeven
+ *			  model based on suggestions from Russell King and
+ *			  Geert Uytterhoeven
  *			Promise DC4030VL now supported.
+ *			add support for ide6/ide7
  *			delay_50ms() changed to ide_delay_50ms() and exported.
+ * Version 6.20		Added/Fixed Generic ATA-66 support and hwif detection.
+ *			Added hdx=flash to allow for second flash disk
+ *			  detection w/o the hang loop.
+ *			Added support for ide8/ide9
+ *			Added idex=ata66 for the quirky chipsets that are
+ *			  ATA-66 compliant, but have yet to determine a method
+ *			  of verification of the 80c cable presence.
+ *			  Specifically Promise's PDC20262 chipset.
  *
- *  Some additional driver compile-time options are in ide.h
+ *  Some additional driver compile-time options are in ./include/linux/ide.h
  *
  *  To do, in likely order of completion:
  *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
 */
 
-#define	REVISION	"Revision: 6.19"
-#define	VERSION		"Id: ide.c 6.19 1999/01/29"
+#define	REVISION	"Revision: 6.20"
+#define	VERSION		"Id: ide.c 6.20 1999/07/10"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -144,7 +153,11 @@
 extern byte fifoconfig;           /* defined in via82c586.c used by ide_setup()*/
 #endif
 
-static const byte	ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR };
+static const byte	ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
+						IDE2_MAJOR, IDE3_MAJOR,
+						IDE4_MAJOR, IDE5_MAJOR,
+						IDE6_MAJOR, IDE7_MAJOR,
+						IDE8_MAJOR, IDE9_MAJOR };
 
 static int	idebus_parameter; /* holds the "idebus=" parameter */
 static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
@@ -1308,6 +1321,20 @@
 }
 #endif /* MAX_HWIFS > 7 */
 
+#if MAX_HWIFS > 8
+void do_ide8_request (void)
+{
+	unlock_do_hwgroup_request (ide_hwifs[8].hwgroup);
+}
+#endif /* MAX_HWIFS > 8 */
+
+#if MAX_HWIFS > 9
+void do_ide9_request (void)
+{
+	unlock_do_hwgroup_request (ide_hwifs[9].hwgroup);
+}
+#endif /* MAX_HWIFS > 9 */
+
 static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq)
 {
 	unsigned long	flags;
@@ -1347,6 +1374,7 @@
 		handler(drive);
 	} else if (drive_is_ready(drive)) {
 		printk("%s: lost interrupt\n", drive->name);
+		(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
 		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		handler(drive);
 	} else {
@@ -1357,6 +1385,7 @@
 	 *  need something here for HPT34X.......AMH
 	 *  irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }
 	 */
+			(void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
 		}
 		spin_unlock_irqrestore(&hwgroup->spinlock, flags);
 		ide_error(drive, "irq timeout", GET_STAT());
@@ -1957,7 +1986,7 @@
 		}
 		for (index = 0; index < MAX_HWIFS; ++index) {
 			hwif = &ide_hwifs[index];
-			if ((!hwif->present && !initializing) ||
+			if ((!hwif->present && !hwif->mate && !initializing) ||
 			    (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
 				goto found;
 		}
@@ -2524,7 +2553,7 @@
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
  */
-__initfunc(static int stridx (const char *s, char c))
+static int __init stridx (const char *s, char c)
 {
 	char *i = strchr(s, c);
 	return (i && c) ? i - s : -1;
@@ -2542,7 +2571,7 @@
  *     and base16 is allowed when prefixed with "0x".
  * 4. otherwise, zero is returned.
  */
-__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals))
+static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
 {
 	static const char *decimal = "0123456789";
 	static const char *hex = "0123456789abcdef";
@@ -2641,6 +2670,10 @@
  * "idex=four"		: four drives on idex and ide(x^1) share same ports
  * "idex=reset"		: reset interface before first use
  * "idex=dma"		: enable DMA by default on both drives if possible
+ * "idex=ata66"		: informs the interface that it has an 80c cable
+ *				for chipsets that are ATA-66 capable, but
+ *				the ablity to bit test for detection is
+ *				currently unknown.
  *
  * "splitfifo=betweenChan"
  *			: FIFO Configuration of VIA 82c586(<nothing>,"A"or"B").
@@ -2668,8 +2701,9 @@
  * "ide0=ali14xx"	: probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
  * "ide0=umc8672"	: probe/support umc8672 chipsets
  * "idex=dc4030"	: probe/support Promise DC4030VL interface
+ * "ide=doubler"	: probe/support IDE doublers on Amiga
  */
-__initfunc(void ide_setup (char *s))
+void __init ide_setup (char *s)
 {
 	int i, vals[3];
 	ide_hwif_t *hwif;
@@ -2828,9 +2862,12 @@
 	if (s[3] >= '0' && s[3] <= max_hwif) {
 		/*
 		 * Be VERY CAREFUL changing this: note hardcoded indexes below
+		 * -8,-9,-10 : are reserved for future idex calls to ease the hardcoding.
 		 */
-		const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "four",
-			"qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL};
+		const char *ide_words[] = {
+			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
+			"minus8", "minus9", "minus10",
+			"four", "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -2838,19 +2875,19 @@
 		/*
 		 * Cryptic check to ensure chipset not already set for hwif:
 		 */
-		if (i > 0 || i <= -7) {			/* is parameter a chipset name? */
+		if (i > 0 || i <= -11) {			/* is parameter a chipset name? */
 			if (hwif->chipset != ide_unknown)
 				goto bad_option;	/* chipset already specified */
-			if (i <= -7 && i != -14 && hw != 0)
+			if (i <= -11 && i != -18 && hw != 0)
 				goto bad_hwif;		/* chipset drivers are for "ide0=" only */
-			if (i <= -7 && i != -14 && ide_hwifs[hw+1].chipset != ide_unknown)
+			if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown)
 				goto bad_option;	/* chipset for 2nd port already specified */
 			printk("\n");
 		}
 
 		switch (i) {
 #ifdef CONFIG_BLK_DEV_PDC4030
-			case -14: /* "dc4030" */
+			case -18: /* "dc4030" */
 			{
 				extern void init_pdc4030(void);
 				init_pdc4030();
@@ -2858,7 +2895,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 #ifdef CONFIG_BLK_DEV_ALI14XX
-			case -13: /* "ali14xx" */
+			case -17: /* "ali14xx" */
 			{
 				extern void init_ali14xx (void);
 				init_ali14xx();
@@ -2866,7 +2903,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_ALI14XX */
 #ifdef CONFIG_BLK_DEV_UMC8672
-			case -12: /* "umc8672" */
+			case -16: /* "umc8672" */
 			{
 				extern void init_umc8672 (void);
 				init_umc8672();
@@ -2874,7 +2911,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_UMC8672 */
 #ifdef CONFIG_BLK_DEV_DTC2278
-			case -11: /* "dtc2278" */
+			case -15: /* "dtc2278" */
 			{
 				extern void init_dtc2278 (void);
 				init_dtc2278();
@@ -2882,7 +2919,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_DTC2278 */
 #ifdef CONFIG_BLK_DEV_CMD640
-			case -10: /* "cmd640_vlb" */
+			case -14: /* "cmd640_vlb" */
 			{
 				extern int cmd640_vlb; /* flag for cmd640.c */
 				cmd640_vlb = 1;
@@ -2890,7 +2927,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_CMD640 */
 #ifdef CONFIG_BLK_DEV_HT6560B
-			case -9: /* "ht6560b" */
+			case -13: /* "ht6560b" */
 			{
 				extern void init_ht6560b (void);
 				init_ht6560b();
@@ -2898,7 +2935,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_HT6560B */
 #if CONFIG_BLK_DEV_QD6580
-			case -8: /* "qd6580" */
+			case -12: /* "qd6580" */
 			{
 				extern void init_qd6580 (void);
 				init_qd6580();
@@ -2906,7 +2943,7 @@
 			}
 #endif /* CONFIG_BLK_DEV_QD6580 */
 #ifdef CONFIG_BLK_DEV_4DRIVES
-			case -7: /* "four" drives on one set of ports */
+			case -11: /* "four" drives on one set of ports */
 			{
 				ide_hwif_t *mate = &ide_hwifs[hw^1];
 				mate->drives[0].select.all ^= 0x20;
@@ -2917,6 +2954,18 @@
 				goto do_serialize;
 			}
 #endif /* CONFIG_BLK_DEV_4DRIVES */
+			case -10: /* minus10 */
+			case -9: /* minus9 */
+			case -8: /* minus8 */
+				goto bad_option;
+			case -7: /* ata66 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+				hwif->udma_four = 1;
+				goto done;
+#else /* !CONFIG_BLK_DEV_IDEPCI */
+				hwif->udma_four = 0;
+				goto bad_hwif;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 			case -6: /* dma */
 				hwif->autodma = 1;
 				goto done;
@@ -3080,7 +3129,7 @@
 /*
  * probe_for_hwifs() finds/initializes "known" IDE interfaces
  */
-__initfunc(static void probe_for_hwifs (void))
+static void __init probe_for_hwifs (void)
 {
 #ifdef CONFIG_PCI
 	if (pci_present())
@@ -3154,7 +3203,7 @@
 #endif /* CONFIG_BLK_DEV_BUDDHA */
 }
 
-__initfunc(void ide_init_builtin_drivers (void))
+void __init ide_init_builtin_drivers (void)
 {
 	/*
 	 * Probe for special PCI and other "known" interface chipsets
@@ -3425,6 +3474,12 @@
 #if MAX_HWIFS > 7
 EXPORT_SYMBOL(do_ide7_request);
 #endif /* MAX_HWIFS > 7 */
+#if MAX_HWIFS > 8
+EXPORT_SYMBOL(do_ide8_request);
+#endif /* MAX_HWIFS > 8 */
+#if MAX_HWIFS > 9
+EXPORT_SYMBOL(do_ide9_request);
+#endif /* MAX_HWIFS > 9 */
 
 /*
  * Driver module
@@ -3469,7 +3524,7 @@
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
-__initfunc(int ide_init (void))
+int __init ide_init (void)
 {
 	static char banner_printed = 0;
 
@@ -3491,7 +3546,7 @@
 char *options = NULL;
 MODULE_PARM(options,"s");
 
-__initfunc(static void parse_options (char *line))
+static void __init parse_options (char *line)
 {
 	char *next = line;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/linear.c linux/drivers/block/linear.c
--- v2.3.12/linux/drivers/block/linear.c	Sat Nov  8 11:39:12 1997
+++ linux/drivers/block/linear.c	Mon Aug  9 10:23:09 1999
@@ -184,7 +184,7 @@
 
 #ifndef MODULE
 
-__initfunc(void linear_init (void))
+void __init linear_init (void)
 {
   register_md_personality (LINEAR, &linear_personality);
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.12/linux/drivers/block/ll_rw_blk.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/block/ll_rw_blk.c	Mon Aug  9 11:49:24 1999
@@ -286,7 +286,7 @@
  * with the request-lists in peace. Thus it should be called with no spinlocks
  * held.
  *
- * By this point, req->cmd is always either READ/WRITE, never READA/WRITEA,
+ * By this point, req->cmd is always either READ/WRITE, never READA,
  * which is important for drive_stat_acct() above.
  */
 
@@ -417,7 +417,7 @@
 		}
 	}
 
-	rw_ahead = 0;	/* normal case; gets changed below for READA/WRITEA */
+	rw_ahead = 0;	/* normal case; gets changed below for READA */
 	switch (rw) {
 		case READA:
 			rw_ahead = 1;
@@ -431,9 +431,6 @@
 		case WRITERAW:
 			rw = WRITE;
 			goto do_write;	/* Skip the buffer refile */
-		case WRITEA:
-			rw_ahead = 1;
-			rw = WRITE;	/* drop into WRITE */
 		case WRITE:
 			if (!test_and_clear_bit(BH_Dirty, &bh->b_state))
 				goto end_io;	/* Hmmph! Nothing to write */
@@ -486,6 +483,8 @@
 	     case IDE5_MAJOR:
 	     case IDE6_MAJOR:
 	     case IDE7_MAJOR:
+	     case IDE8_MAJOR:
+	     case IDE9_MAJOR:
 	     case ACSI_MAJOR:
 	     case MFM_ACORN_MAJOR:
 		/*
@@ -596,13 +595,6 @@
 	struct blk_dev_struct * dev;
 	int i;
 
-	/* Make sure that the first block contains something reasonable */
-	while (!*bh) {
-		bh++;
-		if (--nr <= 0)
-			return;
-	}
-
 	dev = NULL;
 	if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
 		dev = blk_dev + major;
@@ -652,26 +644,22 @@
 	}
 
 	for (i = 0; i < nr; i++) {
-		if (bh[i]) {
-			set_bit(BH_Req, &bh[i]->b_state);
+		set_bit(BH_Req, &bh[i]->b_state);
 #ifdef CONFIG_BLK_DEV_MD
-			if (MAJOR(bh[i]->b_dev) == MD_MAJOR) {
-				md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]);
-				continue;
-			}
-#endif
-			make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
+		if (MAJOR(bh[i]->b_dev) == MD_MAJOR) {
+			md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]);
+			continue;
 		}
+#endif
+		make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]);
 	}
 	return;
 
       sorry:
 	for (i = 0; i < nr; i++) {
-		if (bh[i]) {
-			clear_bit(BH_Dirty, &bh[i]->b_state);
-			clear_bit(BH_Uptodate, &bh[i]->b_state);
-			bh[i]->b_end_io(bh[i], 0);
-		}
+		clear_bit(BH_Dirty, &bh[i]->b_state);
+		clear_bit(BH_Uptodate, &bh[i]->b_state);
+		bh[i]->b_end_io(bh[i], 0);
 	}
 	return;
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.3.12/linux/drivers/block/md.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/md.c	Mon Aug  9 10:23:09 1999
@@ -1174,7 +1174,7 @@
 };
 
 /* called from init/main.c */
-__initfunc(void md_setup(char *str,int *ints))
+void __init md_setup(char *str,int *ints)
 {
 	int i;
 	for(i=0;i<=ints[0];i++) {
@@ -1186,7 +1186,7 @@
 	return;
 }
 
-__initfunc(void do_md_setup(char *str,int *ints))
+void __init do_md_setup(char *str,int *ints)
 {
 	int minor, pers, factor, fault;
 	kdev_t dev;
@@ -1265,7 +1265,7 @@
 void raid1_init (void);
 void raid5_init (void);
 
-__initfunc(int md_init (void))
+int __init md_init (void)
 {
   printk ("md driver %d.%d.%d MAX_MD_DEV=%d, MAX_REAL=%d\n",
     MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION,
@@ -1306,7 +1306,7 @@
 }
 
 #ifdef CONFIG_MD_BOOT
-__initfunc(void md_setup_drive(void))
+void __init md_setup_drive(void)
 {
 	if(md_setup_args.set)
 		do_md_setup(md_setup_args.str, md_setup_args.ints);
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c
--- v2.3.12/linux/drivers/block/ns87415.c	Wed Jun  2 22:21:51 1999
+++ linux/drivers/block/ns87415.c	Mon Aug  9 10:23:09 1999
@@ -102,7 +102,7 @@
 	}
 }
 
-__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif))
+void __init ide_init_ns87415 (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned int ctrl, using_inta;
diff -u --recursive --new-file v2.3.12/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c
--- v2.3.12/linux/drivers/block/pdc202xx.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/block/pdc202xx.c	Thu Aug  5 18:48:45 1999
@@ -215,8 +215,8 @@
 	byte			test1, test2, speed;
 	byte			AP, BP, CP, DP, EP;
 	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-	byte udma_66		= ((id->word93 & 0x2000) && (dev->device == PCI_DEVICE_ID_PROMISE_20262)) ? 1 : 0;
-	byte udma_33		= ultra ? (inb((dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK) + 0x001f) & 1) : 0;
+	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;
 
 	pci_read_config_byte(dev, 0x50, &EP);
 
@@ -308,7 +308,7 @@
 		speed = XFER_UDMA_3;
 	} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
 		if (!((id->dma_ultra >> 8) & 4)) {
-			drive->id->dma_ultra &= ~0x0F00;
+			drive->id->dma_ultra &= ~0xFF00;
 			drive->id->dma_ultra |= 0x0404;
 			drive->id->dma_mword &= ~0x0F00;
 			drive->id->dma_1word &= ~0x0F00;
@@ -319,7 +319,7 @@
 		speed = XFER_UDMA_2;
 	} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
 		if (!((id->dma_ultra >> 8) & 2)) {
-			drive->id->dma_ultra &= ~0x0F00;
+			drive->id->dma_ultra &= ~0xFF00;
 			drive->id->dma_ultra |= 0x0202;
 			drive->id->dma_mword &= ~0x0F00;
 			drive->id->dma_1word &= ~0x0F00;
@@ -330,7 +330,7 @@
 		speed = XFER_UDMA_1;
 	} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
 		if (!((id->dma_ultra >> 8) & 1)) {
-			drive->id->dma_ultra &= ~0x0F00;
+			drive->id->dma_ultra &= ~0xFF00;
 			drive->id->dma_ultra |= 0x0101;
 			drive->id->dma_mword &= ~0x0F00;
 			drive->id->dma_1word &= ~0x0F00;
@@ -493,7 +493,7 @@
 
 __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name))
 {
-	unsigned long high_16	= dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+	unsigned long high_16	= dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK;
 	byte udma_speed_flag	= inb(high_16 + 0x001f);
 	byte primary_mode	= inb(high_16 + 0x001a);
 	byte secondary_mode	= inb(high_16 + 0x001b);
@@ -551,5 +551,20 @@
 {
 	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;
+		}
 	}
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/block/piix.c linux/drivers/block/piix.c
--- v2.3.12/linux/drivers/block/piix.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/block/piix.c	Thu Aug  5 18:48:45 1999
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/piix.c	Version 0.24	June 28, 1999
+ * linux/drivers/block/piix.c	Version 0.25	July 11, 1999
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
@@ -149,18 +149,19 @@
 
 #ifdef CONFIG_BLK_DEV_PIIX_TUNING
 
-static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra)
+static int piix_config_drive_for_dma(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
 
-	unsigned long		flags;
 	int			sitre;
 	short			reg4042, reg44, reg48, reg4a;
 	byte			speed;
 	int			u_speed;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;			
+
+	byte maslave		= hwif->channel ? 0x42 : 0x40;
+	int ultra		= (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0;
 	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
 	int a_speed		= 2 << (drive_number * 4);
 	int u_flag		= 1 << drive_number;
@@ -171,9 +172,6 @@
 	pci_read_config_word(dev, 0x48, &reg48);
 	pci_read_config_word(dev, 0x4a, &reg4a);
 
-	save_flags(flags);
-	cli();
-
 	if (id->dma_ultra && (ultra)) {
 		if (!(reg48 & u_flag)) {
 			pci_write_config_word(dev, 0x48, reg48|u_flag);
@@ -184,7 +182,12 @@
 		}
 	}
 
-	if ((id->dma_ultra & 0x0004) && (ultra)) {
+	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)) {
@@ -256,7 +259,6 @@
 		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
 	}
 
-	restore_flags(flags);
 	piix_tune_drive(drive, piix_dma_2_pio(speed));
 
 	(void) ide_config_drive_speed(drive, speed);
@@ -269,7 +271,8 @@
 	printk("\n");
 #endif /* PIIX_DEBUG_DRIVE_INFO */
 
-	return ((int)	((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
+			((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);
@@ -277,10 +280,9 @@
 
 static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	int ultra = (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_INTEL_82371AB) ? 1 : 0;
 	switch (func) {
 		case ide_dma_check:
-			 return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive, ultra), drive);
+			 return ide_dmaproc((ide_dma_action_t) piix_config_drive_for_dma(drive), drive);
 		default :
 			break;
 	}
@@ -292,12 +294,14 @@
 void ide_init_piix (ide_hwif_t *hwif)
 {
 	hwif->tuneproc = &piix_tune_drive;
-#ifdef CONFIG_BLK_DEV_PIIX_TUNING
+
 	if (hwif->dma_base) {
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
 		hwif->dmaproc = &piix_dmaproc;
-	} else
 #endif /* CONFIG_BLK_DEV_PIIX_TUNING */
-	{
+		hwif->drives[0].autotune = 0;
+		hwif->drives[1].autotune = 0;
+	} else {
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
 	}
diff -u --recursive --new-file v2.3.12/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.3.12/linux/drivers/block/ps2esdi.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/ps2esdi.c	Mon Aug  9 10:23:09 1999
@@ -178,7 +178,7 @@
 };
 
 /* initialization routine called by ll_rw_blk.c   */
-__initfunc(int ps2esdi_init(void))
+int __init ps2esdi_init(void)
 {
 
 	/* register the device - pass the name, major number and operations
@@ -244,7 +244,7 @@
 #endif /* MODULE */
 
 /* handles boot time command line parameters */
-__initfunc(void tp720_setup(char *str, int *ints))
+void __init tp720_setup(char *str, int *ints)
 {
 	/* no params, just sets the tp720esdi flag if it exists */
 
@@ -252,7 +252,7 @@
 	tp720esdi = 1;
 }
 
-__initfunc(void ed_setup(char *str, int *ints))
+void __init ed_setup(char *str, int *ints)
 {
 	int hdind = 0;
 
@@ -299,7 +299,7 @@
 }
 
 /* ps2 esdi specific initialization - called thru the gendisk chain */
-__initfunc(static void ps2esdi_geninit(struct gendisk *ignored))
+static void __init ps2esdi_geninit(struct gendisk *ignored)
 {
 	/*
 	   The first part contains the initialization code
@@ -437,7 +437,7 @@
 }				/* ps2esdi_geninit */
 
 
-__initfunc(static void ps2esdi_get_device_cfg(void))
+static void __init ps2esdi_get_device_cfg(void)
 {
 	u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/q40ide.c linux/drivers/block/q40ide.c
--- v2.3.12/linux/drivers/block/q40ide.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/q40ide.c	Mon Aug  9 12:32:28 1999
@@ -0,0 +1,109 @@
+/*
+ *  linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver
+ *
+ *     original file created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ *  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.
+ *
+ * RZ:
+ *  almost identical with pcide.c, maybe we can merge it later. 
+ *  Differences:
+ *       max 2 HWIFS for now
+ *       translate portaddresses to q40 native addresses (not yet...) instead rely on in/out[bw]
+ *         address translation
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include "ide.h"
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define PCIDE_NUM_HWIFS	2
+
+#define PCIDE_BASE1	0x1f0
+#define PCIDE_BASE2	0x170
+#define PCIDE_BASE3	0x1e8
+#define PCIDE_BASE4	0x168
+#define PCIDE_BASE5	0x1e0
+#define PCIDE_BASE6	0x160
+
+static const q40ide_ioreg_t pcide_bases[PCIDE_NUM_HWIFS] = {
+    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
+    PCIDE_BASE6 */
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#undef HD_DATA
+#define HD_DATA  0x1f0
+
+#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
+    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
+    PCIDE_REG(CMD)
+};
+
+int q40ide_default_irq(q40ide_ioreg_t base)
+{
+           switch (base) { 
+	            case 0x1f0: return 14;
+		    case 0x170: return 15;
+		    case 0x1e8: return 11;
+		    default:
+			return 0;
+	   }
+}
+
+void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq)
+{
+	q40ide_ioreg_t port = base;
+	int i = 8;
+
+	while (i--)
+		*p++ = port++;
+	*p++ = base + 0x206;
+	if (irq != NULL)
+		*irq = 0;
+}
+
+
+    /*
+     *  Probe for PC IDE interfaces
+     */
+
+int q40ide_probe_hwif(int index, ide_hwif_t *hwif)
+{
+    static int pcide_index[PCIDE_NUM_HWIFS] = { 0, };
+    int i;
+
+    if (!MACH_IS_Q40)
+      return 0;
+
+    for (i = 0; i < PCIDE_NUM_HWIFS; i++) {
+	if (!pcide_index[i]) {
+	  /*printk("ide%d: Q40 IDE interface\n", index);*/
+	    pcide_index[i] = index+1;
+	}
+	if (pcide_index[i] == index+1) {
+	    ide_setup_ports(hwif,(ide_ioreg_t) pcide_bases[i], pcide_offsets, 0, /*q40_ack_intr???*/ NULL);
+	    hwif->irq = ide_default_irq((ide_ioreg_t)pcide_bases[i]); /*q40_ide_irq[i];  */ /* 14 */
+	    return 1;
+	}
+    }
+    return 0;
+}
diff -u --recursive --new-file v2.3.12/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.12/linux/drivers/block/rd.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/rd.c	Mon Aug  9 10:23:09 1999
@@ -116,6 +116,7 @@
 int rd_size = 4096;		/* Size of the RAM disks */
 
 #ifndef MODULE
+
 int rd_doload = 0;		/* 1 = load RAM disk, 0 = don't load */
 int rd_prompt = 1;		/* 1 = prompt for RAM disk, 0 = don't prompt */
 int rd_image_start = 0;		/* starting block # of image */
@@ -123,7 +124,52 @@
 unsigned long initrd_start,initrd_end;
 int mount_initrd = 1;		/* zero if initrd should not be mounted */
 int initrd_below_start_ok = 0;
+
+static int __init no_initrd(char *str)
+{
+	mount_initrd = 0;
+	return 1;
+}
+
+__setup("noinitrd", no_initrd);
+
 #endif
+
+static int __init ramdisk_start_setup(char *str)
+{
+	rd_image_start = simple_strtol(str,NULL,0);
+	return 1;
+}
+
+static int __init load_ramdisk(char *str)
+{
+	rd_doload = simple_strtol(str,NULL,0) & 3;
+	return 1;
+}
+
+static int __init prompt_ramdisk(char *str)
+{
+	rd_prompt = simple_strtol(str,NULL,0) & 1;
+	return 1;
+}
+
+static int __init ramdisk_size(char *str)
+{
+	rd_size = simple_strtol(str,NULL,0);
+	return 1;
+}
+
+static int __init ramdisk_size2(char *str)
+{
+	return ramdisk_size(str);
+}
+
+__setup("ramdisk_start=", ramdisk_start_setup);
+__setup("load_ramdisk=", load_ramdisk);
+__setup("prompt_ramdisk=", prompt_ramdisk);
+__setup("ramdisk=", ramdisk_size);
+__setup("ramdisk_size=", ramdisk_size2);
+
 #endif
 
 /*
@@ -297,7 +343,7 @@
 };
 
 /* This is the registration and initialization section of the RAM disk driver */
-__initfunc(int rd_init(void))
+int __init rd_init(void)
 {
 	int		i;
 
@@ -370,8 +416,8 @@
  *	romfs
  * 	gzip
  */
-__initfunc(int
-identify_ramdisk_image(kdev_t device, struct file *fp, int start_block))
+int __init 
+identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)
 {
 	const int size = 512;
 	struct minix_super_block *minixsb;
@@ -463,7 +509,7 @@
 /*
  * This routine loads in the RAM disk image.
  */
-__initfunc(static void rd_load_image(kdev_t device, int offset, int unit))
+static void __init rd_load_image(kdev_t device, int offset, int unit)
 {
  	struct inode inode, out_inode;
 	struct file infile, outfile;
@@ -585,7 +631,7 @@
 }
 
 
-__initfunc(static void rd_load_disk(int n))
+static void __init rd_load_disk(int n)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
 	extern kdev_t real_root_dev;
@@ -614,18 +660,18 @@
 
 }
 
-__initfunc(void rd_load(void))
+void __init rd_load(void)
 {
 	rd_load_disk(0);
 }
 
-__initfunc(void rd_load_secondary(void))
+void __init rd_load_secondary(void)
 {
 	rd_load_disk(1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-__initfunc(void initrd_load(void))
+void __init initrd_load(void)
 {
 	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);
 }
@@ -684,21 +730,21 @@
 
 #include "../../lib/inflate.c"
 
-__initfunc(static void *malloc(int size))
+static void __init *malloc(int size)
 {
 	return kmalloc(size, GFP_KERNEL);
 }
 
-__initfunc(static void free(void *where))
+static void __init free(void *where)
 {
 	kfree(where);
 }
 
-__initfunc(static void gzip_mark(void **ptr))
+static void __init gzip_mark(void **ptr)
 {
 }
 
-__initfunc(static void gzip_release(void **ptr))
+static void __init gzip_release(void **ptr)
 {
 }
 
@@ -707,7 +753,7 @@
  * Fill the input buffer. This is called only when the buffer is empty
  * and at least one byte is really needed.
  */
-__initfunc(static int fill_inbuf(void))
+static int __init fill_inbuf(void)
 {
 	if (exit_code) return -1;
 	
@@ -724,7 +770,7 @@
  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  * (Used for the decompressed data only.)
  */
-__initfunc(static void flush_window(void))
+static void __init flush_window(void)
 {
     ulg c = crc;         /* temporary variable */
     unsigned n;
@@ -741,14 +787,14 @@
     outcnt = 0;
 }
 
-__initfunc(static void error(char *x))
+static void __init error(char *x)
 {
 	printk(KERN_ERR "%s", x);
 	exit_code = 1;
 }
 
-__initfunc(static int
-crd_load(struct file * fp, struct file *outfp))
+static int __init 
+crd_load(struct file * fp, struct file *outfp)
 {
 	int result;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c
--- v2.3.12/linux/drivers/block/rz1000.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/rz1000.c	Mon Aug  9 10:23:09 1999
@@ -33,7 +33,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 
-__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif))	/* called from ide-pci.c */
+void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
 {
 	unsigned short reg;
 	struct pci_dev *dev = hwif->pci_dev;
@@ -53,7 +53,7 @@
 
 #else
 
-__initfunc(static void init_rz1000 (struct pci_dev *dev, const char *name))
+static void __init init_rz1000 (struct pci_dev *dev, const char *name)
 {
 	unsigned short reg, h;
 
@@ -83,7 +83,7 @@
 	}
 }
 
-__initfunc(void ide_probe_for_rz100x (void))	/* called from ide.c */
+void __init ide_probe_for_rz100x (void)	/* called from ide.c */
 {
 	struct pci_dev *dev = NULL;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/sis5513.c linux/drivers/block/sis5513.c
--- v2.3.12/linux/drivers/block/sis5513.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/sis5513.c	Fri Aug  6 11:16:54 1999
@@ -0,0 +1,417 @@
+/*
+ * linux/drivers/block/sis5513.c	Version 0.06	July 11, 1999
+ *
+ * Copyright (C) 1999	Andre Hedrick
+ *
+ * drive_number
+ *	= ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ *	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+static struct pci_dev *host_dev;
+
+#define SIS5513_DEBUG_DRIVE_INFO	0
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ * ((id->word93 & 0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	byte			drive_pci, test1, test2, mask;
+	int			err;
+
+	byte speed		= 0x00;
+	byte unmask		= 0xE0;
+	byte four_two		= 0x00;
+	int drive_number	= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+	byte udma_66		= ((id->word93 & 0x2000) && (hwif->udma_four)) ? 1 : 0;
+
+	if (host_dev) {
+		switch(host_dev->device) {
+			case PCI_DEVICE_ID_SI_530:
+			case PCI_DEVICE_ID_SI_620:
+				unmask   = 0xF0;
+				four_two = 0x01;
+			default:
+				break;
+		}
+	}
+
+	switch(drive_number) {
+		case 0:		drive_pci = 0x40;break;
+		case 1:		drive_pci = 0x42;break;
+		case 2:		drive_pci = 0x44;break;
+		case 3:		drive_pci = 0x46;break;
+		default:	return ide_dma_off;
+	}
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	pci_read_config_byte(dev, drive_pci|0x01, &test2);
+
+	if ((!ultra) && (test2 & 0x80)) {
+		pci_write_config_byte(dev, drive_pci|0x01, test2 & ~0x80);
+		pci_read_config_byte(dev, drive_pci|0x01, &test2);
+	}
+
+	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);
+			pci_write_config_byte(dev, drive_pci|0x01, test2|mask);
+		}
+		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);
+			pci_write_config_byte(dev, drive_pci|0x01, test2|mask);
+		}
+		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);
+	}
+
+	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);
+#endif /* SIS5513_DEBUG_DRIVE_INFO */
+
+	return ((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);
+}
+
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif		= HWIF(drive);
+	struct pci_dev *dev		= hwif->pci_dev;
+
+	byte				timing, pio, drive_pci, test1, test2;
+
+	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+	unsigned short xfer_pio		= drive->id->eide_pio_modes;
+	int drive_number		= ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+
+	if (drive->media == ide_disk) {
+		struct pci_dev *dev	= hwif->pci_dev;
+		byte reg4bh		= 0;
+                byte rw_prefetch	= (0x11 << drive_number);
+
+		pci_read_config_byte(dev, 0x4b, &reg4bh);
+		if ((reg4bh & rw_prefetch) != rw_prefetch)
+			pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+	}
+
+	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0) {
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	} else {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+/*
+ *               Mode 0       Mode 1     Mode 2     Mode 3     Mode 4
+ * Active time    8T (240ns)  6T (180ns) 4T (120ns) 3T  (90ns) 3T  (90ns)
+ * 0x41 2:0 bits  000          110        100        011        011
+ * Recovery time 12T (360ns)  7T (210ns) 4T (120ns) 3T  (90ns) 1T  (30ns)
+ * 0x40 3:0 bits 0000         0111       0100       0011       0001
+ * Cycle time    20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
+ */
+
+	switch(drive_number) {
+		case 0:		drive_pci = 0x40;break;
+		case 1:		drive_pci = 0x42;break;
+		case 2:		drive_pci = 0x44;break;
+		case 3:		drive_pci = 0x46;break;
+		default:	return;
+	}
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	pci_read_config_byte(dev, drive_pci|0x01, &test2);
+
+	/*
+	 * Do a blanket clear of active and recovery timings.
+	 */
+
+	test1 &= ~0x07;
+	test2 &= ~0x0F;
+
+	switch(timing) {
+		case 4:		test1 |= 0x01;test2 |= 0x03;break;
+		case 3:		test1 |= 0x03;test2 |= 0x03;break;
+		case 2:		test1 |= 0x04;test2 |= 0x04;break;
+		case 1:		test1 |= 0x07;test2 |= 0x06;break;
+		default:	break;
+	}
+
+	pci_write_config_byte(dev, drive_pci, test1);
+	pci_write_config_byte(dev, drive_pci|0x01, test2);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+	struct hd_driveid *id		= drive->id;
+	ide_dma_action_t dma_func	= ide_dma_off_quietly;
+
+	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			return HWIF(drive)->dmaproc(ide_dma_off, drive);
+		}
+
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & 0x001F) {
+				/* Force if Capable UltraDMA */
+				dma_func = config_chipset_for_dma(drive, 1);
+				if ((id->field_valid & 2) &&
+				    (dma_func != ide_dma_on))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & 0x0007) ||
+			    (id->dma_1word & 0x0007)) {
+				/* Force if Capable regular DMA modes */
+				dma_func = config_chipset_for_dma(drive, 0);
+			}
+		} 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);
+		}
+	}
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * sis5513_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			config_drive_art_rwp(drive);
+			return config_drive_xfer_rate(drive);
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+
+__initfunc(unsigned int pci_init_sis5513 (struct pci_dev *dev, const char *name))
+{
+	struct pci_dev *host;
+	byte latency = 0, reg48h = 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 &&
+		    host->device == PCI_DEVICE_ID_SI_620) {
+			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;
+		}
+	}
+
+	if (host_dev) {
+		byte reg52h = 0;
+
+		pci_read_config_byte(dev, 0x52, &reg52h);
+		if (!(reg52h & 0x04))
+			pci_write_config_byte(dev, 0x52, reg52h|0x04);
+	}
+
+	return 0;
+}
+
+__initfunc(void ide_init_sis5513 (ide_hwif_t *hwif))
+{
+	byte reg48h = 0;
+	byte mask = hwif->channel ? 0x20 : 0x10;
+
+	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+	hwif->irq = hwif->channel ? 15 : 14;
+
+	if (!(hwif->dma_base))
+		return;
+
+	if (host_dev) {
+		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;
+			default:
+				hwif->autodma = 0;
+				hwif->udma_four = 0;
+				return;
+		}
+	}
+}
diff -u --recursive --new-file v2.3.12/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c
--- v2.3.12/linux/drivers/block/sl82c105.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/sl82c105.c	Thu Aug  5 18:48:45 1999
@@ -1,3 +1,14 @@
+/*
+ * drivers/block/sl82c105.c
+ *
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * Maintainer unknown.
+ *
+ * Drive tuning added from Corel Computer's kernel sources
+ *  -- Russell King (15/11/98) linux@arm.linux.org.uk
+ */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -15,9 +26,108 @@
 
 #include "ide_modes.h"
 
+#ifdef CONFIG_ARCH_NETWINDER
+/*
+ * Convert a PIO mode and cycle time to the required on/off
+ * times for the interface.  This has protection against run-away
+ * timings.
+ */
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+{
+	unsigned int cmd_on;
+	unsigned int cmd_off;
+
+	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+
+	if (cmd_on > 32)
+		cmd_on = 32;
+	if (cmd_on == 0)
+		cmd_on = 1;
+
+	if (cmd_off > 32)
+		cmd_off = 32;
+	if (cmd_off == 0)
+		cmd_off = 1;
+
+	return (cmd_on - 1) << 8 | (cmd_off - 1);
+}
+
+/*
+ * Tell the drive to enable the specified PIO mode.
+ * This should be in ide.c, maybe as a special command
+ * (see do_special).
+ */
+static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (pio > 2) {
+		/* FIXME: I don't believe that this SELECT_DRIVE is required,
+		 * since ide.c only calls tuneproc from do_special, after
+		 * the correct drive has been selected.
+		 */
+		SELECT_DRIVE(hwif, drive);
+		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+		OUT_BYTE(0x08 | pio,  IDE_NSECTOR_REG);
+		OUT_BYTE(0x03, IDE_FEATURE_REG);
+		OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+
+		if (ide_wait_stat(drive, DRIVE_READY,
+				  BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD)) {
+			printk("%s: drive not ready for command\n",
+			       drive->name);
+			return 1;
+		}
+
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+	}
+
+	return 0;
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, byte pio)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	ide_pio_data_t p;
+	unsigned int drv_ctrl = 0x909;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+
+	if (!ide_set_drive_pio_mode(drive, pio)) {
+		drv_ctrl = get_timing_sl82c105(&p);
+
+		if (p.use_iordy)
+			drv_ctrl |= 0x40;
+	}
+
+	pci_write_config_word(dev,
+			      (hwif->channel ? 0x4c : 0x44)
+			       + (drive->select.b.unit ? 4 : 0),
+			      drv_ctrl);
+
+	printk("%s: selected PIO mode %d (%dns)\n",
+		drive->name, p.pio_mode, p.cycle_time);
+}
+#endif
+
 void ide_init_sl82c105(ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
+
+#ifdef CONFIG_ARCH_NETWINDER
+	unsigned char ctrl_stat;
+
+	pci_read_config_byte(dev, 0x40, &ctrl_stat);
+	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+
+	hwif->tuneproc = tune_sl82c105;
+#else
 	unsigned short t16;
 	unsigned int t32;
 	pci_read_config_word(dev, PCI_COMMAND, &t16);
@@ -33,4 +143,5 @@
 	printk("IDE control/status register: %08x\n",t32);
 	pci_write_config_dword(dev, 0x40, 0x10ff08a1);
 #endif /* CONFIG_MBX */
+#endif
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/block/trm290.c linux/drivers/block/trm290.c
--- v2.3.12/linux/drivers/block/trm290.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/trm290.c	Mon Aug  9 10:23:09 1999
@@ -212,7 +212,7 @@
 /*
  * Invoked from ide-dma.c at boot time.
  */
-__initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
+void __init ide_init_trm290 (ide_hwif_t *hwif)
 {
 	unsigned int cfgbase = 0;
 	unsigned long flags;
@@ -220,7 +220,7 @@
 	struct pci_dev *dev = hwif->pci_dev;
 
 	hwif->chipset = ide_trm290;
-	cfgbase = dev->base_address[4];
+	cfgbase = dev->resource[4].start;
 	if ((dev->class & 5) && cfgbase)
 	{
 		hwif->config_data = cfgbase & PCI_BASE_ADDRESS_IO_MASK;
diff -u --recursive --new-file v2.3.12/linux/drivers/block/via82c586.c linux/drivers/block/via82c586.c
--- v2.3.12/linux/drivers/block/via82c586.c	Wed May 26 16:55:40 1999
+++ linux/drivers/block/via82c586.c	Thu Aug  5 18:48:45 1999
@@ -1,8 +1,8 @@
 /*
- * linux/drivers/block/via82c586.c	Version 0.03	Nov. 19, 1998
+ * linux/drivers/block/via82c586.c	Version 0.04	July 11, 1999
  *
  *  Copyright (C) 1998 Michel Aubry, Maintainer
- *  Copyright (C) 1998 Andre Hedrick, Integrater
+ *  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.
@@ -57,6 +57,9 @@
 
 #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)
@@ -438,6 +441,137 @@
 	return 0;
 }
 
+__initfunc(unsigned int 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;
+}
+
+__initfunc(void 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
@@ -464,9 +598,3 @@
 		ide_setup_dma(hwif, dmabase, 8);
 	}
 }
-
-__initfunc(void ide_init_via82c586 (ide_hwif_t *hwif))
-{
-	set_via_timings(hwif);
-}
-
diff -u --recursive --new-file v2.3.12/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.3.12/linux/drivers/block/xd.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/xd.c	Mon Aug  9 10:23:09 1999
@@ -179,7 +179,7 @@
 static int nodma = XD_DONT_USE_DMA;
 
 /* xd_init: register the block device number and set up pointer tables */
-__initfunc(int xd_init (void))
+int __init xd_init (void)
 {
 	if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
 		printk("xd: Unable to get major number %d\n",MAJOR_NR);
@@ -194,7 +194,7 @@
 }
 
 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
-__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address))
+static __init u_char xd_detect (u_char *controller, unsigned int *address)
 {
 	u_char i,j,found = 0;
 
@@ -218,7 +218,7 @@
 
 /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
 /* and set up the "raw" device entries in the table */
-__initfunc(static void xd_geninit (struct gendisk *ignored))
+static void __init xd_geninit (struct gendisk *ignored)
 {
 	u_char i,controller;
 	unsigned int address;
@@ -686,7 +686,7 @@
 	return (csb & CSB_ERROR);
 }
 
-__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive)))
+static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
 {
 	u_char cmdblk[6],i,count = 0;
 
@@ -708,14 +708,14 @@
 	return (count);
 }
 
-__initfunc(static void xd_manual_geo_set (u_char drive))
+static void __init xd_manual_geo_set (u_char drive)
 {
 	xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
 	xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
 	xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
 }
 
-__initfunc(static void xd_dtc_init_controller (unsigned int address))
+static void __init xd_dtc_init_controller (unsigned int address)
 {
 	switch (address) {
 		case 0x00000:
@@ -732,7 +732,7 @@
 }
 
 
-__initfunc(static void xd_dtc5150cx_init_drive (u_char drive))
+static void __init xd_dtc5150cx_init_drive (u_char drive)
 {
 	/* values from controller's BIOS - BIOS chip may be removed */
 	static u_short geometry_table[][4] = {
@@ -779,7 +779,7 @@
 	xd_recalibrate(drive);
 }
 
-__initfunc(static void xd_dtc_init_drive (u_char drive))
+static void __init xd_dtc_init_drive (u_char drive)
 {
 	u_char cmdblk[6],buf[64];
 
@@ -806,7 +806,7 @@
 		printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
 }
 
-__initfunc(static void xd_wd_init_controller (unsigned int address))
+static void __init xd_wd_init_controller (unsigned int address)
 {
 	switch (address) {
 		case 0x00000:
@@ -828,7 +828,7 @@
 	sleep_on(&xdc_wait);
 }
 
-__initfunc(static void xd_wd_init_drive (u_char drive))
+static void __init xd_wd_init_drive (u_char drive)
 {
 	/* values from controller's BIOS - BIOS may be disabled */
 	static u_short geometry_table[][4] = {
@@ -912,7 +912,7 @@
 
 }
 
-__initfunc(static void xd_seagate_init_controller (unsigned int address))
+static void __init xd_seagate_init_controller (unsigned int address)
 {
 	switch (address) {
 		case 0x00000:
@@ -928,7 +928,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-__initfunc(static void xd_seagate_init_drive (u_char drive))
+static void __init xd_seagate_init_drive (u_char drive)
 {
 	u_char cmdblk[6],buf[0x200];
 
@@ -944,7 +944,7 @@
 }
 
 /* Omti support courtesy Dirk Melchers */
-__initfunc(static void xd_omti_init_controller (unsigned int address))
+static void __init xd_omti_init_controller (unsigned int address)
 {
 	switch (address) {
 		case 0x00000:
@@ -961,7 +961,7 @@
 	outb(0,XD_RESET);		/* reset the controller */
 }
 
-__initfunc(static void xd_omti_init_drive (u_char drive))
+static void __init xd_omti_init_drive (u_char drive)
 {
 	/* gets infos from drive */
 	xd_override_init_drive(drive);
@@ -971,7 +971,7 @@
 }
 
 /* Xebec support (AK) */
-__initfunc(static void xd_xebec_init_controller (unsigned int address))
+static void __init xd_xebec_init_controller (unsigned int address)
 {
 /* iobase may be set manually in range 0x300 - 0x33C
       irq may be set manually to 2(9),3,4,5,6,7
@@ -1004,7 +1004,7 @@
 	sleep_on(&xdc_wait);
 }
 
-__initfunc(static void xd_xebec_init_drive (u_char drive))
+static void __init xd_xebec_init_drive (u_char drive)
 {
 	/* values from controller's BIOS - BIOS chip may be removed */
 	static u_short geometry_table[][5] = {
@@ -1047,7 +1047,7 @@
 
 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
-__initfunc(static void xd_override_init_drive (u_char drive))
+static void __init xd_override_init_drive (u_char drive)
 {
 	u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
 	u_char cmdblk[6],i;
@@ -1074,7 +1074,7 @@
 }
 
 /* xd_setup: initialise controler from command line parameters */
-__initfunc(void xd_setup (char *command,int *integers))
+void __init xd_setup (char *command,int *integers)
 {
 	switch (integers[0]) {
 		case 4: if (integers[4] < 0)
@@ -1097,7 +1097,7 @@
 #ifndef MODULE
 /* xd_manual_geo_init: initialise drive geometry from command line parameters
    (used only for WD drives) */
-__initfunc(void xd_manual_geo_init (char *command,int *integers))
+void __init xd_manual_geo_init (char *command,int *integers)
 {
 	int i;
 	if (integers[0]%3 != 0) {
@@ -1110,7 +1110,7 @@
 #endif /* MODULE */
 
 /* xd_setparam: set the drive characteristics */
-__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc))
+static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
 {
 	u_char cmdblk[14];
 
diff -u --recursive --new-file v2.3.12/linux/drivers/block/z2ram.c linux/drivers/block/z2ram.c
--- v2.3.12/linux/drivers/block/z2ram.c	Fri Dec 18 09:36:05 1998
+++ linux/drivers/block/z2ram.c	Mon Aug  9 12:32:28 1999
@@ -32,23 +32,18 @@
 #include <linux/malloc.h>
 #include <linux/blk.h>
 #include <linux/init.h>
-
-#if defined(MODULE)
 #include <linux/module.h>
-#endif
 
 #include <asm/setup.h>
 #include <asm/bitops.h>
 #include <asm/amigahw.h>
-#ifdef CONFIG_APUS
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#endif
 #include <linux/zorro.h>
 
 
-extern int num_memory;
-extern struct mem_info memory[NUM_MEMINFO];
+extern int m68k_realnum_memory;
+extern struct mem_info m68k_memory[NUM_MEMINFO];
 
 #define TRUE                  (1)
 #define FALSE                 (0)
@@ -191,14 +186,14 @@
 		int index = device - Z2MINOR_MEMLIST1 + 1;
 		unsigned long size, paddr, vaddr;
 
-		if (index >= num_memory) {
+		if (index >= m68k_realnum_memory) {
 			printk( KERN_ERR DEVICE_NAME
 				": no such entry in z2ram_map\n" );
 			return -ENOMEM;
 		}
 
-		paddr = memory[index].addr;
-		size = memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
+		paddr = m68k_memory[index].addr;
+		size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
 
 #ifdef __powerpc__
 		/* FIXME: ioremap doesn't build correct memory tables. */
@@ -212,8 +207,7 @@
 						   _PAGE_WRITETHRU);
 
 #else
-		vaddr = kernel_map (paddr, size, KERNELMAP_FULL_CACHING,
-				    NULL);
+		vaddr = (unsigned long)ioremap(paddr, size);
 #endif
 		z2ram_map = 
 			kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]),
@@ -316,9 +310,7 @@
 	blk_size[ MAJOR_NR ] = z2_sizes;
     }
 
-#if defined(MODULE)
     MOD_INC_USE_COUNT;
-#endif
 
     return 0;
 }
@@ -331,9 +323,11 @@
 
     sync_dev( inode->i_rdev );
 
-#if defined(MODULE)
+    /*
+     * FIXME: unmap memory
+     */
+
     MOD_DEC_USE_COUNT;
-#endif
 
     return 0;
 }
@@ -356,8 +350,8 @@
 	NULL,			/* revalidate */
 };
 
-__initfunc(int
-z2_init( void ))
+int __init 
+z2_init( void )
 {
 
     if ( !MACH_IS_AMIGA )
diff -u --recursive --new-file v2.3.12/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.12/linux/drivers/cdrom/cdrom.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/cdrom/cdrom.c	Mon Aug  9 12:34:22 1999
@@ -1,7 +1,7 @@
 /* linux/drivers/cdrom/cdrom.c. 
    Copyright (c) 1996, 1997 David A. van Leeuwen.
    Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org>
-   Copyright (c) 1998, 1999 Jens Axboe
+   Copyright (c) 1998, 1999 Jens Axboe <axboe@image.dk>
 
    May be copied or modified under the terms of the GNU General Public
    License.  See linux/COPYING for more information.
@@ -125,11 +125,44 @@
   -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of
   CDC_CLOSE_TRAY.
   -- proc info didn't mask against capabilities mask.
+  
+  3.00 Aug 5, 1999 - Jens Axboe <axboe@image.dk>
+  -- Unified audio ioctl handling across CD-ROM drivers. A lot of the
+  code was duplicated before. Drives that support the generic packet
+  interface are now being fed packets from here instead.
+  -- First attempt at adding support for MMC2 commands - for DVD and
+  CD-R(W) drives. Only the DVD parts are in now - the interface used is
+  the same as for the audio ioctls.
+  -- ioctl cleanups. if a drive couldn't play audio, it didn't get
+  a change to perform device specific ioctls as well.
+  -- Defined CDROM_CAN(CDC_XXX) for checking the capabilities.
+  -- Put in sysctl files for autoclose, autoeject, check_media, debug,
+  and lock.
+  -- /proc/sys/dev/cdrom/info has been updated to also contain info about
+  CD-Rx and DVD capabilities.
+  -- Now default to checking media type.
+  -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for
+  doing this anyway, with the generic_packet addition.
+  
+  3.01 Aug 6, 1999 - Jens Axboe <axboe@image.dk>
+  -- Fix up the sysctl handling so that the option flags get set
+  correctly.
+  -- Fix up ioctl handling so the device specific ones actually get
+  called :).
+  
+  3.02 Aug 8, 1999 - Jens Axboe <axboe@image.dk>
+  -- Fixed volume control on SCSI drives (or others with longer audio
+  page).
+  -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath
+  <andrewtv@usa.net> for telling me and for having defined the various
+  DVD structures and ioctls in the first place! He designed the original
+  DVD patches for ide-cd and while I rearranged and unified them, the
+  interface is still the same.
 
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 2.55"
-#define VERSION "Id: cdrom.c 2.55 1999/04/25"
+#define REVISION "Revision: 3.02"
+#define VERSION "Id: cdrom.c 3.02 1999/08/08"
 
 /* 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: */
@@ -172,7 +205,7 @@
 static int autoclose=1;
 static int autoeject=0;
 static int lockdoor = 1;
-static int check_media_type = 0;
+static int check_media_type = 1;
 MODULE_PARM(debug, "i");
 MODULE_PARM(autoclose, "i");
 MODULE_PARM(autoeject, "i");
@@ -194,8 +227,12 @@
 #define IOCTL_OUT(arg, type, out) \
 	copy_to_user_ret((type *) arg, &out, sizeof out, -EFAULT)
 
+/* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in
+   a lot of places. This macro makes the code more clear. */
+#define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & type)
 
-#define FM_WRITE	0x2                 /* file mode write bit */
+/* used in the audio ioctls */
+#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
 
 /* Not-exported routines. */
 static int cdrom_open(struct inode *ip, struct file *fp);
@@ -208,6 +245,8 @@
 			 struct cdrom_device_ops * cdo);
 static void sanitize_format(union cdrom_addr *addr, 
 		u_char * curr, u_char requested);
+static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+		     unsigned long arg);
 #ifdef CONFIG_SYSCTL
 static void cdrom_sysctl_register(void);
 #endif /* CONFIG_SYSCTL */ 
@@ -269,13 +308,14 @@
 	ENSURE(reset, CDC_RESET);
 	ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
 	ENSURE(dev_ioctl, CDC_IOCTLS);
+	ENSURE(generic_packet, CDC_GENERIC_PACKET);
 	cdi->mc_flags = 0;
 	cdo->n_minors = 0;
         cdi->options = CDO_USE_FFLAGS;
 	
-	if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
+	if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY))
 		cdi->options |= (int) CDO_AUTO_CLOSE;
-	if (autoeject==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
+	if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY))
 		cdi->options |= (int) CDO_AUTO_EJECT;
 	if (lockdoor==1)
 		cdi->options |= (int) CDO_LOCK;
@@ -347,7 +387,7 @@
 	cdinfo(CD_OPEN, "entering cdrom_open\n"); 
 	if (cdi == NULL)
 		return -ENODEV;
-	if (fp->f_mode & FM_WRITE)
+	if (fp->f_mode & FMODE_WRITE)
 		return -EROFS;
 	purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
 	if (purpose)
@@ -377,7 +417,7 @@
 		if (ret == CDS_TRAY_OPEN) {
 			cdinfo(CD_OPEN, "the tray is open...\n"); 
 			/* can/may i close it? */
-			if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
+			if (CDROM_CAN(CDC_CLOSE_TRAY) &&
 			    cdi->options & CDO_AUTO_CLOSE) {
 				cdinfo(CD_OPEN, "trying to close the tray.\n"); 
 				ret=cdo->tray_move(cdi,0);
@@ -421,6 +461,9 @@
 	 * for example, need bit CDO_CHECK_TYPE cleared! */
 	if (tracks.data==0) {
 		if (cdi->options & CDO_CHECK_TYPE) {
+		    /* give people a warning shot, now that CDO_CHECK_TYPE
+		       is the default case! */
+		    printk("cdrom: pid %d is buggy!\n", (unsigned int)current->pid);
 		    cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
 		    ret=-EMEDIUMTYPE;
 		    goto clean_up_and_return;
@@ -442,8 +485,7 @@
 		cdinfo(CD_OPEN, "open device failed.\n"); 
 		goto clean_up_and_return;
 	}
-	if (cdo->capability & ~cdi->mask & CDC_LOCK && 
-		cdi->options & CDO_LOCK) {
+	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
 			cdo->lock_door(cdi, 1);
 			cdinfo(CD_OPEN, "door locked.\n");
 	}	
@@ -457,8 +499,7 @@
 	is a goto to avoid bloating the driver with redundant code. */ 
 clean_up_and_return:
 	cdinfo(CD_WARNING, "open failed.\n"); 
-	if (cdo->capability & ~cdi->mask & CDC_LOCK && 
-		cdi->options & CDO_LOCK) {
+	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
 			cdo->lock_door(cdi, 0);
 			cdinfo(CD_OPEN, "door unlocked.\n");
 	}
@@ -482,7 +523,7 @@
 		if (ret == CDS_TRAY_OPEN) {
 			cdinfo(CD_OPEN, "the tray is open...\n"); 
 			/* can/may i close it? */
-			if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
+			if (CDROM_CAN(CDC_CLOSE_TRAY) &&
 			    cdi->options & CDO_AUTO_CLOSE) {
 				cdinfo(CD_OPEN, "trying to close the tray.\n"); 
 				ret=cdo->tray_move(cdi,0);
@@ -553,8 +594,7 @@
 		if (sb) invalidate_inodes(sb);
 		invalidate_buffers(dev);
 		if (opened_for_data &&
-		    cdi->options & CDO_AUTO_EJECT &&
-		    cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
+		    cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
 			cdo->tray_move(cdi, 1);
 	}
 	return 0;
@@ -572,7 +612,7 @@
 	unsigned int mask = (1 << (queue & 1));
 	int ret = !!(cdi->mc_flags & mask);
 
-	if (!(cdi->ops->capability & ~cdi->mask & CDC_MEDIA_CHANGED))
+	if (!CDROM_CAN(CDC_MEDIA_CHANGED))
 	    return ret;
 	/* changed since last call? */
 	if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
@@ -594,7 +634,7 @@
 		return 0;
 	if (cdi->ops->media_changed == NULL)
 		return 0;
-	if (!(cdi->ops->capability & ~cdi->mask & CDC_MEDIA_CHANGED))
+	if (!CDROM_CAN(CDC_MEDIA_CHANGED))
 	    return 0;
 	return (media_changed(cdi, 0));
 }
@@ -610,7 +650,7 @@
 	tracks->xa=0;
 	tracks->error=0;
 	cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); 
-        if (!(cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)) { 
+        if (!CDROM_CAN(CDC_PLAY_AUDIO)) { 
                 tracks->error=CDS_NO_INFO;
                 return;
         }        
@@ -684,6 +724,374 @@
 	*curr = requested;
 }
 
+/* DVD handling */
+
+#define copy_key(dest,src)	memcpy((dest), (src), sizeof(dvd_key))
+#define copy_chal(dest,src)	memcpy((dest), (src), sizeof(dvd_challenge))
+
+static void setup_report_key (struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
+{
+	cgc->cmd[0] = DVD_REPORT_KEY;
+	cgc->cmd[10] = type | (agid << 6);
+}
+
+static void setup_send_key (struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
+{
+	cgc->cmd[0] = DVD_SEND_KEY;
+	cgc->cmd[10] = type | (agid << 6);
+}
+
+static int dvd_do_auth (struct cdrom_device_info *cdi, dvd_authinfo *ai)
+{
+	int rv;
+	u_char buf[20];
+	struct cdrom_generic_command cgc;
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(&cgc, 0, sizeof(cgc));
+	memset(buf, 0x93, sizeof(buf));
+	cgc.buffer = buf;
+
+	switch (ai->type) {
+	/* LU data send */
+	case DVD_LU_SEND_AGID:
+		cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_AGID\n"); 
+		setup_report_key (&cgc, 0, 0);
+		cgc.buflen = cgc.cmd[9] = 8;
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+
+		ai->lsa.agid = buf[7] >> 6;
+		/* Returning data, let host change state */
+		break;
+
+	case DVD_LU_SEND_KEY1:
+		cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_KEY1\n"); 
+		setup_report_key (&cgc, ai->lsk.agid, 2);
+		cgc.buflen = cgc.cmd[9] = 12;
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+
+		copy_key(ai->lsk.key, &buf[4]);
+		/* Returning data, let host change state */
+		break;
+
+	case DVD_LU_SEND_CHALLENGE:
+		cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_CHALLENGE\n"); 
+		setup_report_key (&cgc, ai->lsc.agid, 1);
+		cgc.buflen = cgc.cmd[9] = 16;
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+
+		copy_chal(ai->lsc.chal, &buf[4]);
+		/* Returning data, let host change state */
+		break;
+
+	/* Post-auth key */
+	case DVD_LU_SEND_TITLE_KEY:
+		cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_TITLE_KEY\n"); 
+		setup_report_key (&cgc, ai->lstk.agid, 4);
+		cgc.cmd[5] = ai->lstk.lba;
+		cgc.cmd[4] = ai->lstk.lba >> 8;
+		cgc.cmd[3] = ai->lstk.lba >> 16;
+		cgc.cmd[2] = ai->lstk.lba >> 24;
+		cgc.buflen = cgc.cmd[9] = 12;
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+
+		ai->lstk.cpm = (buf[4] >> 7) & 1;
+		ai->lstk.cp_sec = (buf[4] >> 6) & 1;
+		ai->lstk.cgms = (buf[4] >> 4) & 3;
+		copy_key (ai->lstk.title_key, &buf[5]);
+		/* Returning data, let host change state */
+		break;
+
+	case DVD_LU_SEND_ASF:
+		cdinfo(CD_DO_IOCTL, "entering DVD_LU_SEND_ASF\n"); 
+		setup_report_key (&cgc, ai->lsasf.asf, 5);
+		cgc.buflen = cgc.cmd[9] = 8;
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+
+		ai->lsasf.asf = buf[7] & 1;
+		break;
+
+	/* LU data receive (LU changes state) */
+	case DVD_HOST_SEND_CHALLENGE:
+		cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_CHALLENGE\n"); 
+		setup_send_key (&cgc, ai->hsc.agid, 1);
+		cgc.buflen = -(cgc.cmd[9] = 16);
+		buf[1] = 14;
+		copy_chal (&buf[4], ai->hsc.chal);
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+
+		ai->type = DVD_LU_SEND_KEY1;
+		break;
+
+	case DVD_HOST_SEND_KEY2:
+		cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_KEY2\n"); 
+		setup_send_key (&cgc, ai->hsk.agid, 3);
+		cgc.buflen = -(cgc.cmd[9] = 12);
+		buf[1] = 10;
+		copy_key (&buf[4], ai->hsk.key);
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv) {
+			ai->type = DVD_AUTH_FAILURE;
+			return rv;
+		}
+		ai->type = DVD_AUTH_ESTABLISHED;
+		break;
+
+	/* Misc */
+	case DVD_INVALIDATE_AGID:
+		cdinfo(CD_DO_IOCTL, "entering DVD_INVALIDATE_AGID\n"); 
+		setup_report_key (&cgc, ai->lsa.agid, 0x3f);
+
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (rv)
+			return rv;
+		break;
+
+	default:
+		cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static int dvd_read_physical (struct cdrom_device_info *cdi, dvd_struct *s)
+{
+	int rv, i;
+	u_char buf[4 + 4 * 20], *base;
+	struct dvd_layer *layer;
+	struct cdrom_generic_command cgc;
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(buf, 0, sizeof(buf));
+	memset(&cgc, 0, sizeof(cgc));
+	cgc.buffer = buf;
+	cgc.buflen = sizeof(buf);
+	cgc.cmd[0] = DVD_READ_STRUCTURE;
+	cgc.cmd[6] = s->physical.layer_num;
+	cgc.cmd[7] = s->type;
+	cgc.cmd[9] = cgc.buflen & 0xff;
+
+	rv = cdo->generic_packet(cdi, &cgc);
+	if (rv)
+		return rv;
+
+	base = &buf[4];
+	layer = &s->physical.layer[0];
+
+	/* place the data... really ugly, but at least we won't have to
+	   worry about endianess in userspace or here. */
+	for (i = 0; i < 4; ++i, base += 20, ++layer) {
+		memset (layer, 0, sizeof (*layer));
+		layer->book_version = base[0] & 0xf;
+		layer->book_type = base[0] >> 4;
+		layer->min_rate = base[1] & 0xf;
+		layer->disc_size = base[1] >> 4;
+		layer->layer_type = base[2] & 0xf;
+		layer->track_path = (base[2] >> 4) & 1;
+		layer->nlayers = (base[2] >> 5) & 3;
+		layer->track_density = base[3] & 0xf;
+		layer->linear_density = base[3] >> 4;
+		layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
+		layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
+		layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
+		layer->bca = base[16] >> 7;
+	}
+
+	return 0;
+}
+
+static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
+{
+	int rv;
+	u_char buf[8];
+	struct cdrom_generic_command cgc;
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(buf, 0, sizeof(buf));
+	memset(&cgc, 0, sizeof(cgc));
+	cgc.buffer = buf;
+	cgc.buflen = sizeof(buf);
+	cgc.cmd[0] = DVD_READ_STRUCTURE;
+	cgc.cmd[6] = s->copyright.layer_num;
+	cgc.cmd[7] = s->type;
+	cgc.cmd[8] = cgc.buflen >> 8;
+	cgc.cmd[9] = cgc.buflen & 0xff;
+
+	rv = cdo->generic_packet(cdi, &cgc);
+	if (rv)
+		return rv;
+
+	s->copyright.cpst = buf[4];
+	s->copyright.rmi = buf[5];
+
+	return 0;
+}
+
+static int dvd_read_disckey (struct cdrom_device_info *cdi, dvd_struct *s)
+{
+	int rv;
+	u_char buf[4 + 2048];
+	struct cdrom_generic_command cgc;
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(buf, 0, sizeof (buf));
+	memset(&cgc, 0, sizeof (cgc));
+
+	cgc.buffer = buf;
+	cgc.buflen = sizeof(buf);
+	cgc.cmd[0] = DVD_READ_STRUCTURE;
+	cgc.cmd[7] = s->type;
+	cgc.cmd[8] = sizeof(buf) >> 8;
+	cgc.cmd[9] = cgc.buflen & 0xff;
+	cgc.cmd[10] = s->disckey.agid << 6;
+
+	rv = cdo->generic_packet(cdi, &cgc);
+	if (rv)
+		return rv;
+
+	memcpy (s->disckey.value, &buf[4], 2048);
+
+	return 0;
+}
+
+static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
+{
+	int rv;
+	u_char buf[4 + 188];
+	struct cdrom_generic_command cgc;
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(buf, 0, sizeof (buf));
+	memset(&cgc, 0, sizeof (cgc));
+	cgc.buffer = buf;
+	cgc.buflen = sizeof(buf);
+	cgc.cmd[0] = DVD_READ_STRUCTURE;
+	cgc.cmd[7] = s->type;
+	cgc.cmd[9] = cgc.buflen = 0xff;
+
+	rv = cdo->generic_packet(cdi, &cgc);
+	if (rv)
+		return rv;
+
+	s->bca.len = buf[0] << 8 | buf[1];
+	if (s->bca.len < 12 || s->bca.len > 188) {
+		cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len);
+		return -EIO;
+	}
+	memcpy(s->bca.value, &buf[4], s->bca.len);
+
+	return 0;
+}
+
+static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
+{
+	int rv;
+	u_char buf[4 + 2048];
+	struct cdrom_generic_command cgc;
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(buf, 0, sizeof(buf));
+	memset(&cgc, 0, sizeof(cgc));
+	cgc.buffer = buf;
+	cgc.cmd[0] = DVD_READ_STRUCTURE;
+	cgc.cmd[7] = s->type;
+	cgc.buflen = sizeof(buf);
+	cgc.cmd[8] = sizeof(buf) >> 8;
+	cgc.cmd[9] = cgc.buflen & 0xff;
+
+	rv = cdo->generic_packet(cdi, &cgc);
+	if (rv)
+		return rv;
+
+	s->manufact.len = buf[0] << 8 | buf[1];
+	if (s->manufact.len < 0 || s->manufact.len > 2048) {
+		cdinfo(CD_WARNING, "Recieved invalid manufacture info length (%d)\n", s->bca.len);
+		return -EIO;
+	}
+	memcpy(s->manufact.value, &buf[4], s->manufact.len);
+
+	return 0;
+}
+
+static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s)
+{
+	switch (s->type) {
+	case DVD_STRUCT_PHYSICAL:
+		return dvd_read_physical(cdi, s);
+
+	case DVD_STRUCT_COPYRIGHT:
+		return dvd_read_copyright(cdi, s);
+
+	case DVD_STRUCT_DISCKEY:
+		return dvd_read_disckey(cdi, s);
+
+	case DVD_STRUCT_BCA:
+		return dvd_read_bca(cdi, s);
+
+	case DVD_STRUCT_MANUFACT:
+		return dvd_read_manufact(cdi, s);
+		
+	default:
+		cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n",
+					s->type);
+		return -EINVAL;
+	}
+}
+
+static int cdrom_mode_sense(struct cdrom_device_info *cdi,
+			    struct cdrom_generic_command *cgc,
+			    int page_code, int page_control)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(cgc->cmd, 0, sizeof(cgc->cmd));
+
+	cgc->cmd[0] = 0x5a;		/* MODE_SENSE_10 */
+	cgc->cmd[2] = page_code | (page_control << 6);
+	cgc->cmd[7] = cgc->buflen >> 8;
+	cgc->cmd[8] = cgc->buflen & 0xff;
+	return cdo->generic_packet(cdi, cgc);
+}
+
+static int cdrom_mode_select(struct cdrom_device_info *cdi,
+			     struct cdrom_generic_command *cgc)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(cgc->cmd, 0, sizeof(cgc->cmd));
+	
+	cgc->cmd[0] = 0x55;		/* MODE_SELECT_10 */
+	cgc->cmd[1] = 0x10;		/* PF */
+
+	/* generic_packet() wants the length as seen from the drive, i.e.
+	   it will transfer data _to_ us. The CD-ROM wants the absolute
+	   value, however. */
+	cgc->cmd[7] = (-cgc->buflen) >> 8;
+	cgc->cmd[8] = (-cgc->buflen) & 0xff;
+
+	return cdo->generic_packet(cdi, cgc);
+}
+
 /* Some of the cdrom ioctls are not implemented here, because these
  * appear to be either too device-specific, or it is not clear to me
  * what use they are. These are (number of drivers that support them
@@ -704,6 +1112,7 @@
 	kdev_t dev = ip->i_rdev;
 	struct cdrom_device_info *cdi = cdrom_find_device (dev);
 	struct cdrom_device_ops *cdo;
+	int ret;
 
 	if (cdi == NULL)
 		return -ENODEV;
@@ -715,7 +1124,6 @@
 		/* maybe we should order cases after statistics of use? */
 
 	case CDROMMULTISESSION: {
-		int ret;
 		struct cdrom_multisession ms_info;
 		u_char requested_format;
 		cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); 
@@ -737,28 +1145,28 @@
 		}
 
 	case CDROMEJECT: {
-		int ret;
 		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); 
-		if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY))
+		if (!CDROM_CAN(CDC_OPEN_TRAY))
 			return -ENOSYS;
 		if (cdi->use_count != 1 || keeplocked)
 			return -EBUSY;
-		if (cdo->capability & ~cdi->mask & CDC_LOCK)
+		if (CDROM_CAN(CDC_LOCK))
 			if ((ret=cdo->lock_door(cdi, 0)))
 				return ret;
 
 		return cdo->tray_move(cdi, 1);
 		}
 
-	case CDROMCLOSETRAY:
+	case CDROMCLOSETRAY: {
 		cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); 
-		if (!(cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY))
+		if (!CDROM_CAN(CDC_CLOSE_TRAY))
 			return -ENOSYS;
 		return cdo->tray_move(cdi, 0);
+		}
 
-	case CDROMEJECT_SW:
+	case CDROMEJECT_SW: {
 		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 
-		if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY))
+		if (!CDROM_CAN(CDC_OPEN_TRAY))
 			return -ENOSYS;
 		if (keeplocked)
 			return -EBUSY;
@@ -766,13 +1174,13 @@
 		if (arg)
 			cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
 		return 0;
+		}
 
 	case CDROM_MEDIA_CHANGED: {
 		cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 
-		if (!(cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED))
+		if (!CDROM_CAN(CDC_MEDIA_CHANGED))
 			return -ENOSYS;
-		if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
-		    || arg == CDSL_CURRENT)
+		if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
 			/* cannot select disc or select current disc */
 			return media_changed(cdi, 1);
 		if ((unsigned int)arg >= cdi->capacity)
@@ -780,7 +1188,7 @@
 		return cdo->media_changed (cdi, arg);
 		}
 
-	case CDROM_SET_OPTIONS:
+	case CDROM_SET_OPTIONS: {
 		cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 
 		/* options need to be in sync with capability. too late for
 		   that, so we have to check each one separately... */
@@ -789,34 +1197,36 @@
 		case CDO_CHECK_TYPE:
 			break;
 		case CDO_LOCK:
-			if (!(cdo->capability & ~cdi->mask & CDC_LOCK))
+			if (!CDROM_CAN(CDC_LOCK))
 				return -ENOSYS;
 			break;
 		case 0:
 			return cdi->options;
 		/* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
 		default:
-			if (!(cdo->capability & ~cdi->mask & arg))
+			if (!CDROM_CAN(arg))
 				return -ENOSYS;
 		}
 		cdi->options |= (int) arg;
 		return cdi->options;
+		}
 
-	case CDROM_CLEAR_OPTIONS:
+	case CDROM_CLEAR_OPTIONS: {
 		cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); 
 		cdi->options &= ~(int) arg;
 		return cdi->options;
+		}
 
 	case CDROM_SELECT_SPEED: {
 		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 
-		if (!(cdo->capability & ~cdi->mask & CDC_SELECT_SPEED))
+		if (!CDROM_CAN(CDC_SELECT_SPEED))
 			return -ENOSYS;
 		return cdo->select_speed(cdi, arg);
 		}
 
 	case CDROM_SELECT_DISC: {
 		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); 
-		if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC))
+		if (!CDROM_CAN(CDC_SELECT_DISC))
 			return -ENOSYS;
                 if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) 
 			return cdo->select_disc(cdi, arg);
@@ -826,15 +1236,17 @@
 		}
 
 	case CDROMRESET: {
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
 		cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
-		if (!(cdo->capability & ~cdi->mask & CDC_RESET))
+		if (!CDROM_CAN(CDC_RESET))
 			return -ENOSYS;
 		return cdo->reset(cdi);
 		}
 
 	case CDROM_LOCKDOOR: {
-		cdinfo(CD_DO_IOCTL, "%socking door.\n",arg?"L":"Unl");
-		if (!(cdo->capability & ~cdi->mask & CDC_LOCK)) {
+		cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
+		if (!CDROM_CAN(CDC_LOCK)) {
 			return -EDRIVE_CANT_DO_THIS;
 		} else {
 			keeplocked = arg ? 1 : 0;
@@ -845,7 +1257,7 @@
 	case CDROM_DEBUG: {
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
-		cdinfo(CD_DO_IOCTL, "%sabling debug.\n",arg?"En":"Dis");
+		cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
 		debug = arg ? 1 : 0;
 		return debug;
 		}
@@ -861,7 +1273,6 @@
  * is written on the CD is /not/ uniform across all discs!
  */
 	case CDROM_GET_MCN: {
-		int ret;
 		struct cdrom_mcn mcn;
 		cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); 
 		if (!(cdo->capability & CDC_MCN))
@@ -923,144 +1334,263 @@
 		return CDS_NO_INFO;
 		}
 
-	case CDROM_CHANGER_NSLOTS:
+	case CDROM_CHANGER_NSLOTS: {
 		cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); 
-	return cdi->capacity;
+		return cdi->capacity;
+		}
+	}
 
-/* The following is not implemented, because there are too many
- * different data types. We could support /1/ raw mode, that is large
- * enough to hold everything.
- */
+	/* use the ioctls that are implemented through the generic_packet()
+	   interface. this may look at bit funny, but if -ENOTTY is
+	   returned that particular ioctl is not implemented and we
+	   let it go through the device specific ones. */
+	if (CDROM_CAN(CDC_GENERIC_PACKET)) {
+		ret = mmc_ioctl(cdi, cmd, arg);
+		if (ret != -ENOTTY) {
+			return ret;
+		}
+	}
 
-#if 0
-	case CDROMREADMODE1: {
-		int ret;
+	/* note: most of the cdinfo() calls are commented out here,
+	   because they fill up the sys log when CD players poll
+	   the drive. */
+	switch (cmd) {
+	case CDROMSUBCHNL: {
+		struct cdrom_subchnl q;
+		u_char requested, back;
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		/* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 
+		IOCTL_IN(arg, struct cdrom_subchnl, q);
+		requested = q.cdsc_format;
+		if (!((requested == CDROM_MSF) ||
+		      (requested == CDROM_LBA)))
+			return -EINVAL;
+		q.cdsc_format = CDROM_MSF;
+		if ((ret=cdo->audio_ioctl(cdi, cmd, &q)))
+			return ret;
+		back = q.cdsc_format; /* local copy */
+		sanitize_format(&q.cdsc_absaddr, &back, requested);
+		sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
+		IOCTL_OUT(arg, struct cdrom_subchnl, q);
+		/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 
+		return 0;
+		}
+	case CDROMREADTOCHDR: {
+		struct cdrom_tochdr header;
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ 
+		IOCTL_IN(arg, struct cdrom_tochdr, header);
+		if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))
+			return ret;
+		IOCTL_OUT(arg, struct cdrom_tochdr, header);
+		/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ 
+		return 0;
+		}
+	case CDROMREADTOCENTRY: {
+		struct cdrom_tocentry entry;
+		u_char requested_format;
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ 
+		IOCTL_IN(arg, struct cdrom_tocentry, entry);
+		requested_format = entry.cdte_format;
+		if (!((requested_format == CDROM_MSF) || 
+			(requested_format == CDROM_LBA)))
+				return -EINVAL;
+		/* make interface to low-level uniform */
+		entry.cdte_format = CDROM_MSF;
+		if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))
+			return ret;
+		sanitize_format(&entry.cdte_addr,
+		&entry.cdte_format, requested_format);
+		IOCTL_OUT(arg, struct cdrom_tocentry, entry);
+		/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ 
+		return 0;
+		}
+	case CDROMPLAYMSF: {
 		struct cdrom_msf msf;
-		char buf[CD_FRAMESIZE];
-		cdinfo(CD_DO_IOCTL, "entering CDROMREADMODE1\n"); 
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 
 		IOCTL_IN(arg, struct cdrom_msf, msf);
-		if (ret=cdo->read_audio(dev, cmd, &msf, &buf, cdi))
+		CHECKAUDIO;
+		return cdo->audio_ioctl(cdi, cmd, &msf);
+		}
+	case CDROMPLAYTRKIND: {
+		struct cdrom_ti ti;
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); 
+		IOCTL_IN(arg, struct cdrom_ti, ti);
+		CHECKAUDIO;
+		return cdo->audio_ioctl(cdi, cmd, &ti);
+		}
+	case CDROMVOLCTRL: {
+		struct cdrom_volctrl volume;
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); 
+		IOCTL_IN(arg, struct cdrom_volctrl, volume);
+		return cdo->audio_ioctl(cdi, cmd, &volume);
+		}
+	case CDROMVOLREAD: {
+		struct cdrom_volctrl volume;
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); 
+		if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))
 			return ret;
-		IOCTL_OUT(arg, __typeof__(buf), buf);
+		IOCTL_OUT(arg, struct cdrom_volctrl, volume);
 		return 0;
 		}
-#endif
+	case CDROMSTART:
+	case CDROMSTOP:
+	case CDROMPAUSE:
+	case CDROMRESUME: {
+		if (!CDROM_CAN(CDC_PLAY_AUDIO))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); 
+		CHECKAUDIO;
+		return cdo->audio_ioctl(cdi, cmd, NULL);
+		}
 	} /* switch */
 
-/* Now all the audio-ioctls follow, they are all routed through the
-   same call audio_ioctl(). */
+	/* do the device specific ioctls */
+	if (CDROM_CAN(CDC_IOCTLS))
+		return cdo->dev_ioctl(cdi, cmd, arg);
+	
+	return -ENOSYS;
+}
 
-#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
+static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+		     unsigned long arg)
+{		
+	struct cdrom_device_ops *cdo = cdi->ops;
+	struct cdrom_generic_command cgc;
+	int rv;
 
-	if (!(cdo->capability & CDC_PLAY_AUDIO))
-		return -ENOSYS;
-	else {
-		switch (cmd) {
-		case CDROMSUBCHNL: {
-			int ret;
-			struct cdrom_subchnl q;
-			u_char requested, back;
-			/* comment out the cdinfo calls here because they
-			   fill up the sys logs when CD players poll the drive*/
-			/* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 
-			IOCTL_IN(arg, struct cdrom_subchnl, q);
-			requested = q.cdsc_format;
-                        if (!((requested == CDROM_MSF) ||
-                                (requested == CDROM_LBA)))
-                                        return -EINVAL;
-			q.cdsc_format = CDROM_MSF;
-			if ((ret=cdo->audio_ioctl(cdi, cmd, &q)))
-				return ret;
-			back = q.cdsc_format; /* local copy */
-			sanitize_format(&q.cdsc_absaddr, &back, requested);
-			sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
-			IOCTL_OUT(arg, struct cdrom_subchnl, q);
-			/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 
-			return 0;
-			}
-		case CDROMREADTOCHDR: {
-			int ret;
-			struct cdrom_tochdr header;
-			/* comment out the cdinfo calls here because they
-			   fill up the sys logs when CD players poll the drive*/
-			/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ 
-			IOCTL_IN(arg, struct cdrom_tochdr, header);
-			if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))
-				return ret;
-			IOCTL_OUT(arg, struct cdrom_tochdr, header);
-			/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ 
-			return 0;
-			}
-		case CDROMREADTOCENTRY: {
-			int ret;
-			struct cdrom_tocentry entry;
-			u_char requested_format;
-			/* comment out the cdinfo calls here because they
-			   fill up the sys logs when CD players poll the drive*/
-			/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ 
-			IOCTL_IN(arg, struct cdrom_tocentry, entry);
-			requested_format = entry.cdte_format;
-			if (!((requested_format == CDROM_MSF) || 
-				(requested_format == CDROM_LBA)))
-					return -EINVAL;
-			/* make interface to low-level uniform */
-			entry.cdte_format = CDROM_MSF;
-			if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))
-				return ret;
-			sanitize_format(&entry.cdte_addr,
-			&entry.cdte_format, requested_format);
-			IOCTL_OUT(arg, struct cdrom_tocentry, entry);
-			/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ 
+	memset(&cgc, 0, sizeof(cgc));
+
+	/* build a unified command and queue it through
+	   cdo->generic_packet() */
+	switch (cmd) {
+	case CDROMVOLCTRL:
+	case CDROMVOLREAD: {
+		struct cdrom_volctrl volctrl;
+		char buffer[32], mask[32];
+		unsigned short offset;
+		cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
+
+		IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
+
+		cgc.buffer = buffer;
+		cgc.buflen = 24;
+		rv = cdrom_mode_sense(cdi, &cgc, 0xe, 0);
+		if (rv) return rv;
+		
+		/* some drives have longer pages, adjust and reread. */
+		if (buffer[1] > cgc.buflen) {
+			cgc.buflen = buffer[1] + 2;
+			rv = cdrom_mode_sense(cdi, &cgc, 0xe, 0);
+			if (rv) return rv;
+		}
+		
+		/* get the offset from the length of the page. length
+		   is measure from byte 2 an on, thus the 14. */
+		offset = buffer[1] - 14;
+
+		/* now we have the current volume settings. if it was only
+		   a CDROMVOLREAD, return these values */
+		if (cmd == CDROMVOLREAD) {
+			volctrl.channel0 = buffer[offset+9];
+			volctrl.channel1 = buffer[offset+11];
+			volctrl.channel2 = buffer[offset+13];
+			volctrl.channel3 = buffer[offset+15];
+			IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);
 			return 0;
-			}
-		case CDROMPLAYMSF: {
-			int ret;
-			struct cdrom_msf msf;
-			cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 
-			IOCTL_IN(arg, struct cdrom_msf, msf);
-			CHECKAUDIO;
-			return cdo->audio_ioctl(cdi, cmd, &msf);
-			}
-		case CDROMPLAYTRKIND: {
-			int ret;
-			struct cdrom_ti ti;
-			cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); 
-			IOCTL_IN(arg, struct cdrom_ti, ti);
-			CHECKAUDIO;
-			return cdo->audio_ioctl(cdi, cmd, &ti);
-			}
-		case CDROMVOLCTRL: {
-			struct cdrom_volctrl volume;
-			cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); 
-			IOCTL_IN(arg, struct cdrom_volctrl, volume);
-			return cdo->audio_ioctl(cdi, cmd, &volume);
-			}
-		case CDROMVOLREAD: {
-			int ret;
-			struct cdrom_volctrl volume;
-			cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); 
-			if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))
-				return ret;
-			IOCTL_OUT(arg, struct cdrom_volctrl, volume);
+		}
+		
+		/* get the volume mask */
+		cgc.buffer = mask;
+		rv = cdrom_mode_sense(cdi, &cgc, 0xe, 1);
+		if (rv) return rv;
+
+		buffer[offset+9] = volctrl.channel0 & mask[offset+9];
+		buffer[offset+11] = volctrl.channel1 & mask[offset+11];
+		buffer[offset+13] = volctrl.channel2 & mask[offset+13];
+		buffer[offset+15] = volctrl.channel3 & mask[offset+15];
+
+		/* clear the first three */
+		memset(buffer, 0, 3);
+
+		/* set volume */
+		cgc.buflen = -cgc.buflen;
+		cgc.buffer = buffer;
+		return cdrom_mode_select(cdi, &cgc);
+		}
+
+	case CDROMSTART:
+	case CDROMSTOP: {
+		cdinfo(CD_DO_IOCTL, "entering audio ioctl (start/stop)\n"); 
+		cgc.cmd[0] = 0x1b;
+		cgc.cmd[1] = 1;
+		cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
+		return cdo->generic_packet(cdi, &cgc);
+		}
+
+	case CDROMPAUSE:
+	case CDROMRESUME: {
+		cdinfo(CD_DO_IOCTL, "entering audio ioctl (pause/resume)\n"); 
+		cgc.cmd[0] = 0x4b;
+		cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
+		return cdo->generic_packet(cdi, &cgc);
+		}
+	
+	case DVD_READ_STRUCT: {
+		dvd_struct s;
+		if (!CDROM_CAN(CDC_DVD))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering dvd_read_struct\n"); 
+		IOCTL_IN(arg, dvd_struct, s);
+		if ((rv = dvd_read_struct(cdi, &s)) == 0) {
+			IOCTL_OUT(arg, dvd_struct, s);
 			return 0;
-			}
-		case CDROMSTART:
-		case CDROMSTOP:
-		case CDROMPAUSE:
-		case CDROMRESUME: {
-			int ret;
-			cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); 
-			CHECKAUDIO;
-			return cdo->audio_ioctl(cdi, cmd, NULL);
-			}
-		} /* switch */
-	}
+		}
+		return rv;
+		}
 
-	/* device specific ioctls? */
-	if (!(cdo->capability & CDC_IOCTLS))
-		return -ENOSYS;
-	else 
-		return cdo->dev_ioctl(cdi, cmd, arg);
+	case DVD_AUTH: {
+		dvd_authinfo ai;
+		if (!CDROM_CAN(CDC_DVD))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering dvd_auth\n"); 
+		IOCTL_IN(arg, dvd_authinfo, ai);
+		if ((rv = dvd_do_auth (cdi, &ai)))
+			return rv;
+		IOCTL_OUT(arg, dvd_authinfo, ai);
+		return 0;
+		}
+
+	case CDROM_SEND_PACKET: {
+		if (!CDROM_CAN(CDC_GENERIC_PACKET))
+			return -ENOSYS;
+		cdinfo(CD_DO_IOCTL, "entering send_packet\n"); 
+		IOCTL_IN(arg, struct cdrom_generic_command, cgc);
+		cgc.buffer = kmalloc(cgc.buflen, GFP_KERNEL);
+		rv = cdo->generic_packet(cdi, &cgc);
+		if (copy_to_user((void*)arg, cgc.buffer, cgc.buflen)) {
+			kfree(cgc.buffer);
+			return -EFAULT;
+		}
+		kfree(cgc.buffer);
+		return rv;
+		}
+
+	} /* switch */
+
+	return -ENOTTY;
 }
 
 EXPORT_SYMBOL(cdrom_count_tracks);
@@ -1072,90 +1602,197 @@
 
 #define CDROM_STR_SIZE 1000
 
-static char cdrom_drive_info[CDROM_STR_SIZE]="info\n";
+struct cdrom_sysctl_settings {
+	char	info[CDROM_STR_SIZE];	/* general info */
+	int	autoclose;		/* close tray upon mount, etc */
+	int	autoeject;		/* eject on umount */
+	int	debug;			/* turn on debugging messages */
+	int	lock;			/* lock the door on device open */
+	int	check;			/* check media type */
+} cdrom_sysctl_settings;
 
 int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
                            void *buffer, size_t *lenp)
 {
         int pos;
 	struct cdrom_device_info *cdi;
+	char *info = cdrom_sysctl_settings.info;
 	
 	if (!*lenp || (filp->f_pos && !write)) {
 		*lenp = 0;
 		return 0;
 	}
 
-	pos = sprintf(cdrom_drive_info, "CD-ROM information, " VERSION "\n");
+	pos = sprintf(info, "CD-ROM information, " VERSION "\n");
 	
-	pos += sprintf(cdrom_drive_info+pos, "\ndrive name:\t");
+	pos += sprintf(info+pos, "\ndrive name:\t");
+	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+	    pos += sprintf(info+pos, "\t%s", cdi->name);
+
+	pos += sprintf(info+pos, "\ndrive speed:\t");
+	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+	    pos += sprintf(info+pos, "\t%d", cdi->speed);
+
+	pos += sprintf(info+pos, "\ndrive # of slots:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%s", cdi->name);
+	    pos += sprintf(info+pos, "\t%d", cdi->capacity);
 
-	pos += sprintf(cdrom_drive_info+pos, "\ndrive speed:\t");
+	pos += sprintf(info+pos, "\nCan close tray:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->speed);
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\ndrive # of slots:");
+	pos += sprintf(info+pos, "\nCan open tray:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d", cdi->capacity);
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t");
+	pos += sprintf(info+pos, "\nCan lock tray:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-		((cdi->ops->capability & ~cdi->mask & CDC_CLOSE_TRAY)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t");
+	pos += sprintf(info+pos, "\nCan change speed:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-		   ((cdi->ops->capability & ~cdi->mask & CDC_OPEN_TRAY)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t");
+	pos += sprintf(info+pos, "\nCan select disk:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-		   ((cdi->ops->capability & ~cdi->mask & CDC_LOCK)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:");
+	pos += sprintf(info+pos, "\nCan read multisession:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-		   ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_SPEED)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:");
+	pos += sprintf(info+pos, "\nCan read MCN:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-		   ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_DISC)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:");
+	pos += sprintf(info+pos, "\nReports media changed:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_MULTI_SESSION)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan read MCN:\t");
+	pos += sprintf(info+pos, "\nCan play audio:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_MCN)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nReports media changed:");
+	pos += sprintf(info+pos, "\nCan write CD-R:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_MEDIA_CHANGED)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0);
 
-	pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t");
+	pos += sprintf(info+pos, "\nCan write CD-RW:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-		   ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0));
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0);
 
-        strcpy(cdrom_drive_info+pos,"\n\n");
-        pos += 3;
-        if (*lenp > pos)
-        	*lenp = pos;
+	pos += sprintf(info+pos, "\nCan read DVD:\t");
+	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0);
 
+	pos += sprintf(info+pos, "\nCan write DVD-R:");
+	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0);
+
+	pos += sprintf(info+pos, "\nCan write DVD-RAM:");
+	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0);
+
+	strcpy(info+pos,"\n\n");
+		
         return proc_dostring(ctl, write, filp, buffer, lenp);
 }
 
+/* Unfortunately, per device settings are not implemented through
+   procfs/sysctl yet. When they are, this will naturally disappear. For now
+   just update all drives. Later this will become the template on which
+   new registered drives will be based. */
+void cdrom_update_settings(void)
+{
+	struct cdrom_device_info *cdi;
+
+	for (cdi = topCdromPtr; cdi != NULL; cdi = cdi->next) {
+		if (autoclose && CDROM_CAN(CDC_CLOSE_TRAY))
+			cdi->options |= CDO_AUTO_CLOSE;
+		else if (!autoclose)
+			cdi->options &= ~CDO_AUTO_CLOSE;
+		if (autoeject && CDROM_CAN(CDC_OPEN_TRAY))
+			cdi->options |= CDO_AUTO_EJECT;
+		else if (!autoeject)
+			cdi->options &= ~CDO_AUTO_EJECT;
+		if (lockdoor && CDROM_CAN(CDC_LOCK))
+			cdi->options |= CDO_LOCK;
+		else if (!lockdoor)
+			cdi->options &= ~CDO_LOCK;
+		if (check_media_type)
+			cdi->options |= CDO_CHECK_TYPE;
+		else
+			cdi->options &= ~CDO_CHECK_TYPE;
+	}
+}
+
+static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
+				void *buffer, size_t *lenp)
+{
+	int *valp = ctl->data;
+	int val = *valp;
+	int ret;
+	
+	ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+	if (write && *valp != val) {
+	
+		/* we only care for 1 or 0. */
+		if (*valp)
+			*valp = 1;
+		else
+			*valp = 0;
+
+		switch (ctl->ctl_name) {
+		case DEV_CDROM_AUTOCLOSE: {
+			if (valp == &cdrom_sysctl_settings.autoclose)
+				autoclose = cdrom_sysctl_settings.autoclose;
+			break;
+			}
+		case DEV_CDROM_AUTOEJECT: {
+			if (valp == &cdrom_sysctl_settings.autoeject)
+				autoeject = cdrom_sysctl_settings.autoeject;
+			break;
+			}
+		case DEV_CDROM_DEBUG: {
+			if (valp == &cdrom_sysctl_settings.debug)
+				debug = cdrom_sysctl_settings.debug;
+			break;
+			}
+		case DEV_CDROM_LOCK: {
+			if (valp == &cdrom_sysctl_settings.lock)
+				lockdoor = cdrom_sysctl_settings.lock;
+			break;
+			}
+		case DEV_CDROM_CHECK_MEDIA: {
+			if (valp == &cdrom_sysctl_settings.check)
+				check_media_type = cdrom_sysctl_settings.check;
+			break;
+			}
+		}
+		/* update the option flags according to the changes. we
+		   don't have per device options through sysctl yet,
+		   but we will have and then this will disappear. */
+		cdrom_update_settings();
+	}
+
+        return ret;
+}
+
 /* Place files in /proc/sys/dev/cdrom */
 ctl_table cdrom_table[] = {
-	{DEV_CDROM_INFO, "info", &cdrom_drive_info, 
+	{DEV_CDROM_INFO, "info", &cdrom_sysctl_settings.info, 
 		CDROM_STR_SIZE, 0444, NULL, &cdrom_sysctl_info},
+	{DEV_CDROM_AUTOCLOSE, "autoclose", &cdrom_sysctl_settings.autoclose,
+		sizeof(int), 0644, NULL, &cdrom_sysctl_handler },
+	{DEV_CDROM_AUTOEJECT, "autoeject", &cdrom_sysctl_settings.autoeject,
+		sizeof(int), 0644, NULL, &cdrom_sysctl_handler },
+	{DEV_CDROM_DEBUG, "debug", &cdrom_sysctl_settings.debug,
+		sizeof(int), 0644, NULL, &cdrom_sysctl_handler },
+	{DEV_CDROM_LOCK, "lock", &cdrom_sysctl_settings.lock,
+		sizeof(int), 0644, NULL, &cdrom_sysctl_handler },
+	{DEV_CDROM_CHECK_MEDIA, "check_media", &cdrom_sysctl_settings.check,
+		sizeof(int), 0644, NULL, &cdrom_sysctl_handler },
 	{0}
 	};
 
@@ -1198,6 +1835,13 @@
 
 	cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1);
 	cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount;
+
+	/* set the defaults */
+	cdrom_sysctl_settings.autoclose = autoclose;
+	cdrom_sysctl_settings.autoeject = autoeject;
+	cdrom_sysctl_settings.debug = debug;
+	cdrom_sysctl_settings.lock = lockdoor;
+	cdrom_sysctl_settings.check = check_media_type;
 
 	initialized = 1;
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.12/linux/drivers/char/Config.in	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/Config.in	Thu Aug  5 14:47:44 1999
@@ -41,6 +41,7 @@
    if [ "$CONFIG_SPECIALIX" != "n" ]; then
      bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
    fi 
+   tristate 'Specialix SX (and SI) card support' CONFIG_SX
    tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m
@@ -60,18 +61,22 @@
   dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
 
-bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
-if [ "$CONFIG_MOUSE" = "y" ]; then
-	mainmenu_option next_comment
-	comment 'Mice'
-	tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
-	tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
-	tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
+mainmenu_option next_comment
+comment 'Mice'
+tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
+if [ "$CONFIG_BUSMOUSE" != "n" ]; then
+  dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
+  dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
+  dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
+fi
+
+tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
+if [ "$CONFIG_MOUSE" != "n" ]; then
 	bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
 	tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
 	tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
-	endmenu
 fi
+endmenu
 
 tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
 if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
diff -u --recursive --new-file v2.3.12/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.12/linux/drivers/char/Makefile	Wed Jul 28 14:47:42 1999
+++ linux/drivers/char/Makefile	Thu Aug  5 14:47:44 1999
@@ -18,19 +18,19 @@
 #
 FONTMAPFILE = cp437.uni
 
-L_TARGET := char.a
+O_TARGET := char.o
 M_OBJS   :=
-L_OBJS   := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o
-LX_OBJS  := pty.o misc.o
+O_OBJS   := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o
+OX_OBJS  := pty.o misc.o
 
 ifdef CONFIG_VT
-L_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
-LX_OBJS += console.o selection.o
+O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
+OX_OBJS += console.o selection.o
 endif
 
 ifeq ($(CONFIG_SERIAL),y)
   ifeq ($(CONFIG_SUN_SERIAL),)
-  LX_OBJS += serial.o
+  OX_OBJS += serial.o
   endif
 else
   ifeq ($(CONFIG_SERIAL),m)
@@ -42,24 +42,24 @@
 
 ifndef CONFIG_SUN_KEYBOARD
 ifdef CONFIG_VT
-LX_OBJS += keyboard.o
+OX_OBJS += keyboard.o
 endif
  ifneq ($(ARCH),m68k)
-   L_OBJS += pc_keyb.o defkeymap.o
+   O_OBJS += pc_keyb.o defkeymap.o
  endif
 else
 ifdef CONFIG_PCI
-L_OBJS += defkeymap.o
-LX_OBJS += keyboard.o
+O_OBJS += defkeymap.o
+OX_OBJS += keyboard.o
 endif
 endif
 
 ifdef CONFIG_MAGIC_SYSRQ
-LX_OBJS += sysrq.o
+OX_OBJS += sysrq.o
 endif
 
 ifeq ($(CONFIG_ATARI_DSP56K),y)
-L_OBJS += dsp56k.o
+O_OBJS += dsp56k.o
 S = y
 else
   ifeq ($(CONFIG_ATARI_DSP56K),m)
@@ -69,7 +69,7 @@
 endif
 
 ifeq ($(CONFIG_ROCKETPORT),y)
-L_OBJS += rocket.o
+O_OBJS += rocket.o
 else
   ifeq ($(CONFIG_ROCKETPORT),m)
   M_OBJS += rocket.o
@@ -77,7 +77,7 @@
 endif
 
 ifeq ($(CONFIG_DIGI),y)
-L_OBJS += pcxx.o
+O_OBJS += pcxx.o
 else
   ifeq ($(CONFIG_DIGI),m)
   M_OBJS += pcxx.o
@@ -85,7 +85,7 @@
 endif
 
 ifeq ($(CONFIG_DIGIEPCA),y)
-L_OBJS += epca.o
+O_OBJS += epca.o
 else
   ifeq ($(CONFIG_DIGIEPCA),m)
   M_OBJS += epca.o
@@ -93,7 +93,7 @@
 endif
 
 ifeq ($(CONFIG_CYCLADES),y)
-L_OBJS += cyclades.o
+O_OBJS += cyclades.o
 else
   ifeq ($(CONFIG_CYCLADES),m)
   M_OBJS += cyclades.o
@@ -101,7 +101,7 @@
 endif
 
 ifeq ($(CONFIG_STALLION),y)
-L_OBJS += stallion.o
+O_OBJS += stallion.o
 else
   ifeq ($(CONFIG_STALLION),m)
   M_OBJS += stallion.o
@@ -109,7 +109,7 @@
 endif
 
 ifeq ($(CONFIG_ISTALLION),y)
-L_OBJS += istallion.o
+O_OBJS += istallion.o
 else
   ifeq ($(CONFIG_ISTALLION),m)
   M_OBJS += istallion.o
@@ -117,7 +117,7 @@
 endif
 
 ifeq ($(CONFIG_RISCOM8),y)
-L_OBJS += riscom8.o
+O_OBJS += riscom8.o
 else
   ifeq ($(CONFIG_RISCOM8),m)
   M_OBJS += riscom8.o
@@ -125,7 +125,7 @@
 endif
 
 ifeq ($(CONFIG_ISI),y)
-L_OBJS += isicom.o
+O_OBJS += isicom.o
 else
   ifeq ($(CONFIG_ISI),m)
   M_OBJS += isicom.o
@@ -133,7 +133,7 @@
 endif
 
 ifeq ($(CONFIG_ESPSERIAL),y)
-L_OBJS += esp.o
+O_OBJS += esp.o
 else
   ifeq ($(CONFIG_ESPSERIAL),m)
   M_OBJS += esp.o
@@ -149,31 +149,39 @@
 endif
 
 ifeq ($(CONFIG_SPECIALIX),y)
-L_OBJS += specialix.o
+O_OBJS += specialix.o
 else
   ifeq ($(CONFIG_SPECIALIX),m)
   M_OBJS += specialix.o
   endif
 endif
 
+ifeq ($(CONFIG_SX),y)
+L_OBJS += sx.o generic_serial.o
+else
+  ifeq ($(CONFIG_SX),m)
+  M_OBJS += sx.o
+  endif
+endif
+
 ifeq ($(CONFIG_ATIXL_BUSMOUSE),y)
-L_OBJS += atixlmouse.o
+O_OBJS += atixlmouse.o
 else
   ifeq ($(CONFIG_ATIXL_BUSMOUSE),m)
   M_OBJS += atixlmouse.o
   endif
 endif
 
-ifeq ($(CONFIG_BUSMOUSE),y)
-L_OBJS += busmouse.o
+ifeq ($(CONFIG_LOGIBUSMOUSE),y)
+O_OBJS += logibusmouse.o
 else
-  ifeq ($(CONFIG_BUSMOUSE),m)
-  M_OBJS += busmouse.o
+  ifeq ($(CONFIG_LOGIBUSMOUSE),m)
+  M_OBJS += logibusmouse.o
   endif
 endif
 
 ifeq ($(CONFIG_PRINTER),y)
-L_OBJS += lp.o
+O_OBJS += lp.o
 else
   ifeq ($(CONFIG_PRINTER),m)
   M_OBJS += lp.o
@@ -181,7 +189,7 @@
 endif
 
 ifeq ($(CONFIG_JOYSTICK),y)
-L_OBJS += joystick/js.o
+O_OBJS += joystick/js.o
 SUB_DIRS += joystick
 MOD_SUB_DIRS += joystick
 else
@@ -190,8 +198,18 @@
   endif
 endif
 
+ifeq ($(CONFIG_MOUSE),y)
+M = y
+OX_OBJS += busmouse.o
+else
+  ifeq ($(CONFIG_MOUSE),m)
+  MM = m
+  MX_OBJS += busmouse.o
+  endif
+endif
+
 ifeq ($(CONFIG_DTLK),y)
-L_OBJS += dtlk.o
+O_OBJS += dtlk.o
 else
   ifeq ($(CONFIG_DTLK),m)
   M_OBJS += dtlk.o
@@ -199,7 +217,7 @@
 endif
 
 ifeq ($(CONFIG_MS_BUSMOUSE),y)
-L_OBJS += msbusmouse.o
+O_OBJS += msbusmouse.o
 else
   ifeq ($(CONFIG_MS_BUSMOUSE),m)
   M_OBJS += msbusmouse.o
@@ -207,7 +225,7 @@
 endif
 
 ifeq ($(CONFIG_82C710_MOUSE),y)
-L_OBJS += qpmouse.o
+O_OBJS += qpmouse.o
 else
   ifeq ($(CONFIG_82C710_MOUSE),m)
   M_OBJS += qpmouse.o
@@ -215,7 +233,7 @@
 endif
 
 ifeq ($(CONFIG_SOFT_WATCHDOG),y)
-L_OBJS += softdog.o
+O_OBJS += softdog.o
 else
   ifeq ($(CONFIG_SOFT_WATCHDOG),m)
   M_OBJS += softdog.o
@@ -223,7 +241,7 @@
 endif
 
 ifeq ($(CONFIG_PCWATCHDOG),y)
-L_OBJS += pcwd.o
+O_OBJS += pcwd.o
 else
   ifeq ($(CONFIG_PCWATCHDOG),m)
   M_OBJS += pcwd.o
@@ -231,7 +249,7 @@
 endif
 
 ifeq ($(CONFIG_ACQUIRE_WDT),y)
-L_OBJS += acquirewdt.o
+O_OBJS += acquirewdt.o
 else
   ifeq ($(CONFIG_ACQUIRE_WDT),m)
   M_OBJS += acquirewdt.o
@@ -239,7 +257,7 @@
 endif
 
 ifeq ($(CONFIG_AMIGAMOUSE),y)
-L_OBJS += amigamouse.o
+O_OBJS += amigamouse.o
 else
   ifeq ($(CONFIG_AMIGAMOUSE),m)
     M_OBJS += amigamouse.o
@@ -247,7 +265,7 @@
 endif
 
 ifeq ($(CONFIG_ATARIMOUSE),y)
-L_OBJS += atarimouse.o
+O_OBJS += atarimouse.o
 else
   ifeq ($(CONFIG_ATARIMOUSE),m)
     M_OBJS += atarimouse.o
@@ -255,7 +273,7 @@
 endif
 
 ifeq ($(CONFIG_ADBMOUSE),y)
-L_OBJS += adbmouse.o
+O_OBJS += adbmouse.o
 else
   ifeq ($(CONFIG_ADBMOUSE),m)
     M_OBJS += adbmouse.o
@@ -263,7 +281,7 @@
 endif
 
 ifeq ($(CONFIG_PC110_PAD),y)
-L_OBJS += pc110pad.o
+O_OBJS += pc110pad.o
 else
   ifeq ($(CONFIG_PC110_PAD),m)
     M_OBJS += pc110pad.o
@@ -271,7 +289,7 @@
 endif
 
 ifeq ($(CONFIG_WDT),y)
-L_OBJS += wdt.o
+O_OBJS += wdt.o
 else
   ifeq ($(CONFIG_WDT),m)
     M_OBJS += wdt.o
@@ -279,12 +297,12 @@
 endif
 
 ifeq ($(CONFIG_RTC),y)
-L_OBJS += rtc.o
+O_OBJS += rtc.o
 endif
 
 ifeq ($(CONFIG_NVRAM),y)
   ifeq ($(CONFIG_PPC),)
-  L_OBJS += nvram.o
+  O_OBJS += nvram.o
   endif
 else
   ifeq ($(CONFIG_NVRAM),m)
@@ -295,7 +313,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_DEV),y)
-LX_OBJS += videodev.o
+OX_OBJS += videodev.o
 else
   ifeq ($(CONFIG_VIDEO_DEV),m)
     MX_OBJS += videodev.o
@@ -311,7 +329,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BT848),y)
-L_OBJS += bttv.o msp3400.o tuner.o
+O_OBJS += bttv.o msp3400.o tuner.o
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_BT848),m)
@@ -321,7 +339,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_SAA5249),y)
-L_OBJS += saa5249.o
+O_OBJS += saa5249.o
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_SAA5249),m)
@@ -331,7 +349,7 @@
 endif
 
 ifeq ($(CONFIG_I2C_PARPORT),y)
-L_OBJS += i2c-parport.o
+O_OBJS += i2c-parport.o
 L_I2C = y
 else
   ifeq ($(CONFIG_I2C_PARPORT),m)
@@ -341,7 +359,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BWQCAM),y)
-L_OBJS += bw-qcam.o
+O_OBJS += bw-qcam.o
 else
   ifeq ($(CONFIG_VIDEO_BWQCAM),m)
     M_OBJS += bw-qcam.o
@@ -349,7 +367,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_CQCAM),y)
-L_OBJS += c-qcam.o
+O_OBJS += c-qcam.o
 else
   ifeq ($(CONFIG_VIDEO_CQCAM),m)
     M_OBJS += c-qcam.o
@@ -357,7 +375,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_ZORAN),y)
-L_OBJS += buz.o
+O_OBJS += buz.o
 else
   ifeq ($(CONFIG_VIDEO_LML33),m)
     M_OBJS += buz.o
@@ -365,7 +383,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_LML33),y)
-L_OBJS += bt856.o bt819.o
+O_OBJS += bt856.o bt819.o
 else
   ifeq ($(CONFIG_VIDEO_LML33),m)
     M_OBJS += bt856.o bt819.o
@@ -373,7 +391,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BUZ),y)
-L_OBJS += saa7111.o saa7185.o
+O_OBJS += saa7111.o saa7185.o
 else
   ifeq ($(CONFIG_VIDEO_BUZ),m)
     M_OBJS += saa7111.o saa7185.o
@@ -381,7 +399,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_PMS),y)
-L_OBJS += pms.o
+O_OBJS += pms.o
 else
   ifeq ($(CONFIG_VIDEO_PMS),m)
   M_OBJS += pms.o
@@ -389,7 +407,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_PLANB),y)
-L_OBJS += planb.o
+O_OBJS += planb.o
 else
   ifeq ($(CONFIG_VIDEO_PLANB),m)
   M_OBJS += planb.o
@@ -397,7 +415,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_VINO),y)
-L_OBJS += vino.o
+O_OBJS += vino.o
 else
   ifeq ($(CONFIG_VIDEO_VINO),m)
   M_OBJS += vino.o
@@ -405,7 +423,7 @@
 endif
 
 ifeq ($(CONFIG_RADIO_AZTECH),y)
-L_OBJS += radio-aztech.o
+O_OBJS += radio-aztech.o
 else
   ifeq ($(CONFIG_RADIO_AZTECH),m)
   M_OBJS += radio-aztech.o
@@ -413,7 +431,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_SF16FMI),y)
-L_OBJS += radio-sf16fmi.o
+O_OBJS += radio-sf16fmi.o
 else
   ifeq ($(CONFIG_RADIO_SF16FMI),m)
   M_OBJS += radio-sf16fmi.o
@@ -421,7 +439,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_RTRACK),y)
-L_OBJS += radio-aimslab.o
+O_OBJS += radio-aimslab.o
 else
   ifeq ($(CONFIG_RADIO_RTRACK),m)
   M_OBJS += radio-aimslab.o
@@ -429,7 +447,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_RTRACK2),y)
-L_OBJS += radio-rtrack2.o
+O_OBJS += radio-rtrack2.o
 else
   ifeq ($(CONFIG_RADIO_RTRACK2),m)
   M_OBJS += radio-rtrack2.o
@@ -437,7 +455,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_TYPHOON),y)
-L_OBJS += radio-typhoon.o
+O_OBJS += radio-typhoon.o
 else
   ifeq ($(CONFIG_RADIO_TYPHOON),m)
   M_OBJS += radio-typhoon.o
@@ -445,7 +463,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_ZOLTRIX),y)
-L_OBJS += radio-zoltrix.o
+O_OBJS += radio-zoltrix.o
 else
   ifeq ($(CONFIG_RADIO_ZOLTRIX),m)
   M_OBJS += radio-zoltrix.o
@@ -453,7 +471,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_CADET),y)
-L_OBJS += radio-cadet.o
+O_OBJS += radio-cadet.o
 else
   ifeq ($(CONFIG_RADIO_CADET),m)
   M_OBJS += radio-cadet.o
@@ -461,7 +479,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_MIROPCM20),y)
-L_OBJS += radio-miropcm20.o
+O_OBJS += radio-miropcm20.o
 else
   ifeq ($(CONFIG_RADIO_MIROPCM20),m)
   M_OBJS += radio-miropcm20.o
@@ -469,7 +487,7 @@
 endif
 
 ifeq ($(CONFIG_RADIO_GEMTEK),y)
-L_OBJS += radio-gemtek.o
+O_OBJS += radio-gemtek.o
 else
   ifeq ($(CONFIG_RADIO_GEMTEK),m)
   M_OBJS += radio-gemtek.o
@@ -477,7 +495,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_TERRATEC),y)
-L_OBJS += radio-terratec.o
+O_OBJS += radio-terratec.o
 else
   ifeq ($(CONFIG_RADIO_TERRATEC),m)
   M_OBJS += radio-terratec.o
@@ -485,7 +503,7 @@
 endif
 
 ifeq ($(CONFIG_QIC02_TAPE),y)
-L_OBJS += tpqic02.o
+O_OBJS += tpqic02.o
 else
   ifeq ($(CONFIG_QIC02_TAPE),m)
   M_OBJS += tpqic02.o
@@ -493,7 +511,7 @@
 endif
 
 ifeq ($(CONFIG_FTAPE),y)
-L_OBJS       += ftape/ftape.o
+O_OBJS       += ftape/ftape.o
 SUB_DIRS     += ftape
 ifneq ($(CONFIG_ZFTAPE),n)
 MOD_SUB_DIRS += ftape
@@ -505,11 +523,11 @@
 endif
 
 ifdef CONFIG_H8
-LX_OBJS += h8.o
+OX_OBJS += h8.o
 endif
 
 ifeq ($(CONFIG_PPDEV),y)
-L_OBJS += ppdev.o
+O_OBJS += ppdev.o
 else
   ifeq ($(CONFIG_PPDEV),m)
   M_OBJS += ppdev.o
@@ -517,24 +535,11 @@
 endif
 
 ifeq ($(L_I2C),y)
-LX_OBJS += i2c.o
+OX_OBJS += i2c.o
 else
   ifeq ($(M_I2C),y)
   MX_OBJS += i2c.o
   endif
-endif
-
-
-ifeq ($(CONFIG_HFMODEM),y)
-ALL_SUB_DIRS += hfmodem
-SUB_DIRS += hfmodem
-L_OBJS += hfmodem/hfmodem.o
-else
-  ifeq ($(CONFIG_HFMODEM),m)
-  ALL_SUB_DIRS += hfmodem
-  MOD_SUB_DIRS += hfmodem
-  endif
-
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.12/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.3.12/linux/drivers/char/adbmouse.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/char/adbmouse.c	Mon Aug  2 09:54:29 1999
@@ -21,6 +21,9 @@
  * 1996/02/11 Andreas Schwab
  * Module support
  * Allow multiple open's
+ *
+ * Converted to use new generic busmouse code.  11 July 1998
+ *   Russell King <rmk@arm.uk.linux.org>
  */
 
 #include <linux/module.h>
@@ -34,7 +37,6 @@
 #include <linux/init.h>
 
 #include <asm/adb_mouse.h>
-#include <asm/uaccess.h>
 #ifdef __powerpc__
 #include <asm/processor.h>
 #endif
@@ -42,227 +44,129 @@
 #include <asm/setup.h>
 #endif
 
-static struct mouse_status mouse;
+#include "busmouse.h"
+
+static int msedev;
 static unsigned char adb_mouse_buttons[16];
 
 extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
 extern int adb_emulate_buttons;
 extern int adb_button2_keycode;
 extern int adb_button3_keycode;
-
 extern int console_loglevel;
 
 /*
- *	XXX: need to figure out what ADB mouse packets mean ... 
- *	This is the stuff stolen from the Atari driver ...
+ *    XXX: need to figure out what ADB mouse packets mean ... 
+ *      This is the stuff stolen from the Atari driver ...
  */
 static void adb_mouse_interrupt(unsigned char *buf, int nb)
 {
-    int buttons, id;
+	int buttons, id;
+	char dx, dy;
 
-/*
-    Handler 1 -- 100cpi original Apple mouse protocol.
-    Handler 2 -- 200cpi original Apple mouse protocol.
+	/*
+	   Handler 1 -- 100cpi original Apple mouse protocol.
+	   Handler 2 -- 200cpi original Apple mouse protocol.
 
-    For Apple's standard one-button mouse protocol the data array will
-    contain the following values:
+	   For Apple's standard one-button mouse protocol the data array will
+	   contain the following values:
 
-                BITS    COMMENTS
-    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
-    data[1] = bxxx xxxx First button and x-axis motion.
-    data[2] = byyy yyyy Second button and y-axis motion.
-
-    Handler 4 -- Apple Extended mouse protocol.
-
-    For Apple's 3-button mouse protocol the data array will contain the
-    following values:
-
-		BITS    COMMENTS
-    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
-    data[1] = bxxx xxxx Left button and x-axis motion.
-    data[2] = byyy yyyy Second button and y-axis motion.
-    data[3] = byyy bxxx Third button and fourth button.  
-    	      Y is additional high bits of y-axis motion.  
-    	      X is additional high bits of x-axis motion.
-
-    This procedure also gets called from the keyboard code if we
-    are emulating mouse buttons with keys.  In this case data[0] == 0
-    (data[0] cannot be 0 for a real ADB packet).
-
-    'buttons' here means 'button down' states!
-    Button 1 (left)  : bit 2, busmouse button 3
-    Button 2 (middle): bit 1, busmouse button 2
-    Button 3 (right) : bit 0, busmouse button 1
-*/
-
-    /* x/y and buttons swapped */
-    
-    if (console_loglevel >= 8)
-	printk("KERN_DEBUG adb_mouse: %s data; ", buf[0]? "real": "fake"); 
-
-    id = (buf[0] >> 4) & 0xf;
-    buttons = adb_mouse_buttons[id];
-
-    /* button 1 (left, bit 2) */
-    buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
-
-    /* button 2 (middle) */
-    buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
-
-    /* button 3 (right) present?
-     *  on a logitech mouseman, the right and mid buttons sometimes behave
-     *  strangely until they both have been pressed after booting. */
-    /* data valid only if extended mouse format ! */
-    if (nb >= 4)
-	buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
-
-    add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
-
-    adb_mouse_buttons[id] = buttons;
-    /* a button is down if it is down on any mouse */
-    for (id = 0; id < 16; ++id)
-	buttons &= adb_mouse_buttons[id];
-
-    mouse.buttons = buttons;
-    mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 );
-    mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 );
-
-    if (console_loglevel >= 8)
-        printk(" %X %X %X buttons %x dx %d dy %d \n", 
-               buf[1], buf[2], buf[3], mouse.buttons, mouse.dx, mouse.dy);
- 
-    mouse.ready = 1;
-    wake_up_interruptible(&mouse.wait);
-    if (mouse.fasyncptr)
-	kill_fasync(mouse.fasyncptr, SIGIO);
-}
+		       BITS    COMMENTS
+	   data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+	   data[1] = bxxx xxxx First button and x-axis motion.
+	   data[2] = byyy yyyy Second button and y-axis motion.
 
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-	int retval;
+	   Handler 4 -- Apple Extended mouse protocol.
 
-	retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
+	   For Apple's 3-button mouse protocol the data array will contain the
+	   following values:
 
-static int release_mouse(struct inode *inode, struct file *file)
-{
-    fasync_mouse(-1, file, 0);
-    if (--mouse.active)
-      return 0;
-
-    adb_mouse_interrupt_hook = NULL;
-    MOD_DEC_USE_COUNT;
-    return 0;
-}
+		       BITS    COMMENTS
+	   data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+	   data[1] = bxxx xxxx Left button and x-axis motion.
+	   data[2] = byyy yyyy Second button and y-axis motion.
+	   data[3] = byyy bxxx Third button and fourth button.  
+		   Y is additiona. high bits of y-axis motion.  
+		   X is additional high bits of x-axis motion.
 
-static int open_mouse(struct inode *inode, struct file *file)
-{
-    int id;
+	   'buttons' here means 'button down' states!
+	   Button 1 (left)  : bit 2, busmouse button 3
+	   Button 2 (right) : bit 0, busmouse button 1
+	   Button 3 (middle): bit 1, busmouse button 2
+	 */
 
-    if (mouse.active++)
-	return 0;
-	
-    mouse.ready = 0;
+	/* x/y and buttons swapped */
 
-    mouse.dx = mouse.dy = 0;
-    for (id = 0; id < 16; ++id)
-	adb_mouse_buttons[id] = 7;	/* all buttons up */
-    MOD_INC_USE_COUNT;
-    adb_mouse_interrupt_hook = adb_mouse_interrupt;
-    return 0;
-}
+	id = (buf[0] >> 4) & 0xf;
 
-static ssize_t write_mouse(struct file *file, const char *buffer,
-			   size_t count, loff_t *ppos)
-{
-    return -EINVAL;
-}
+	buttons = adb_mouse_buttons[id];
 
-static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
-			  loff_t *ppos)
-{
-    int dx, dy, buttons;
+	/* button 1 (left, bit 2) */
+	buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+
+	/* button 2 (middle) */
+	buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
 
-    if (count < 3)
-	return -EINVAL;
-    if (!mouse.ready)
-	return -EAGAIN;
-    dx = mouse.dx;
-    dy = mouse.dy;
-    buttons = mouse.buttons;
-    if (dx > 127)
-	dx = 127;
-    else if (dx < -128)
-	dx = -128;
-    if (dy > 127)
-	dy = 127;
-    else if (dy < -128)
-	dy = -128;
-    mouse.dx -= dx;
-    mouse.dy -= dy;
-    if (mouse.dx == 0 && mouse.dy == 0)
-	mouse.ready = 0;
-    if (put_user(buttons | 0x80, buffer++) ||
-	put_user((char) dx, buffer++) ||
-	put_user((char) dy, buffer++))
-	return -EFAULT;
-    if (count > 3)
-	if (clear_user(buffer, count - 3))
-	    return -EFAULT;
-    return count;
+	/* button 3 (right) present?
+	 *  on a logitech mouseman, the right and mid buttons sometimes behave
+	 *  strangely until they both have been pressed after booting. */
+	/* data valid only if extended mouse format ! */
+	if (nb >= 4)
+		buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+
+	adb_mouse_buttons[id] = buttons;
+
+	/* a button is down if it is down on any mouse */
+	for (id = 0; id < 16; ++id)
+		buttons &= adb_mouse_buttons[id];
+
+	dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128);
+	dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128);
+	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
+
+	if (console_loglevel >= 8)
+		printk(" %X %X %X dx %d dy %d \n",
+		       buf[1], buf[2], buf[3], dx, dy);
 }
 
-static unsigned int mouse_poll(struct file *file, poll_table *wait)
+static int release_mouse(struct inode *inode, struct file *file)
 {
-	poll_wait(file, &mouse.wait, wait);
-	if (mouse.ready)
-		return POLLIN | POLLRDNORM;
+	adb_mouse_interrupt_hook = NULL;
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-struct file_operations adb_mouse_fops = {
-    NULL,		/* mouse_seek */
-    read_mouse,
-    write_mouse,
-    NULL,		/* mouse_readdir */
-    mouse_poll,
-    NULL,		/* mouse_ioctl */
-    NULL,		/* mouse_mmap */
-    open_mouse,
-    NULL,		/* flush */
-    release_mouse,
-    NULL,
-    fasync_mouse,
-};
-
-#define ADB_MOUSE_MINOR	10
+static int open_mouse(struct inode *inode, struct file *file)
+{
+	MOD_INC_USE_COUNT;
+	adb_mouse_interrupt_hook = adb_mouse_interrupt;
+	return 0;
+}
 
-static struct miscdevice adb_mouse = {
-    ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
+static struct busmouse adb_mouse =
+{
+	ADB_MOUSE_MINOR, "adbmouse", open_mouse, close_mouse, 7
 };
 
 __initfunc(int adb_mouse_init(void))
 {
-    mouse.active = 0;
-    mouse.ready = 0;
-    init_waitqueue_head(&mouse.wait);
-
 #ifdef __powerpc__
-    if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-	    return -ENODEV;
+	if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac))
+		return -ENODEV;
 #endif
 #ifdef __mc68000__
-    if (!MACH_IS_MAC)
-	return -ENODEV;
+	if (!MACH_IS_MAC)
+		return -ENODEV;
 #endif
-    printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
-    misc_register(&adb_mouse);
-    return 0;
-}
 
+	msedev = register_busmouse(&adb_mouse);
+	if (msedev < 0)
+		printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
+	else
+		printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
+
+	return msedev < 0 ? msedev : 0;
+}
 
 /*
  * XXX this function is misnamed.
@@ -286,11 +190,12 @@
 
 int init_module(void)
 {
-    return adb_mouse_init();
+	return adb_mouse_init();
 }
 
 void cleanup_module(void)
 {
-    misc_deregister(&adb_mouse);
+	unregister_busmouse(msedev);
 }
+
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- v2.3.12/linux/drivers/char/amigamouse.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/amigamouse.c	Mon Aug  2 09:54:29 1999
@@ -30,6 +30,9 @@
  * Moved the isr-allocation to the mouse_{open,close} calls, as there
  *   is no reason to service the mouse in the vertical blank isr if
  *   the mouse is not in use.             Jes Sorensen
+ *
+ * Converted to use new generic busmouse code.  5 Apr 1998
+ *   Russell King <rmk@arm.uk.linux.org>
  */
 
 #include <linux/module.h>
@@ -44,7 +47,7 @@
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/busmouse.h>
+#include <linux/logibusmouse.h>
 
 #include <asm/setup.h>
 #include <asm/system.h>
@@ -53,13 +56,15 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 
+#include "busmouse.h"
+
+#if 0
 #define AMI_MSE_INT_ON()	mouseint_allowed = 1
 #define AMI_MSE_INT_OFF()	mouseint_allowed = 0
-
-
-static struct mouse_status mouse;
-
 static int mouseint_allowed;
+#endif
+
+static int msedev;
 
 static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
@@ -70,9 +75,11 @@
 
 	unsigned short joy0dat, potgor;
 
+#if 0
 	if(!mouseint_allowed)
 		return;
 	AMI_MSE_INT_OFF();
+#endif
 
 	/*
 	 *  This routine assumes, just like Kickstart, that the mouse
@@ -128,44 +135,10 @@
 		  (potgor & 0x0400 ? 1 : 0);	/* right button */
 
 
-	if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
-	  add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
-	  mouse.buttons = buttons;
-	  mouse.dx += dx;
-	  mouse.dy -= dy;
-	  mouse.ready = 1;
-	  wake_up_interruptible(&mouse.wait);
-
-	  /*
-	   * keep dx/dy reasonable, but still able to track when X (or
-	   * whatever) must page or is busy (i.e. long waits between
-	   * reads)
-	   */
-	  if (mouse.dx < -2048)
-	      mouse.dx = -2048;
-	  else
-	  if (mouse.dx >  2048)
-	      mouse.dx =  2048;
-
-	  if (mouse.dy < -2048)
-	      mouse.dy = -2048;
-	  else
-	  if (mouse.dy >  2048)
-	      mouse.dy =  2048;
-
-	  if (mouse.fasyncptr)
-	      kill_fasync(mouse.fasyncptr, SIGIO);
-	}
+	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
+#if 0
 	AMI_MSE_INT_ON();
-}
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-	int retval;
-	retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
-	if (retval < 0)
-		return retval;
-	return 0;
+#endif
 }
 
 /*
@@ -174,11 +147,10 @@
 
 static int release_mouse(struct inode * inode, struct file * file)
 {
-	fasync_mouse(-1, file, 0);
-	if (--mouse.active)
-		return 0;
 	free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
+#if 0
 	AMI_MSE_INT_OFF();
+#endif
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -190,123 +162,25 @@
 
 static int open_mouse(struct inode * inode, struct file * file)
 {
-	if (!mouse.present)
-		return -EINVAL;
-	if (mouse.active++)
-		return 0;
 	/*
 	 *  use VBL to poll mouse deltas
 	 */
 
 	if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
 	               "Amiga mouse", mouse_interrupt)) {
-		mouse.present = 0;
 		printk(KERN_INFO "Installing Amiga mouse failed.\n");
 		return -EIO;
 	}
 
-	mouse.ready = 0;
-	mouse.dx = 0;
-	mouse.dy = 0;
-	mouse.buttons = 0x87;
-	mouse.active = 1;
 	MOD_INC_USE_COUNT;
+#if 0
 	AMI_MSE_INT_ON();
+#endif
 	return 0;
 }
 
-/*
- * writes are disallowed
- */
-
-static ssize_t write_mouse(struct file * file, const char * buffer,
-			   size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-/*
- * read mouse data.  Currently never blocks.
- */
-
-static ssize_t read_mouse(struct file * file, char * buffer,
-			  size_t count, loff_t *ppos)
-{
-	int dx;
-	int dy;
-	unsigned char buttons; 
-
-	if (count < 3)
-		return -EINVAL;
-	if (!mouse.ready)
-		return -EAGAIN;
-
-	/*
-	 * Obtain the current mouse parameters and limit as appropriate for
-	 * the return data format.  Interrupts are only disabled while 
-	 * obtaining the parameters, NOT during the puts_user() calls,
-	 * so paging in put_user() does not effect mouse tracking.
-	 */
-
-	AMI_MSE_INT_OFF();
-	dx = mouse.dx;
-	dy = mouse.dy;
-	if (dx < -127)
-	    dx = -127;
-	else
-	if (dx > 127)
-	    dx = 127;
-	if (dy < -127)
-	    dy = -127;
-	else
-	if (dy > 127)
-	    dy = 127;
-	buttons = mouse.buttons;
-	mouse.dx -= dx;
-	mouse.dy -= dy;
-	mouse.ready = 0;
-	AMI_MSE_INT_ON();
-
-	if (put_user(buttons | 0x80, buffer++) ||
-	    put_user((char)dx, buffer++) ||
-	    put_user((char)dy, buffer++))
-		return -EINVAL;
-
-	if (count > 3)
-		if (clear_user(buffer, count - 3))
-			return -EFAULT;
-	return count;
-}
-
-/*
- * poll for mouse input
- */
-
-static unsigned int mouse_poll(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &mouse.wait, wait);
-	if (mouse.ready)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations amiga_mouse_fops = {
-	NULL,		/* mouse_seek */
-	read_mouse,
-	write_mouse,
-	NULL, 		/* mouse_readdir */
-	mouse_poll, 	/* mouse_poll */
-	NULL, 		/* mouse_ioctl */
-	NULL,		/* mouse_mmap */
-	open_mouse,
-	NULL,		/* flush */
-	release_mouse,
-	NULL,
-	fasync_mouse,
-};
-
-static struct miscdevice amiga_mouse = {
-	AMIGAMOUSE_MINOR, "amigamouse", &amiga_mouse_fops
+static struct busmouse amigamouse = {
+	AMIGAMOUSE_MINOR, "amigamouse", open_mouse, release_mouse, 7
 };
 
 int __init amiga_mouse_init(void)
@@ -315,21 +189,15 @@
 		return -ENODEV;
 
 	custom.joytest = 0;	/* reset counters */
-
+#if 0
 	AMI_MSE_INT_OFF();
-
-	mouse.active = 0;
-	mouse.ready = 0;
-	mouse.buttons = 0x87;
-	mouse.dx = 0;
-	mouse.dy = 0;
-	mouse.wait = NULL;
-
-	mouse.present = 1;
-
-	printk(KERN_INFO "Amiga mouse installed.\n");
-	misc_register(&amiga_mouse);
-	return 0;
+#endif
+	msedev = register_busmouse(&amigamouse);
+	if (msedev < 0)
+		printk(KERN_WARNING "Unable to install Amiga mouse driver.\n");
+	else
+		printk(KERN_INFO "Amiga mouse installed.\n");
+	return msedev < 0 ? msedev : 0;
 }
 
 #ifdef MODULE
@@ -341,6 +209,6 @@
 
 void cleanup_module(void)
 {
-	misc_deregister(&amiga_mouse);
+	unregsiter_busmouse(msedev);
 }
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c
--- v2.3.12/linux/drivers/char/amikeyb.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/amikeyb.c	Mon Aug  9 12:32:28 1999
@@ -257,7 +257,7 @@
 	    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
 	    add_timer(&amikeyb_rep_timer);
 	}
-	handle_scancode(scancode, !break_flag);
+	handle_scancode(keycode, !break_flag);
     } else
 	switch (keycode) {
 	    case 0x78:
@@ -340,9 +340,4 @@
     k->rate  = key_repeat_rate  * 1000 / HZ;
     
     return( 0 );
-}
-
-/* for "kbd-reset" cmdline param */
-void __init amiga_kbd_reset_setup(char *str, int *ints)
-{
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v2.3.12/linux/drivers/char/atarimouse.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/atarimouse.c	Mon Aug  2 09:54:29 1999
@@ -10,6 +10,9 @@
  * 1996/02/11 Andreas Schwab
  * Module support
  * Allow multiple open's
+ *
+ * Converted to use new generic busmouse code.  5 Apr 1998
+ *   Russell King <rmk@arm.uk.linux.org>
  */
 
 #include <linux/module.h>
@@ -21,13 +24,15 @@
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/busmouse.h>
+#include <linux/logibusmouse.h>
 
 #include <asm/setup.h>
 #include <asm/atarikb.h>
 #include <asm/uaccess.h>
 
-static struct mouse_status mouse;
+#include "busmouse.h"
+
+static int msedev;
 static int mouse_threshold[2] = {2,2};
 MODULE_PARM(mouse_threshold, "2i");
 extern int atari_mouse_buttons;
@@ -42,32 +47,13 @@
 	       | (buf[0] & 2 ? 4 : 0)
 	       | (atari_mouse_buttons & 2));
     atari_mouse_buttons = buttons;
-    add_mouse_randomness((buttons << 16) + (buf[2] << 8) + buf[1]);
-    mouse.buttons = ~buttons & 7;
-    mouse.dx += buf[1];
-    mouse.dy -= buf[2];
-    mouse.ready = 1;
-    wake_up_interruptible(&mouse.wait);
-    if (mouse.fasyncptr)
-	kill_fasync(mouse.fasyncptr, SIGIO);
 
+    busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons);
 /*    ikbd_mouse_rel_pos(); */
 }
 
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-	int retval;
-	retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
 static int release_mouse(struct inode *inode, struct file *file)
 {
-    fasync_mouse(-1, file, 0);
-    if (--mouse.active)
-      return 0;
     ikbd_mouse_disable();
 
     atari_mouse_interrupt_hook = NULL;
@@ -77,10 +63,6 @@
 
 static int open_mouse(struct inode *inode, struct file *file)
 {
-    if (mouse.active++)
-	return 0;
-    mouse.ready = 0;
-    mouse.dx = mouse.dy = 0;
     atari_mouse_buttons = 0;
     ikbd_mouse_y0_top ();
     ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]);
@@ -90,92 +72,20 @@
     return 0;
 }
 
-static ssize_t write_mouse(struct file *file, const char *buffer,
-			  size_t count, loff_t *ppos)
-{
-    return -EINVAL;
-}
-
-static ssize_t read_mouse(struct file * file, char * buffer,
-			  size_t count, loff_t *ppos)
-{
-    int dx, dy, buttons;
-
-    if (count < 3)
-	return -EINVAL;
-    if (!mouse.ready)
-	return -EAGAIN;
-    /* ikbd_mouse_disable */
-    dx = mouse.dx;
-    dy = mouse.dy;
-    buttons = mouse.buttons;
-    if (dx > 127)
-      dx = 127;
-    else if (dx < -128)
-      dx = -128;
-    if (dy > 127)
-      dy = 127;
-    else if (dy < -128)
-      dy = -128;
-    mouse.dx -= dx;
-    mouse.dy -= dy;
-    if (mouse.dx == 0 && mouse.dy == 0)
-      mouse.ready = 0;
-    /* ikbd_mouse_rel_pos(); */
-    if (put_user(buttons | 0x80, buffer++) ||
-	put_user((char) dx, buffer++) ||
-	put_user((char) dy, buffer++))
-	return -EFAULT;
-    if (count > 3)
-	if (clear_user(buffer, count - 3))
-	    return -EFAULT;
-    return count;
-}
-
-static unsigned int mouse_poll(struct file *file, poll_table *wait)
-{
-	poll_wait(file, &mouse.wait, wait);
-	if (mouse.ready)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations atari_mouse_fops = {
-    NULL,		/* mouse_seek */
-    read_mouse,
-    write_mouse,
-    NULL,		/* mouse_readdir */
-    mouse_poll,
-    NULL,		/* mouse_ioctl */
-    NULL,		/* mouse_mmap */
-    open_mouse,
-    NULL,		/* flush */
-    release_mouse,
-    NULL,
-    fasync_mouse,
-};
-
-static struct miscdevice atari_mouse = {
-    ATARIMOUSE_MINOR, "atarimouse", &atari_mouse_fops
+static struct busmouse atarimouse = {
+	ATARIMOUSE_MINOR, "atarimouse", open_mouse, release_mouse, 0
 };
 
 int __init atari_mouse_init(void)
 {
-	int r;
-
-	if (!MACH_IS_ATARI)
-		return -ENODEV;
-
-	mouse.active = 0;
-	mouse.ready = 0;
-	mouse.wait = NULL;
-
-	r = misc_register(&atari_mouse);
-	if (r)
-		return r;
-
-	printk(KERN_INFO "Atari mouse installed.\n");
-	return 0;
+    if (!MACH_IS_ATARI)
+	return -ENODEV;
+    msedev = register_busmouse(&atarimouse);
+    if (msedev < 0)
+    	printk(KERN_WARNING "Unable to register Atari mouse driver.\n");
+    else
+    	printk(KERN_INFO "Atari mouse installed.\n");
+    return msedev < 0 ? msedev : 0;
 }
 
 
@@ -215,6 +125,6 @@
 
 void cleanup_module(void)
 {
-  misc_deregister(&atari_mouse);
+	unregister_busmouse(msedev);
 }
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v2.3.12/linux/drivers/char/atixlmouse.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/atixlmouse.c	Mon Aug  2 09:54:29 1999
@@ -7,6 +7,9 @@
  * Modified by Chris Colohan (colohan@eecg.toronto.edu)
  * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  *
+ * Converted to use new generic busmouse code.  5 Apr 1998
+ *   Russell King <rmk@arm.uk.linux.org>
+ *
  * version 0.3a
  */
 
@@ -26,6 +29,8 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 
+#include "busmouse.h"
+
 #define ATIXL_MOUSE_IRQ		5 /* H/W interrupt # set up on ATIXL board */
 #define ATIXL_BUSMOUSE		3 /* Minor device # (mknod c 10 3 /dev/bm) */
 
@@ -59,17 +64,7 @@
 
 /* Same general mouse structure */
 
-static struct mouse_status {
-	char buttons;
-	char latch_buttons;
-	int dx;
-	int dy;
-	int present;
-	int ready;
-	int active;
-	wait_queue_head_t wait;
-	struct fasync_struct *fasync;
-} mouse;
+static int msedev;
 
 void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
@@ -82,35 +77,13 @@
 	dy = inb( ATIXL_MSE_DATA_PORT);
 	outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */
 	buttons = inb( ATIXL_MSE_DATA_PORT);
-	if (dx != 0 || dy != 0 || buttons != mouse.latch_buttons) {
-		add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
-		mouse.latch_buttons |= buttons;
-		mouse.dx += dx;
-		mouse.dy += dy;
-		mouse.ready = 1;
-		wake_up_interruptible(&mouse.wait);
-		if (mouse.fasync)
-			kill_fasync(mouse.fasync, SIGIO);
-	}
+	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
 	ATIXL_MSE_ENABLE_UPDATE();
 }
 
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-	int retval;
-	retval = fasync_helper(fd, filp, on, &mouse.fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
 static int release_mouse(struct inode * inode, struct file * file)
 {
-	fasync_mouse(-1, file, 0);
-	if (--mouse.active)
-		return 0;
 	ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
-	mouse.ready = 0;
 	free_irq(ATIXL_MOUSE_IRQ, NULL);
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -118,90 +91,17 @@
 
 static int open_mouse(struct inode * inode, struct file * file)
 {
-	if (!mouse.present)
-		return -EINVAL;
-	if (mouse.active++)
-		return 0;
-	if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) {
-		mouse.active--;
+	if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
 		return -EBUSY;
-	}
-	mouse.ready = 0;
-	mouse.dx = 0;
-	mouse.dy = 0;
-	mouse.buttons = mouse.latch_buttons = 0;
 	ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
 	MOD_INC_USE_COUNT;
 	return 0;
 }
 
-
-static ssize_t write_mouse(struct file * file, const char * buffer,
-       size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-static ssize_t read_mouse(struct file * file, char * buffer,
-       size_t count, loff_t *ppos)
-{
-       ssize_t i;
-
-	if (count < 3)
-		return -EINVAL;
-	if (!mouse.ready)
-		return -EAGAIN;
-	ATIXL_MSE_DISABLE_UPDATE();
-	/* Allowed interrupts to occur during data gathering - shouldn't hurt */
-	put_user((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
-	if (mouse.dx < -127)
-		mouse.dx = -127;
-	if (mouse.dx > 127)
-		mouse.dx =  127;
-	put_user((char)mouse.dx, buffer + 1);
-	if (mouse.dy < -127)
-		mouse.dy = -127;
-	if (mouse.dy > 127)
-		mouse.dy =  127;
-	put_user((char)-mouse.dy, buffer + 2);
-	for(i = 3; i < count; i++)
-		put_user(0x00, buffer + i);
-	mouse.dx = 0;
-	mouse.dy = 0;
-	mouse.latch_buttons = mouse.buttons;
-	mouse.ready = 0;
-	ATIXL_MSE_ENABLE_UPDATE();
-	return i; /* i data bytes returned */
-}
-
-static unsigned int mouse_poll(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &mouse.wait, wait);
-	if (mouse.ready)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations atixl_busmouse_fops = {
-	NULL,		/* mouse_seek */
-	read_mouse,
-	write_mouse,
-	NULL, 		/* mouse_readdir */
-	mouse_poll, 	/* mouse_poll */
-	NULL, 		/* mouse_ioctl */
-	NULL,		/* mouse_mmap */
-	open_mouse,
-	NULL,		/* flush */
-	release_mouse,
-	NULL,
-	fasync_mouse,
+static struct busmouse atixlmouse = {
+	ATIXL_BUSMOUSE, "atixl", open_mouse, release_mouse, 0
 };
 
-static struct miscdevice atixl_mouse = { 
-	ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops
-};
-
-
 int __init atixl_busmouse_init(void)
 {
 	unsigned char a,b,c;
@@ -211,22 +111,18 @@
 	c = inb( ATIXL_MSE_SIGNATURE_PORT );
 	if (( a != b ) && ( a == c ))
 		printk(KERN_INFO "\nATI Inport ");
-	else{
-		mouse.present = 0;
+	else
 		return -EIO;
-	}
 	outb(0x80, ATIXL_MSE_CONTROL_PORT);	/* Reset the Inport device */
 	outb(0x07, ATIXL_MSE_CONTROL_PORT);	/* Select Internal Register 7 */
 	outb(0x0a, ATIXL_MSE_DATA_PORT);	/* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
-	mouse.present = 1;
-	mouse.active = 0;
-	mouse.ready = 0;
-	mouse.buttons = mouse.latch_buttons = 0;
-	mouse.dx = mouse.dy = 0;
-	init_waitqueue_head(&mouse.wait);
-	printk("Bus mouse detected and installed.\n");
-	misc_register(&atixl_mouse);
-	return 0;
+
+	msedev = register_busmouse(&atixlmouse);
+	if (msedev < 0)
+		printk("Bus mouse initialisation error.\n");
+	else
+		printk("Bus mouse detected and installed.\n");
+	return msedev < 0 ? msedev : 0;
 }
 
 #ifdef MODULE
@@ -238,6 +134,6 @@
 
 void cleanup_module(void)
 {
-	misc_deregister(&atixl_mouse);
+	unregister_busmouse(msedev);
 }
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.12/linux/drivers/char/bttv.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/bttv.c	Thu Aug  5 15:04:52 1999
@@ -3538,12 +3538,13 @@
 
         btv->id=dev->device;
         btv->irq=dev->irq;
-        btv->bt848_adr=dev->base_address[0];
+        btv->bt848_adr=dev->resource[0].start;
         if (btv->id >= 878)
                 btv->i2c_command = 0x83;                   
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
+#if 0
         if (remap[bttv_num])
         {
                 unsigned int dw = btv->bt848_adr;
@@ -3558,7 +3559,7 @@
                 pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dw);
                 btv->dev->base_address[0] = btv->bt848_adr;
         }					
-        btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
+#endif        
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
                bttv_num,btv->id, btv->revision);
diff -u --recursive --new-file v2.3.12/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v2.3.12/linux/drivers/char/busmouse.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/busmouse.c	Mon Aug  2 09:54:29 1999
@@ -1,299 +1,484 @@
 /*
- * Logitech Bus Mouse Driver for Linux
- * by James Banks
+ * linux/drivers/char/mouse.c
  *
- * Mods by Matthew Dillon
- *   calls verify_area()
- *   tracks better when X is busy or paging
+ * Copyright (C) 1995 - 1998 Russell King
+ *  Protocol taken from busmouse.c
+ *  read() waiting taken from psaux.c
  *
- * Heavily modified by David Giller
- *   changed from queue- to counter- driven
- *   hacked out a (probably incorrect) mouse_select
+ * Medium-level interface for quadrature or bus mice.
  *
- * Modified again by Nathan Laredo to interface with
- *   0.96c-pl1 IRQ handling changes (13JUL92)
- *   didn't bother touching select code.
+ * Currently, the majority of kernel busmice drivers in the
+ * kernel common code to talk to userspace.  This driver
+ * attempts to rectify this situation by presenting a
+ * simple and safe interface to the mice and user.
  *
- * Modified the select() code blindly to conform to the VFS
- *   requirements. 92.07.14 - Linus. Somebody should test it out.
- *
- * Modified by Johan Myreen to make room for other mice (9AUG92)
- *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
- *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
- *   renamed this file mouse.c => busmouse.c
- *
- * Minor addition by Cliff Matthews
- *   added fasync support
- *
- * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk> 
- *
- * Replaced dumb busy loop with udelay()  16 Nov 95
- *   Nathan Laredo <laredo@gnu.ai.mit.edu>
- *
- * Track I/O ports with request_region().  12 Dec 95 Philip Blundell 
+ * This driver:
+ *  - is SMP safe
+ *  - handles multiple opens
+ *  - handles the wakeups and locking
+ *  - has optional blocking reads
  */
 
 #include <linux/module.h>
-
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/busmouse.h>
 #include <linux/signal.h>
+#include <linux/malloc.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/poll.h>
 #include <linux/miscdevice.h>
 #include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/irq.h>
+#include <asm/io.h>
 
-static struct mouse_status mouse;
-static int mouse_irq = MOUSE_IRQ;
+#include "busmouse.h"
 
-#ifdef MODULE
-MODULE_PARM(mouse_irq, "i");
-#endif
+/* Uncomment this if your mouse drivers expect the kernel to
+ * return with EAGAIN if the mouse does not have any events
+ * available, even if the mouse is opened in nonblocking mode.
+ *
+ * Should this be on a per-mouse basis?  If so, add an entry to
+ * the struct busmouse structure and add the relevent flag to
+ * the drivers.
+ */
+/*#define BROKEN_MOUSE*/
+
+extern int adb_mouse_init(void);
+extern int bus_mouse_init(void);
+extern int ms_bus_mouse_init(void);
+extern int atixl_busmouse_init(void);
+extern int amiga_mouse_init(void);
+extern int atari_mouse_init(void);
+extern int sun_mouse_init(void);
+extern void mouse_rpc_init (void);
+
+struct busmouse_data {
+	struct miscdevice	miscdev;
+	struct busmouse		*ops;
+	spinlock_t		lock;
+
+	wait_queue_head_t	wait;
+	struct fasync_struct	*fasyncptr;
+	char			active;
+	char			buttons;
+	char			latch_buttons;
+	char			ready;
+	int			dxpos;
+	int			dypos;
+};
 
-void __init bmouse_setup(char *str, int *ints)
+#define NR_MICE			15
+#define FIRST_MOUSE		0
+#define DEV_TO_MOUSE(dev)	MINOR_TO_MOUSE(MINOR(dev))
+#define MINOR_TO_MOUSE(minor)	((minor) - FIRST_MOUSE)
+
+static struct busmouse_data *busmouse_data[NR_MICE];
+
+/* a mouse driver just has to interface with these functions
+ *  These are !!!OLD!!!  Do not use!!!
+ */
+void add_mouse_movement(int dx, int dy)
+{
+	struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
+
+	mse->dxpos += dx;
+	mse->dypos += dy;
+	mse->ready = 1;
+	wake_up(&mse->wait);
+}
+
+int add_mouse_buttonchange(int set, int value)
 {
-	if (ints[0] > 0)
-		mouse_irq=ints[1];
+	struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
+
+	mse->buttons = (mse->buttons & ~set) ^ value;
+	mse->ready = 1;
+	wake_up(&mse->wait);
+	return mse->buttons;
 }
 
-static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+/* New interface.  !!! Use this one !!!
+ * These routines will most probably be called from interrupt.
+ */
+void
+busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
 {
-	char dx, dy;
-	unsigned char buttons;
-
-	outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
-	dx = (inb(MSE_DATA_PORT) & 0xf);
-	outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
-	dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
-	outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
-	dy = (inb(MSE_DATA_PORT) & 0xf);
-	outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
-	buttons = inb(MSE_DATA_PORT);
-	dy |= (buttons & 0xf) << 4;
-	buttons = ((buttons >> 5) & 0x07);
-	if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
-	  add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
-	  mouse.buttons = buttons;
-	  mouse.dx += dx;
-	  mouse.dy -= dy;
-	  mouse.ready = 1;
-	  wake_up_interruptible(&mouse.wait);
-
-	  /*
-	   * keep dx/dy reasonable, but still able to track when X (or
-	   * whatever) must page or is busy (i.e. long waits between
-	   * reads)
-	   */
-	  if (mouse.dx < -2048)
-	      mouse.dx = -2048;
-	  if (mouse.dx >  2048)
-	      mouse.dx =  2048;
-
-	  if (mouse.dy < -2048)
-	      mouse.dy = -2048;
-	  if (mouse.dy >  2048)
-	      mouse.dy =  2048;
+	struct busmouse_data *mse = busmouse_data[mousedev];
+	int changed;
+
+	spin_lock(&mse->lock);
+	changed = (dx != 0 || dy != 0 || mse->buttons != buttons);
+
+	if (changed) {
+		add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
+
+		mse->buttons = buttons;
+//		mse->latch_buttons |= buttons;
+		mse->dxpos += dx;
+		mse->dypos += dy;
+		mse->ready = 1;
+
+		/*
+		 * keep dx/dy reasonable, but still able to track when X (or
+		 * whatever) must page or is busy (i.e. long waits between
+		 * reads)
+		 */
+		if (mse->dxpos < -2048)
+			mse->dxpos = -2048;
+		if (mse->dxpos > 2048)
+			mse->dxpos = 2048;
+		if (mse->dypos < -2048)
+			mse->dypos = -2048;
+		if (mse->dypos > 2048)
+			mse->dypos = 2048;
+	}
+
+	spin_unlock(&mse->lock);
+
+	if (changed) {
+		wake_up(&mse->wait);
 
-	  if (mouse.fasyncptr)
-	      kill_fasync(mouse.fasyncptr, SIGIO);
+		if (mse->fasyncptr)
+			kill_fasync(mse->fasyncptr, SIGIO);
 	}
-	MSE_INT_ON();
 }
 
-static int fasync_mouse(int fd, struct file *filp, int on)
+void
+busmouse_add_movement(int mousedev, int dx, int dy)
 {
+	struct busmouse_data *mse = busmouse_data[mousedev];
+
+	busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
+}
+
+void
+busmouse_add_buttons(int mousedev, int clear, int eor)
+{
+	struct busmouse_data *mse = busmouse_data[mousedev];
+
+	busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
+}
+
+static int
+busmouse_fasync(int fd, struct file *filp, int on)
+{
+	struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
 	int retval;
 
-	retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
+	retval = fasync_helper(fd, filp, on, &mse->fasyncptr);
 	if (retval < 0)
 		return retval;
 	return 0;
 }
 
-/*
- * close access to the mouse
- */
-
-static int close_mouse(struct inode * inode, struct file * file)
+static int
+busmouse_release(struct inode *inode, struct file *file)
 {
-	fasync_mouse(-1, file, 0);
-	if (--mouse.active)
-		return 0;
-	MSE_INT_OFF();
-	free_irq(mouse_irq, NULL);
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
+	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
+	int ret = 0;
 
-/*
- * open access to the mouse
- */
+	busmouse_fasync(-1, file, 0);
 
-static int open_mouse(struct inode * inode, struct file * file)
+	if (--mse->active == 0) {
+		if (mse->ops &&
+		    mse->ops->release)
+			ret = mse->ops->release(inode, file);
+
+		mse->ready = 0;
+
+		MOD_DEC_USE_COUNT;
+	}
+
+	return ret;
+}
+
+static int
+busmouse_open(struct inode *inode, struct file *file)
 {
-	if (!mouse.present)
+	struct busmouse_data *mse;
+	unsigned long flags;
+	unsigned int mousedev;
+	int ret = 0;
+
+	mousedev = DEV_TO_MOUSE(inode->i_rdev);
+	if (mousedev >= NR_MICE)
 		return -EINVAL;
-	if (mouse.active++)
+	mse = busmouse_data[mousedev];
+	if (!mse)
+		/* shouldn't happen, but... */
+		return -ENODEV;
+
+	if (mse->ops &&
+	    mse->ops->open)
+		ret = mse->ops->open(inode, file);
+
+	if (ret)
+		return ret;
+
+	file->private_data = mse;
+
+	if (mse->active++)
 		return 0;
-	if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) {
-		mouse.active--;
-		return -EBUSY;
-	}
-	mouse.ready = 0;
-	mouse.dx = 0;
-	mouse.dy = 0;
-	mouse.buttons = 0x87;
+
 	MOD_INC_USE_COUNT;
-	MSE_INT_ON();
+
+	spin_lock_irqsave(&mse->lock, flags);
+
+	mse->ready   = 0;
+	mse->dxpos   = 0;
+	mse->dypos   = 0;
+	if (mse->ops)
+		mse->buttons = mse->ops->init_button_state;
+	else
+		mse->buttons = 7;
+
+	spin_unlock_irqrestore(&mse->lock, flags);
+
 	return 0;
 }
 
-/*
- * writes are disallowed
- */
-
-static ssize_t write_mouse(struct file * file,
-	const char * buffer, size_t count, loff_t *ppos)
+static ssize_t
+busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	return -EINVAL;
 }
 
-/*
- * read mouse data.  Currently never blocks.
- */
-
-static ssize_t read_mouse(struct file * file,
-	char * buffer, size_t count, loff_t *ppos)
+static ssize_t
+busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
-	int r;
-	int dx;
-	int dy;
-	unsigned char buttons; 
-	/* long flags; */
+	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	int dxpos, dypos, buttons;
 
 	if (count < 3)
 		return -EINVAL;
-	if ((r = verify_area(VERIFY_WRITE, buffer, count)))
-		return r;
-	if (!mouse.ready)
+
+	spin_lock_irqsave(&mse->lock, flags);
+
+	if (!mse->ready) {
+#ifdef BROKEN_MOUSE
+		spin_unlock_irqrestore(&mse->lock, flags);
 		return -EAGAIN;
+#else
+		if (file->f_flags & O_NONBLOCK) {
+			spin_unlock_irqrestore(&mse->lock, flags);
+			return -EAGAIN;
+		}
+
+		add_wait_queue(&mse->wait, &wait);
+repeat:
+		current->state = TASK_INTERRUPTIBLE;
+		if (!mse->ready && !signal_pending(current)) {
+			spin_unlock_irqrestore(&mse->lock, flags);
+			schedule();
+			spin_lock_irqsave(&mse->lock, flags);
+			goto repeat;
+		}
+
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&mse->wait, &wait);
+
+		if (signal_pending(current)) {
+			spin_unlock_irqrestore(&mse->lock, flags);
+			return -ERESTARTSYS;
+		}
+#endif
+	}
+
+	dxpos = mse->dxpos;
+	dypos = mse->dypos;
+	buttons = mse->buttons;
+//	mse->latch_buttons = mse->buttons;
+
+	if (dxpos < -127)
+		dxpos =- 127;
+	if (dxpos > 127)
+		dxpos = 127;
+	if (dypos < -127)
+		dypos =- 127;
+	if (dypos > 127)
+		dypos = 127;
+
+	mse->dxpos -= dxpos;
+	mse->dypos -= dypos;
+
+	/* This is something that many drivers have apparantly
+	 * forgotten...  If the X and Y positions still contain
+	 * information, we still have some info ready for the
+	 * user program...
+	 */
+	mse->ready = mse->dxpos || mse->dypos;
+
+	spin_unlock_irqrestore(&mse->lock, flags);
 
-	/*
-	 * Obtain the current mouse parameters and limit as appropriate for
-	 * the return data format.  Interrupts are only disabled while 
-	 * obtaining the parameters, NOT during the puts_fs_byte() calls,
-	 * so paging in put_user() does not effect mouse tracking.
+	/* Write out data to the user.  Format is:
+	 *   byte 0 - identifer (0x80) and (inverted) mouse buttons
+	 *   byte 1 - X delta position +/- 127
+	 *   byte 2 - Y delta position +/- 127
 	 */
+	if (put_user((char)buttons | 128, buffer) ||
+	    put_user((char)dxpos, buffer + 1) ||
+	    put_user((char)dypos, buffer + 2))
+		return -EFAULT;
+
+	if (count > 3 && clear_user(buffer + 3, count - 3))
+		return -EFAULT;
+
+	file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 
-	/* save_flags(flags); cli(); */
-	disable_irq(mouse_irq);
-	dx = mouse.dx;
-	dy = mouse.dy;
-	if (dx < -127)
-	    dx = -127;
-	if (dx > 127)
-	    dx = 127;
-	if (dy < -127)
-	    dy = -127;
-	if (dy > 127)
-	    dy = 127;
-	buttons = mouse.buttons;
-	mouse.dx -= dx;
-	mouse.dy -= dy;
-	mouse.ready = 0;
-	enable_irq(mouse_irq);
-	/* restore_flags(flags); */
-
-	put_user(buttons | 0x80, buffer);
-	put_user((char)dx, buffer + 1);
-	put_user((char)dy, buffer + 2);
-	for (r = 3; r < count; r++)
-	    put_user(0x00, buffer + r);
-	return r;
+	return count;
 }
 
-/*
- * poll for mouse input
- */
-static unsigned int mouse_poll(struct file *file, poll_table * wait)
+static unsigned int
+busmouse_poll(struct file *file, poll_table *wait)
 {
-	poll_wait(file, &mouse.wait, wait);
-	if (mouse.ready)
+	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
+
+	poll_wait(file, &mse->wait, wait);
+
+	if (mse->ready)
 		return POLLIN | POLLRDNORM;
+
 	return 0;
 }
 
-struct file_operations bus_mouse_fops = {
-	NULL,		/* mouse_seek */
-	read_mouse,
-	write_mouse,
-	NULL, 		/* mouse_readdir */
-	mouse_poll, 	/* mouse_poll */
-	NULL, 		/* mouse_ioctl */
-	NULL,		/* mouse_mmap */
-	open_mouse,
-	NULL,		/* flush */
-	close_mouse,
+struct file_operations busmouse_fops=
+{
+	NULL,			/* busmouse_seek */
+	busmouse_read,
+	busmouse_write,
+	NULL,			/* busmouse_readdir */
+	busmouse_poll,
+	NULL,			/* busmouse_ioctl */
+	NULL,			/* busmouse_mmap */
+	busmouse_open,
+	NULL,			/* busmouse_flush */
+	busmouse_release,
 	NULL,
-	fasync_mouse,
+	busmouse_fasync,
 };
 
-static struct miscdevice bus_mouse = {
-	LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
-};
+int
+register_busmouse(struct busmouse *ops)
+{
+	unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
+	struct busmouse_data *mse;
+	int ret;
+
+	if (msedev >= NR_MICE) {
+		printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",
+		       ops->minor);
+		return -EINVAL;
+	}
 
-int __init bus_mouse_init(void)
+	if (busmouse_data[msedev])
+		return -EBUSY;
+
+	mse = kmalloc(GFP_KERNEL, sizeof(*mse));
+	if (!mse)
+		return -ENOMEM;
+
+	memset(mse, 0, sizeof(*mse));
+
+	mse->miscdev.minor = ops->minor;
+	mse->miscdev.name = ops->name;
+	mse->miscdev.fops = &busmouse_fops;
+	mse->ops = ops;
+	mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+	init_waitqueue_head(&mse->wait);
+
+	busmouse_data[msedev] = mse;
+
+	ret = misc_register(&mse->miscdev);
+	if (!ret)
+		ret = msedev;
+
+	return ret;
+}
+
+int
+unregister_busmouse(int mousedev)
 {
-	if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) {
-	  mouse.present = 0;
-	  return -EIO;
+	if (mousedev < 0)
+		return 0;
+	if (mousedev >= NR_MICE) {
+		printk(KERN_ERR "busmouse: trying to free mouse on"
+		       " mousedev %d\n", mousedev);
+		return -EINVAL;
+	}
+
+	if (!busmouse_data[mousedev]) {
+		printk(KERN_WARNING "busmouse: trying to free free mouse"
+		       " on mousedev %d\n", mousedev);
+		return -EINVAL;
 	}
 
-	outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
-	outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
-	udelay(100L);	/* wait for reply from mouse */
-	if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
-		mouse.present = 0;
-		return -EIO;
+	if (busmouse_data[mousedev]->active) {
+		printk(KERN_ERR "busmouse: trying to free active mouse"
+		       " on mousedev %d\n", mousedev);
+		return -EINVAL;
 	}
-	outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
-	MSE_INT_OFF();
-	
-	request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse");
-
-	mouse.present = 1;
-	mouse.active = 0;
-	mouse.ready = 0;
-	mouse.buttons = 0x87;
-	mouse.dx = 0;
-	mouse.dy = 0;
-	init_waitqueue_head(&mouse.wait);
-	printk(KERN_INFO "Logitech bus mouse detected, using IRQ %d.\n",
-	       mouse_irq);
-	misc_register(&bus_mouse);
+
+	misc_deregister(&busmouse_data[mousedev]->miscdev);
+
+	kfree(busmouse_data[mousedev]);
+	busmouse_data[mousedev] = NULL;
 	return 0;
 }
 
-#ifdef MODULE
+__initfunc(int
+bus_mouse_init(void))
+{
+#ifdef CONFIG_BUSMOUSE
+	bus_mouse_init();
+#endif
+#ifdef CONFIG_MS_BUSMOUSE
+	ms_bus_mouse_init();
+#endif
+#ifdef CONFIG_ATIXL_BUSMOUSE
+ 	atixl_busmouse_init();
+#endif
+#ifdef CONFIG_AMIGAMOUSE
+	amiga_mouse_init();
+#endif
+#ifdef CONFIG_ATARIMOUSE
+	atari_mouse_init();
+#endif
+#ifdef CONFIG_MAC_MOUSE
+	mac_mouse_init();
+#endif
+#ifdef CONFIG_SUN_MOUSE
+	sun_mouse_init();
+#endif
+#ifdef CONFIG_ADBMOUSE
+	adb_mouse_init();
+#endif
+#ifdef CONFIG_RPCMOUSE
+	mouse_rpc_init();
+#endif
+	return 0;
+}
+
+EXPORT_SYMBOL(busmouse_add_movement);
+EXPORT_SYMBOL(busmouse_add_buttons);
+EXPORT_SYMBOL(register_busmouse);
+EXPORT_SYMBOL(unregister_busmouse);
 
-int init_module(void)
+#ifdef MODULE
+int
+init_module(void)
 {
 	return bus_mouse_init();
 }
 
-void cleanup_module(void)
+void
+cleanup_module(void)
 {
-	misc_deregister(&bus_mouse);
-	release_region(LOGIBM_BASE, LOGIBM_EXTENT);
 }
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/busmouse.h linux/drivers/char/busmouse.h
--- v2.3.12/linux/drivers/char/busmouse.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/busmouse.h	Mon Aug  2 09:54:29 1999
@@ -0,0 +1,28 @@
+/*
+ * linux/drivers/char/mouse.h
+ *
+ * Copyright (C) 1995 - 1998 Russell King
+ *
+ * Prototypes for generic busmouse interface
+ */
+#ifndef MOUSE_H
+#define MOUSE_H
+
+struct busmouse {
+	int minor;
+	const char *name;
+	int (*open)(struct inode * inode, struct file * file);
+	int (*release)(struct inode * inode, struct file * file);
+	int init_button_state;
+};
+
+extern void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons);
+extern void busmouse_add_movement(int mousedev, int dx, int dy);
+extern void busmouse_add_buttons(int mousedev, int clear, int eor);
+
+extern int register_busmouse(struct busmouse *ops);
+extern int unregister_busmouse(int mousedev);
+
+extern int bus_mouse_init(void);
+
+#endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/buz.c linux/drivers/char/buz.c
--- v2.3.12/linux/drivers/char/buz.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/buz.c	Thu Aug  5 15:04:52 1999
@@ -3219,7 +3219,7 @@
 	}
 	/* i2c */
 	memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus));
-	sprintf(zr->i2c.name, "zoran%u%u", zr->id);
+	sprintf(zr->i2c.name, "zoran%u", zr->id);
 	zr->i2c.data = zr;
 	if (i2c_register_bus(&zr->i2c) < 0) {
 		kfree((void *) zr->stat_com);
@@ -3327,7 +3327,7 @@
 
 		spin_lock_init(&zr->lock);
 
-		zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+		zr->zr36057_adr = zr->pci_dev->resource[0].start;
 		pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
 		if (zr->revision < 2) {
 			printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n",
diff -u --recursive --new-file v2.3.12/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.3.12/linux/drivers/char/cyclades.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/char/cyclades.c	Mon Aug  9 10:23:09 1999
@@ -4874,9 +4874,9 @@
 
                 /* read PCI configuration area */
 		cy_pci_irq = pdev->irq;
-		cy_pci_addr0 = pdev->base_address[0];
-		cy_pci_addr1 = pdev->base_address[1]; 
-		cy_pci_addr2 = pdev->base_address[2]; 
+		cy_pci_addr0 = pdev->resource[0].start;
+		cy_pci_addr1 = pdev->resource[1].start; 
+		cy_pci_addr2 = pdev->resource[2].start; 
                 pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
 
 		device_id &= ~PCI_DEVICE_ID_MASK;
@@ -4891,10 +4891,8 @@
             printk("Cyclom-Y/PCI:found  winaddr=0x%lx ctladdr=0x%lx\n",
 		(ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
 #endif
-		cy_pci_addr0  &= PCI_BASE_ADDRESS_MEM_MASK;
-		cy_pci_addr2  &= PCI_BASE_ADDRESS_MEM_MASK;
 
-		if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+		if (pdev->resource[2].flags & ~PCI_BASE_ADDRESS_IO_MASK) {
 		    printk("  Warning: PCI I/O bit incorrectly set. "
 			   "Ignoring it...\n");
 		    cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
diff -u --recursive --new-file v2.3.12/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c
--- v2.3.12/linux/drivers/char/dn_keyb.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/dn_keyb.c	Mon Aug  9 12:32:28 1999
@@ -55,7 +55,8 @@
 static u_char debug_buf1[4096],debug_buf2[4096],*debug_buf=&debug_buf1[0];
 static u_char *shadow_buf=&debug_buf2[0];
 static short debug_buf_count=0;
-static int debug_buf_overrun=0,debug_timer_running=0,debug_buffer_updated=0;
+static int debug_buf_overrun=0,debug_timer_running=0;
+static unsigned long debug_buffer_updated=0;
 static struct timer_list debug_keyb_timer = { NULL, NULL, 0, 0,
 											  debug_keyb_timer_handler };
 #endif
@@ -280,7 +281,7 @@
 	u_char *swap;
 	short length,i;
 
-	if((jiffies-debug_buffer_updated) > 100) {
+	if (time_after(jiffies, debug_buffer_updated + 100)) {
 		save_flags(flags);
 		cli();
 		length=debug_buf_count;		
@@ -422,7 +423,7 @@
    			!(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
        	   	prev_scancode==DNKEY_RSHIFT || prev_scancode==DNKEY_REPT ||
        	  	prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
-        		if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) {
+			if (time_after(jiffies, lastkeypress + DNKEY_REPEAT_DELAY)) {
 			/*    	printk("handle_scancode: %02x\n",prev_scancode); */
            			handle_scancode(prev_scancode, 1);
 			  	}
@@ -491,8 +492,8 @@
 				debug_buf[debug_buf_count++]=data;
 				debug_buffer_updated=jiffies;	
 				if(!debug_timer_running) {
-					add_timer(&debug_keyb_timer);
 					debug_keyb_timer.expires=jiffies+10;
+					add_timer(&debug_keyb_timer);
 					debug_timer_running=1;
 				}
 			}
diff -u --recursive --new-file v2.3.12/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.3.12/linux/drivers/char/dsp56k.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/dsp56k.c	Mon Aug  9 12:32:28 1999
@@ -534,6 +534,8 @@
 	dsp56k.in_use = 0;
 
 	printk("DSP56k driver installed\n");
+
+	return 0;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.12/linux/drivers/char/epca.c linux/drivers/char/epca.c
--- v2.3.12/linux/drivers/char/epca.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/epca.c	Thu Aug  5 15:04:52 1999
@@ -4049,12 +4049,12 @@
 	if (!dev)
 		return(0);
 
-	*base_addr0 = dev->base_address[0];
-	*base_addr1 = dev->base_address[1];
-	*base_addr2 = dev->base_address[2];
-	*base_addr3 = dev->base_address[3];
-	*base_addr4 = dev->base_address[4];
-	*base_addr5 = dev->base_address[5];
+	*base_addr0 = dev->resource[0].start;
+	*base_addr1 = dev->resource[1].start;
+	*base_addr2 = dev->resource[2].start;
+	*base_addr3 = dev->resource[3].start;
+	*base_addr4 = dev->resource[4].start;
+	*base_addr5 = dev->resource[5].start;
 
 	/* ------------------------------------------------------------------------
 			 NOTE - The code below mask out either the 2 or 4 bits dependent on the
@@ -4063,36 +4063,6 @@
 				their first 4 bits mask out.)  These bits are flag bits and should always
 				be 0 when used as an address.
 	---------------------------------------------------------------------------- */
-
-	if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
-		(*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK;
-	else
-		(*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
-		(*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK;
-	else
-		(*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
-		(*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK;
-	else
-		(*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
-		(*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK;
-	else
-		(*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
-		(*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK;
-	else
-		(*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */
-		(*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK;
-	else
-		(*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK;
 
 	return(1);
 } /* End get_PCI_configuration */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c
--- v2.3.12/linux/drivers/char/generic_serial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/generic_serial.c	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,1074 @@
+/*
+ *  generic_serial.c
+ *
+ *  Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ *  written for the SX serial driver.
+ *     Contains the code that should be shared over all the serial drivers.
+ *
+ *  Credit for the idea to do it this way might go to Alan Cox. 
+ *
+ *
+ *  Version 0.1 -- December, 1998. Initial version.
+ *  Version 0.2 -- March, 1999.    Some more routines. Bugfixes. Etc.
+ *  Version 0.5 -- August, 1999.   Some more fixes. Reformat for Linus.
+ */
+
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/version.h>
+
+
+#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020200   /* less than 2.2.x */
+#warning "Please use a 2.2.x kernel. "
+#else
+#if LINUX_VERSION_CODE < 0x020300   /* less than 2.2.x */
+#define TWO_TWO
+#else
+#define TWO_THREE
+#endif
+#endif
+#endif
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source 
+   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
+   and provide for compatibility stuff here if possible. */
+
+/* Some 200 days (on intel) */
+#define MAX_SCHEDULE_TIMEOUT     ((long)(~0UL>>1))
+
+
+#ifndef MODULE
+
+#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c) 
+{
+	memcpy_fromfs(to, from, c);
+	return 0;
+}
+
+
+#define capable(x)                   suser()
+
+#define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI  -1
+#define ASYNC_SPD_WARP -1
+
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+   to the "name" field that does exist. As long as the assignments are
+   done in the right order, there is nothing to worry about. */
+#define driver_name           name 
+
+
+/* Should be in a header somewhere. */
+#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
+#endif
+
+#endif
+
+#ifndef TWO_ZERO
+/* This include is new with 2.2  (and required!) */
+#include <asm/uaccess.h>
+#endif
+
+#ifndef TWO_THREE
+/* These are new in 2.3. The source now uses 2.3 syntax, and here is 
+   the compatibility define... */
+#define waitq_head_t struct wait_queue *
+#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
+#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
+
+#endif
+
+#include "generic_serial.h"
+
+
+#ifndef MODULE
+extern void my_hd (unsigned char *ptr, int n);
+#endif
+
+static char *                  tmp_buf; 
+static DECLARE_MUTEX(tmp_buf_sem);
+
+int gs_debug = 0;
+
+
+#ifdef DEBUG
+#define gs_dprintk(f, str...) if (gs_debug & f) printk (str)
+#else
+#define gs_dprintk(f, str...) /* nothing */
+#endif
+
+#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
+#define func_exit()  gs_dprintk (SX_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
+
+
+
+#if NEW_WRITE_LOCKING
+#define DECL      /* Nothing */
+#define LOCKIT    down (& port->port_write_sem);
+#define RELEASEIT up (&port->port_write_sem);
+#else
+#define DECL      unsigned long flags;
+#define LOCKIT    save_flags (flags);cli ()
+#define RELEASEIT restore_flags (flags)
+#endif
+
+
+
+void gs_put_char(struct tty_struct * tty, unsigned char ch)
+{
+	struct gs_port *port = tty->driver_data;
+	DECL
+
+	/*  func_enter (); */
+
+	/* Take a lock on the serial tranmit buffer! */
+	LOCKIT;
+
+	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		/* Sorry, buffer is full, drop character. Update statistics???? -- REW */
+		RELEASEIT;
+		return;
+	}
+
+	port->xmit_buf[port->xmit_head++] = ch;
+	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
+	port->xmit_cnt++;  /* Characters in buffer */
+
+	RELEASEIT;
+	/* func_exit ();*/
+}
+
+
+#ifdef NEW_WRITE_LOCKING
+
+/*
+> Problems to take into account are:
+>       -1- Interrupts that empty part of the buffer.
+>       -2- page faults on the access to userspace. 
+>       -3- Other processes that are also trying to do a "write". 
+*/
+
+int gs_write(struct tty_struct * tty, int from_user, 
+                    const unsigned char *buf, int count)
+{
+	struct gs_port *port = tty->driver_data;
+	int c, total = 0;
+	int t;
+
+	/* func_enter (); */
+
+	if (! (port->flags & ASYNC_INITIALIZED))
+		return 0;
+
+	/* get exclusive "write" access to this port (problem 3) */
+	/* This is not a spinlock because we can have a disk access (page 
+		 fault) in copy_from_user */
+	down (& port->port_write_sem);
+
+	while (1) {
+
+		c = count;
+ 
+		/* This is safe because we "OWN" the "head". Noone else can 
+		   change the "head": we own the port_write_sem. */
+		/* Don't overrun the end of the buffer */
+		t = SERIAL_XMIT_SIZE - port->xmit_head;
+		if (t < c) c = t;
+ 
+		/* This is safe because the xmit_cnt can only decrease. This 
+		   would increase "t", so we might copy too little chars. */
+		/* Don't copy past the "head" of the buffer */
+		t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+		if (t < c) c = t;
+ 
+		/* Can't copy more? break out! */
+		if (c <= 0) break;
+		if (from_user)
+			copy_from_user (port->xmit_buf + port->xmit_head, buf, c);
+		else
+			memcpy         (port->xmit_buf + port->xmit_head, buf, c);
+
+		port -> xmit_cnt += c;
+		port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	up (& port->port_write_sem);
+
+	gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", 
+	            (port->flags & GS_TX_INTEN)?"enabled": "disabled"); 
+
+	if (port->xmit_cnt && 
+	    !tty->stopped && 
+	    !tty->hw_stopped &&
+	    !(port->flags & GS_TX_INTEN)) {
+		port->flags |= GS_TX_INTEN;
+		port->rd->enable_tx_interrupts (port);
+	}
+	/* func_exit (); */
+	return total;
+}
+#else
+/*
+> Problems to take into account are:
+>       -1- Interrupts that empty part of the buffer.
+>       -2- page faults on the access to userspace. 
+>       -3- Other processes that are also trying to do a "write". 
+*/
+
+int gs_write(struct tty_struct * tty, int from_user, 
+                    const unsigned char *buf, int count)
+{
+	struct gs_port *port;
+	int c, total = 0;
+	int t;
+	unsigned long flags;
+
+	func_enter ();
+
+	/* The standard serial driver returns 0 in this case. 
+	   That sounds to me as "No error, I just didn't get to writing any
+	   bytes. Feel free to try again." 
+	   The "official" way to write n bytes from buf is:
+
+		 for (nwritten = 0;nwritten < n;nwritten += rv) {
+			 rv = write (fd, buf+nwritten, n-nwritten);
+			 if (rv < 0) break; // Error: bail out. //
+		 } 
+
+	   which will loop endlessly in this case. The manual page for write
+	   agrees with me. In practise almost everybody writes 
+	   "write (fd, buf,n);" but some people might have had to deal with 
+	   incomplete writes in the past and correctly implemented it by now... 
+	 */
+
+	if (!tty) return -EIO;
+
+	port = tty->driver_data;
+	if (!port || !port->xmit_buf || !tmp_buf)
+		return -EIO;
+
+	/* printk ("from_user = %d.\n", from_user); */
+	save_flags(flags);
+	if (from_user) {
+		/* printk ("Going into the semaphore\n"); */
+		down(&tmp_buf_sem);
+		/* printk ("got out of the semaphore\n"); */
+		while (1) {
+			c = count;
+
+			/* This is safe because we "OWN" the "head". Noone else can 
+			   change the "head": we own the port_write_sem. */
+			/* Don't overrun the end of the buffer */
+			t = SERIAL_XMIT_SIZE - port->xmit_head;
+			if (t < c) c = t;
+ 
+			/* This is safe because the xmit_cnt can only decrease. This 
+			   would increase "t", so we might copy too little chars. */
+			/* Don't copy past the "head" of the buffer */
+			t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+			if (t < c) c = t;	 
+
+			/* Can't copy more? break out! */
+			if (c <= 0) break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!total)
+					total = -EFAULT;
+				break;
+			}
+			cli();
+			t = SERIAL_XMIT_SIZE - port->xmit_head;
+			if (t < c) c = t;
+			t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+			if (t < c) c = t;
+
+			memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
+			port->xmit_head = ((port->xmit_head + c) &
+			                   (SERIAL_XMIT_SIZE-1));
+			port->xmit_cnt += c;
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			total += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		while (1) {
+			cli();
+			c = count;
+
+			/* This is safe because we "OWN" the "head". Noone else can 
+			   change the "head": we own the port_write_sem. */
+			/* Don't overrun the end of the buffer */
+			t = SERIAL_XMIT_SIZE - port->xmit_head;
+			if (t < c) c = t;
+ 
+			/* This is safe because the xmit_cnt can only decrease. This 
+			   would increase "t", so we might copy too little chars. */
+			/* Don't copy past the "head" of the buffer */
+			t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+			if (t < c) c = t;
+ 
+			/* Can't copy more? break out! */
+			if (c <= 0) {
+				restore_flags(flags);
+				break;
+			}
+			memcpy(port->xmit_buf + port->xmit_head, buf, c);
+			port->xmit_head = ((port->xmit_head + c) &
+			                   (SERIAL_XMIT_SIZE-1));
+			port->xmit_cnt += c;
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			total += c;
+		}
+	}
+
+	if (port->xmit_cnt && 
+	    !tty->stopped && 
+	    !tty->hw_stopped &&
+	    !(port->flags & GS_TX_INTEN)) {
+		port->flags |= GS_TX_INTEN;
+		port->rd->enable_tx_interrupts (port);
+	}
+	func_exit ();
+	return total;
+}
+
+#endif
+
+
+
+int gs_write_room(struct tty_struct * tty)
+{
+	struct gs_port *port = tty->driver_data;
+	int ret;
+
+	/* func_enter (); */
+	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	/* func_exit (); */
+	return ret;
+}
+
+
+int gs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct gs_port *port = tty->driver_data;
+	func_enter ();
+
+	func_exit ();
+	return port->xmit_cnt;
+}
+
+
+int gs_real_chars_in_buffer(struct tty_struct *tty)
+{
+	struct gs_port *port = tty->driver_data;
+	func_enter ();
+
+	if (!tty) return 0;
+	port = tty->driver_data;
+
+	func_exit ();
+	return port->xmit_cnt + port->rd->chars_in_buffer (port);
+}
+
+
+static void gs_wait_tx_flushed (void * ptr, int timeout) 
+{
+	struct gs_port *port = ptr;
+	long end_jiffies;
+	int jiffies_to_transmit, charsleft;
+	int to, rcib;
+
+	func_enter();
+
+	gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port);
+	if (port) {
+		gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", 
+		port->xmit_cnt, port->xmit_buf, port->tty);
+	}
+
+	if (!port || port->xmit_cnt < 0 || !port->xmit_buf) {
+		gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n");
+	func_exit();
+		return;  /* This is an error which we don't know how to handle. */
+	}
+	gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 1\n");
+
+	rcib = gs_real_chars_in_buffer(port->tty);
+
+	gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 2\n");
+
+	if(rcib <= 0) {
+		gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n");
+	func_exit();
+	return;
+	}
+	gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 3\n");
+
+	/* stop trying: now + twice the time it would normally take +  seconds */
+	end_jiffies  = jiffies; 
+	if (timeout !=  MAX_SCHEDULE_TIMEOUT)
+		end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0;
+	end_jiffies += timeout;
+
+	gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", 
+		    jiffies, end_jiffies, end_jiffies-jiffies); 
+
+	to = 100;
+	/* the expression is actually jiffies < end_jiffies, but that won't
+	   work around the wraparound. Tricky eh? */
+	while (to-- &&
+	       (charsleft = gs_real_chars_in_buffer (port->tty)) &&
+	        time_after (end_jiffies, jiffies)) {
+		/* Units check: 
+		   chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies!
+		   check! */
+
+		charsleft += 16; /* Allow 16 chars more to be transmitted ... */
+		jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0;
+		/*                                ^^^ Round up.... */
+		if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1;
+
+		gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies "
+			    "(%d chars).\n", jiffies_to_transmit, charsleft); 
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(jiffies_to_transmit);
+		if (signal_pending (current))
+			break;
+	}
+
+	gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); 
+	current->state = TASK_RUNNING;
+
+	func_exit();
+}
+
+
+
+void gs_flush_buffer(struct tty_struct *tty)
+{
+	struct gs_port *port = tty->driver_data;
+	unsigned long flags;
+
+	func_enter ();
+	/* XXX Would the write semaphore do? */
+	save_flags(flags); cli();
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	restore_flags(flags);
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+	func_exit ();
+}
+
+
+void gs_flush_chars(struct tty_struct * tty)
+{
+	struct gs_port *port = tty->driver_data;
+
+	func_enter ();
+	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !port->xmit_buf) {
+		func_exit ();
+		return;
+	}
+
+	/* Beats me -- REW */
+	port->flags |= GS_TX_INTEN;
+	port->rd->enable_tx_interrupts (port);
+	func_exit ();
+}
+
+
+void gs_stop(struct tty_struct * tty)
+{
+	struct gs_port *port = tty->driver_data;
+
+	func_enter ();
+	if (port->xmit_cnt && 
+	    port->xmit_buf && 
+	    (port->flags & GS_TX_INTEN) ) {
+		port->flags &= ~GS_TX_INTEN;
+		port->rd->disable_tx_interrupts (port);
+	}
+	func_exit ();
+}
+
+
+void gs_start(struct tty_struct * tty)
+{
+	struct gs_port *port = tty->driver_data;
+
+	if (port->xmit_cnt && 
+	    port->xmit_buf && 
+	    !(port->flags & GS_TX_INTEN) ) {
+		port->flags |= GS_TX_INTEN;
+		port->rd->enable_tx_interrupts (port);
+	}
+	func_exit ();
+}
+
+
+void gs_shutdown_port (struct gs_port *port)
+{
+	long flags;
+
+	if (!(port->flags & ASYNC_INITIALIZED))
+		return;
+
+	save_flags (flags);
+	cli ();
+
+	if (port->xmit_buf) {
+		free_page((unsigned long) port->xmit_buf);
+		port->xmit_buf = 0;
+	}
+
+	if (port->tty)
+		set_bit(TTY_IO_ERROR, &port->tty->flags);
+
+	port->rd->shutdown_port (port);
+
+	port->flags &= ~ASYNC_INITIALIZED;
+	restore_flags (flags);
+}
+
+
+void gs_hangup(struct tty_struct *tty)
+{
+	struct gs_port   *port = tty->driver_data;
+
+	func_enter ();
+
+	tty = port->tty;
+	if (!tty) return;
+
+	gs_shutdown_port (port);
+
+	/* gs_flush_buffer (tty); */
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE);
+	port->tty = NULL;
+	port->count = 0;
+
+	wake_up_interruptible(&port->open_wait);
+	func_exit ();
+}
+
+
+void gs_do_softint(void *private_)
+{
+	struct gs_port *port = private_;
+	struct tty_struct *tty;
+
+	tty = port->tty;
+	if(!tty) return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+	func_exit ();
+}
+
+
+int block_til_ready(void *port_, struct file * filp)
+{
+	struct gs_port *port = port_;
+	DECLARE_WAITQUEUE(wait, current);
+	int    retval;
+	int    do_clocal = 0;
+	int    CD;
+	struct tty_struct *tty;
+
+	func_enter ();
+	tty = port->tty;
+
+	gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n"); 
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+	  interruptible_sleep_on(&port->close_wait);
+		if (port->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+	}
+
+	gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); 
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == GS_TYPE_CALLOUT) {
+		if (port->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (port->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (port->session != current->session))
+			return -EBUSY;
+		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (port->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (port->pgrp != current->pgrp))
+			return -EBUSY;
+		port->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+
+	gs_dprintk (GS_DEBUG_BTR, "after subtype\n");
+
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (port->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		port->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); 
+ 
+	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (port->normal_termios.c_cflag & CLOCAL) 
+			do_clocal = 1;
+	} else {
+		if (C_CLOCAL(tty))
+			do_clocal = 1;
+	}
+
+	gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n"); 
+
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, port->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&port->open_wait, &wait);
+
+	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
+
+	cli();
+	if (!tty_hung_up_p(filp))
+		port->count--;
+	sti();
+	port->blocked_open++;
+	while (1) {
+		CD = port->rd->get_CD (port);
+		gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(port->flags & ASYNC_INITIALIZED)) {
+			if (port->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+			break;
+		}
+		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(port->flags & ASYNC_CLOSING) &&
+		    (do_clocal || CD))
+			break;
+		gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 
+		(int)signal_pending (current), *(long*)(&current->blocked)); 
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
+		    port->blocked_open);
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&port->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		port->count++;
+	port->blocked_open--;
+	if (retval)
+		return retval;
+
+	port->flags |= ASYNC_NORMAL_ACTIVE;
+	func_exit ();
+	return 0;
+}			 
+
+
+void gs_close(struct tty_struct * tty, struct file * filp)
+{
+	unsigned long flags;
+	struct gs_port *port;
+
+	func_enter ();
+	port = (struct gs_port *) tty->driver_data;
+
+	gs_dprintk (GS_DEBUG_CLOSE, "tty=%p, port=%p port->tty=%p\n",
+	            tty, port, port->tty);
+
+	if(! port) {
+		func_exit();
+		return;
+	}
+	if (!port->tty) {
+		printk (KERN_WARNING "gs: Odd: port->tty is NULL\n");
+		port->tty = tty;
+	}
+
+
+	save_flags(flags); cli();
+
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		port->rd->hungup (port);
+		func_exit ();
+		return;
+	}
+
+	if ((tty->count == 1) && (port->count != 1)) {
+		printk(KERN_ERR "gs: gs_close: bad port count;"
+		       " tty->count is 1, port count is %d\n", port->count);
+		port->count = 1;
+	}
+	if (--port->count < 0) {
+		printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count);
+		port->count = 0;
+	}
+	if (port->count) {
+		restore_flags(flags);
+		func_exit ();
+		return;
+	}
+	port->flags |= ASYNC_CLOSING;
+
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (port->flags & ASYNC_NORMAL_ACTIVE)
+		port->normal_termios = *tty->termios;
+	if (port->flags & ASYNC_CALLOUT_ACTIVE)
+		port->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	/* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+	   tty_wait_until_sent(tty, port->closing_wait); */
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	port->rd->disable_rx_interrupts (port);
+
+	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		gs_wait_tx_flushed (port, port->closing_wait); 
+
+	port->flags &= ~GS_ACTIVE;
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	port->event = 0;
+	port->tty = 0;
+	if (port->blocked_open) {
+		if (port->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(port->close_delay);
+		}
+		wake_up_interruptible(&port->open_wait);
+	}
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+	                 ASYNC_CLOSING | ASYNC_INITIALIZED);
+	wake_up_interruptible(&port->close_wait);
+
+	port->rd->close (port);
+	port->rd->shutdown_port (port);
+	restore_flags(flags);
+	func_exit ();
+}
+
+
+static unsigned int     gs_baudrates[] = {
+  0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+  9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+};
+
+
+void gs_set_termios (struct tty_struct * tty, 
+                     struct termios * old_termios)
+{
+	struct gs_port *port = tty->driver_data;
+	int baudrate, tmp;
+	struct termios *tiosp;
+
+	func_enter();
+
+	tiosp = tty->termios;
+
+
+	if (gs_debug & GS_DEBUG_TERMIOS) {
+		gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
+		my_hd ((unsigned char *)tiosp, sizeof (struct termios));
+	}
+
+#if 0
+	/* This is an optimization that is only allowed for dumb cards */
+	/* Smart cards require knowledge of iflags and oflags too: that 
+	   might change hardware cooking mode.... */
+#endif
+	if (old_termios) {
+		if(   (tiosp->c_iflag == old_termios->c_iflag)
+		   && (tiosp->c_oflag == old_termios->c_oflag)
+		   && (tiosp->c_cflag == old_termios->c_cflag)
+		   && (tiosp->c_lflag == old_termios->c_lflag)
+		   && (tiosp->c_line  == old_termios->c_line)
+		   && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) {
+			gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n");
+			return;
+		}
+	} else 
+		gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: "
+		           "no optimization\n");
+
+	if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) {
+		if(tiosp->c_iflag != old_termios->c_iflag)  printk("c_iflag changed\n");
+		if(tiosp->c_oflag != old_termios->c_oflag)  printk("c_oflag changed\n");
+		if(tiosp->c_cflag != old_termios->c_cflag)  printk("c_cflag changed\n");
+		if(tiosp->c_lflag != old_termios->c_lflag)  printk("c_lflag changed\n");
+		if(tiosp->c_line  != old_termios->c_line)   printk("c_line changed\n");
+		if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
+	}
+
+	baudrate = tiosp->c_cflag & CBAUD;
+	if (baudrate & CBAUDEX) {
+		baudrate &= ~CBAUDEX;
+		if ((baudrate < 1) || (baudrate > 4))
+			tiosp->c_cflag &= ~CBAUDEX;
+		else
+			baudrate += 15;
+	}
+
+	baudrate = gs_baudrates[baudrate];
+	if ((tiosp->c_cflag & CBAUD) == B38400) {
+		if (     (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			baudrate = 57600;
+		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			baudrate = 115200;
+		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			baudrate = 230400;
+		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			baudrate = 460800;
+		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+			baudrate = (port->baud_base / port->custom_divisor);
+	}
+
+	/* I recommend using THIS instead of the mess in termios (and
+	   duplicating the above code). Next we should create a clean
+	   interface towards this variable. If your card supports arbitrary
+	   baud rates, (e.g. CD1400 or 16550 based cards) then everything
+	   will be very easy..... */
+	port->baud = baudrate;
+
+	/* Two timer ticks seems enough to wakeup something like SLIP driver */
+	/* Baudrate/10 is cps. Divide by HZ to get chars per tick. */
+	tmp = (baudrate / 10 / HZ) * 2;			 
+
+	if (tmp <                 0) tmp = 0;
+	if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1;
+
+	port->wakeup_chars = tmp;
+
+	/* We should really wait for the characters to be all sent before
+	   changing the settings. -- CAL */
+	gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);
+
+	port->rd->set_real_termios(port);
+
+	if ((!old_termios || 
+	     (old_termios->c_cflag & CRTSCTS)) &&
+	    !(      tiosp->c_cflag & CRTSCTS)) {
+		tty->stopped = 0;
+		gs_start(tty);
+	}
+
+#ifdef tytso_patch_94Nov25_1726
+	/* This "makes sense", Why is it commented out? */
+
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+
+	func_exit();
+	return;
+}
+
+
+
+/* Must be called with interrupts enabled */
+int gs_init_port(struct gs_port *port)
+{
+	unsigned long flags;
+	unsigned long page;
+
+	save_flags (flags);
+	if (!tmp_buf) {
+		page = get_free_page(GFP_KERNEL);
+
+		cli (); /* Don't expect this to make a difference. */ 
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+		restore_flags (flags);
+
+		if (!tmp_buf) {
+			return -ENOMEM;
+		}
+	}
+
+	if (port->flags & ASYNC_INITIALIZED)
+		return 0;
+
+	if (!port->xmit_buf) {
+		/* We may sleep in get_free_page() */
+		unsigned long tmp;
+
+		tmp = get_free_page(GFP_KERNEL);
+
+		/* Spinlock? */
+		cli ();
+		if (port->xmit_buf) 
+			free_page (tmp);
+		else
+			port->xmit_buf = (unsigned char *) tmp;
+		restore_flags (flags);
+
+		if (!port->xmit_buf)
+			return -ENOMEM;
+	}
+
+	cli();
+
+	if (port->tty) 
+		clear_bit(TTY_IO_ERROR, &port->tty->flags);
+
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+
+	gs_set_termios(port->tty, NULL);
+
+	port->flags |= ASYNC_INITIALIZED;
+	port->flags &= ~GS_TX_INTEN;
+
+	restore_flags(flags);
+	return 0;
+}
+
+
+int gs_setserial(struct gs_port *port, struct serial_struct *sp)
+{
+	struct serial_struct sio;
+
+	copy_from_user(&sio, sp, sizeof(struct serial_struct));
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((sio.baud_base != port->baud_base) ||
+		    (sio.close_delay != port->close_delay) ||
+		    ((sio.flags & ~ASYNC_USR_MASK) !=
+		     (port->flags & ~ASYNC_USR_MASK)))
+			return(-EPERM);
+	} 
+
+	port->flags = (port->flags & ~ASYNC_USR_MASK) |
+		(sio.flags & ASYNC_USR_MASK);
+  
+	port->baud_base = sio.baud_base;
+	port->close_delay = sio.close_delay;
+	port->closing_wait = sio.closing_wait;
+	port->custom_divisor = sio.custom_divisor;
+
+	gs_set_termios (port->tty, NULL);
+
+	return 0;
+}
+
+
+/*****************************************************************************/
+
+/*
+ *      Generate the serial struct info.
+ */
+
+void gs_getserial(struct gs_port *port, struct serial_struct *sp)
+{
+	struct serial_struct    sio;
+
+	memset(&sio, 0, sizeof(struct serial_struct));
+	sio.flags = port->flags;
+	sio.baud_base = port->baud_base;
+	sio.close_delay = port->close_delay;
+	sio.closing_wait = port->closing_wait;
+	sio.custom_divisor = port->custom_divisor;
+	sio.hub6 = 0;
+
+	/* If you want you can override these. */
+	sio.type = PORT_UNKNOWN;
+	sio.xmit_fifo_size = -1;
+	sio.line = -1;
+	sio.port = -1;
+	sio.irq = -1;
+
+	if (port->rd->getserial)
+		port->rd->getserial (port, &sio);
+
+	copy_to_user(sp, &sio, sizeof(struct serial_struct));
+}
+
diff -u --recursive --new-file v2.3.12/linux/drivers/char/generic_serial.h linux/drivers/char/generic_serial.h
--- v2.3.12/linux/drivers/char/generic_serial.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/generic_serial.h	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,101 @@
+/*
+ *  generic_serial.h
+ *
+ *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ *  written for the SX serial driver.
+ *     Contains the code that should be shared over all the serial drivers.
+ *
+ *  Version 0.1 -- December, 1998.
+ */
+
+#ifndef GENERIC_SERIAL_H
+#define GENERIC_SERIAL_H
+
+struct real_driver {
+  void                    (*disable_tx_interrupts) (void *);
+  void                    (*enable_tx_interrupts) (void *);
+  void                    (*disable_rx_interrupts) (void *);
+  void                    (*enable_rx_interrupts) (void *);
+  int                     (*get_CD) (void *);
+  void                    (*shutdown_port) (void*);
+  void                    (*set_real_termios) (void*);
+  int                     (*chars_in_buffer) (void*);
+  void                    (*close) (void*);
+  void                    (*hungup) (void*);
+  void                    (*getserial) (void*, struct serial_struct *sp);
+};
+
+
+
+struct gs_port {
+  int                     magic;
+  unsigned char           *xmit_buf; 
+  int                     xmit_head;
+  int                     xmit_tail;
+  int                     xmit_cnt;
+  /*  struct semaphore        port_write_sem; */
+  int                     flags;
+  struct termios          normal_termios;
+  struct termios          callout_termios;
+  wait_queue_head_t       open_wait;
+  wait_queue_head_t       close_wait;
+  long                    session;
+  long                    pgrp;
+  int                     count;
+  int                     blocked_open;
+  struct tty_struct       *tty;
+  int                     event;
+  unsigned short          closing_wait;
+  int                     close_delay;
+  struct real_driver      *rd;
+  int                     wakeup_chars;
+  int                     baud_base;
+  int                     baud;
+  int                     custom_divisor;
+};
+
+
+/* Flags */
+/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
+   used in serial.c, but they are also used in all other serial drivers. 
+   Make sure they don't clash with these here... */
+#define GS_TX_INTEN      0x00800000
+#define GS_RX_INTEN      0x00400000
+#define GS_ACTIVE        0x00200000
+
+
+
+#define GS_TYPE_NORMAL   1
+#define GS_TYPE_CALLOUT  2
+
+
+#define GS_DEBUG_FLUSH   0x00000001
+#define GS_DEBUG_BTR     0x00000002
+#define GS_DEBUG_TERMIOS 0x00000004
+#define GS_DEBUG_STUFF   0x00000008
+#define GS_DEBUG_CLOSE   0x00000010
+
+
+void gs_put_char(struct tty_struct *tty, unsigned char ch);
+int  gs_write(struct tty_struct *tty, int from_user, 
+             const unsigned char *buf, int count);
+int  gs_write_room(struct tty_struct *tty);
+int  gs_chars_in_buffer(struct tty_struct *tty);
+void gs_flush_buffer(struct tty_struct *tty);
+void gs_flush_chars(struct tty_struct *tty);
+void gs_stop(struct tty_struct *tty);
+void gs_start(struct tty_struct *tty);
+void gs_hangup(struct tty_struct *tty);
+void gs_do_softint(void *private_);
+int  block_til_ready(void *port, struct file *filp);
+void gs_close(struct tty_struct *tty, struct file *filp);
+void gs_set_termios (struct tty_struct * tty, 
+                     struct termios * old_termios);
+int  gs_init_port(struct gs_port *port);
+int  gs_setserial(struct gs_port *port, struct serial_struct *sp);
+void gs_getserial(struct gs_port *port, struct serial_struct *sp);
+
+extern int gs_debug;
+
+#endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/Config.in linux/drivers/char/hfmodem/Config.in
--- v2.3.12/linux/drivers/char/hfmodem/Config.in	Tue Dec 29 11:28:49 1998
+++ linux/drivers/char/hfmodem/Config.in	Wed Dec 31 16:00:00 1969
@@ -1,6 +0,0 @@
-comment 'Misc. hamradio protocols'
-dep_tristate 'Shortwave radio modem driver' CONFIG_HFMODEM $CONFIG_PARPORT
-if [ "$CONFIG_HFMODEM" != "n" ]; then
-  bool '   HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC
-  bool '   HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS
-fi
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/Makefile linux/drivers/char/hfmodem/Makefile
--- v2.3.12/linux/drivers/char/hfmodem/Makefile	Mon Jul 20 10:05:16 1998
+++ linux/drivers/char/hfmodem/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,37 +0,0 @@
-#
-# Makefile for the hfmodem device driver.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-O_TARGET	:= hfmodem.o
-
-O_OBJS		:= refclock.o modem.o main.o
-ifeq ($(CONFIG_HFMODEM_SBC),y)
-O_OBJS		+= sbc.o
-endif
-ifeq ($(CONFIG_HFMODEM_WSS),y)
-O_OBJS		+= wss.o
-endif
-
-M_OBJS		:= $(O_TARGET)
-
-all:		all_targets
-.PHONY:		all
-
-gentbl:		gentbl.c
-		$(HOSTCC) $(HOSTCFLAGS) $< -o $@ -lm
-
-TBLHDR		:= tables.h
-
-tables.h:	gentbl
-		./gentbl > $@
-
-fastdep:	$(TBLHDR)
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/gentbl.c linux/drivers/char/hfmodem/gentbl.c
--- v2.3.12/linux/drivers/char/hfmodem/gentbl.c	Tue Apr  7 07:48:54 1998
+++ linux/drivers/char/hfmodem/gentbl.c	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      gentbl.c  --  Linux soundcard HF FSK driver,
- *                    Table generator.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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 is compiled with HOSTCC - do not include any <linux/foo.h> headers. */
-#include <math.h>
-#include <stdio.h>
-
-/* --------------------------------------------------------------------- */
-
-#define SINTABBITS  9
-#define SINTABSIZE  (1<<SINTABBITS)
-
-/* --------------------------------------------------------------------- */
-
-static void gensintbl(void)
-{
-	int i;
-
-	printf("#define SINTABBITS %d\n#define SINTABSIZE  (1<<SINTABBITS)\n"
-	       "\nstatic short isintab[SINTABSIZE+SINTABSIZE/4] = {\n\t", SINTABBITS);
-	for (i = 0; i < (SINTABSIZE+SINTABSIZE/4); i++) {
-		printf("%6d", (int)(32767.0 * sin(2.0 * M_PI / SINTABSIZE * i)));
-		if (i < (SINTABSIZE+SINTABSIZE/4)-1) {
-			if ((i & 7) == 7)
-				printf(",\n\t");
-			else
-				printf(",");
-		}
-	}
-	printf("\n};\n\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-int main(int argc, char *argv[])
-{
-	printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n",
-	       argv[0]);
-	gensintbl();
-	exit(0);
-}
-
-/* --------------------------------------------------------------------- */
-
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/main.c linux/drivers/char/hfmodem/main.c
--- v2.3.12/linux/drivers/char/hfmodem/main.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/hfmodem/main.c	Wed Dec 31 16:00:00 1969
@@ -1,734 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      main.c  --  Linux soundcard HF FSK driver.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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.
- *
- *  Command line options (insmod command line)
- *
- *  History:
- *   0.1  15.04.97  Adapted from baycom.c and made network driver interface
- *   0.2  05.07.97  All floating point stuff thrown out due to Linus' rantings :)
- *
- */
-
-/*****************************************************************************/
-      
-
-#include <linux/config.h> /* for CONFIG_HFMODEM_WSS and CONFIG_HFMODEM_SBC */
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/hfmodem.h>
-
-#include <asm/io.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*static*/ const char hfmodem_drvname[] = "hfmodem";
-static const char hfmodem_drvinfo[] = KERN_INFO "hfmodem: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "hfmodem: version 0.2 compiled " __TIME__ " " __DATE__ "\n";
-
-/* --------------------------------------------------------------------- */
-/*
- * currently we support only one device
- */
-
-struct hfmodem_state hfmodem_state[NR_DEVICE];
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== port checking routines ========================
- */
-
-
-#define UART_RBR(iobase) (iobase+0)
-#define UART_THR(iobase) (iobase+0)
-#define UART_IER(iobase) (iobase+1)
-#define UART_IIR(iobase) (iobase+2)
-#define UART_FCR(iobase) (iobase+2)
-#define UART_LCR(iobase) (iobase+3)
-#define UART_MCR(iobase) (iobase+4)
-#define UART_LSR(iobase) (iobase+5)
-#define UART_MSR(iobase) (iobase+6)
-#define UART_SCR(iobase) (iobase+7)
-#define UART_DLL(iobase) (iobase+0)
-#define UART_DLM(iobase) (iobase+1)
-
-#define SER_EXTENT 8
-
-#define LPT_DATA(iobase)    (iobase+0)
-#define LPT_STATUS(iobase)  (iobase+1)
-#define LPT_CONTROL(iobase) (iobase+2)
-#define LPT_IRQ_ENABLE      0x10
-
-#define MIDI_DATA(iobase)     (iobase)
-#define MIDI_STATUS(iobase)   (iobase+1)
-#define MIDI_READ_FULL 0x80   /* attention: negative logic!! */
-#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */
-
-#define MIDI_EXTENT 2
-
-#define SP_SER  1
-#define SP_PAR  2
-#define SP_MIDI 4
-
-/* --------------------------------------------------------------------- */
-
-static void parptt_wakeup(void *handle)
-{
-        struct hfmodem_state *dev = (struct hfmodem_state *)handle;
-
-	printk(KERN_DEBUG "%s: parptt: why am I being woken up?\n", hfmodem_drvname);
-	if (!parport_claim(dev->ptt_out.pardev))
-		printk(KERN_DEBUG "%s: parptt: I'm broken.\n", hfmodem_drvname);
-}
-
-/* --------------------------------------------------------------------- */
-static int __init check_lpt(struct hfmodem_state *dev, unsigned int iobase)
-{
-	struct parport *pp = parport_enumerate();
-
-	while (pp && pp->base != iobase)
-		pp = pp->next;
-	if (!pp)
-		return 0;
-	if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, NULL, parptt_wakeup, 
-							    NULL, PARPORT_DEV_EXCL, dev)))
-		return 0;
-	return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-enum uart { c_uart_unknown, c_uart_8250, c_uart_16450, c_uart_16550, c_uart_16550A };
-static const char *uart_str[] __initdata = { "unknown", "8250", "16450", "16550", "16550A" };
-
-static enum uart __init check_uart(unsigned int iobase)
-{
-        unsigned char b1,b2,b3;
-        enum uart u;
-        enum uart uart_tab[] = { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
-
-        if (iobase <= 0 || iobase > 0x1000-SER_EXTENT)
-                return c_uart_unknown;
-        if (check_region(iobase, SER_EXTENT))
-                return c_uart_unknown;
-        b1 = inb(UART_MCR(iobase));
-        outb(b1 | 0x10, UART_MCR(iobase));      /* loopback mode */
-        b2 = inb(UART_MSR(iobase));
-        outb(0x1a, UART_MCR(iobase));
-        b3 = inb(UART_MSR(iobase)) & 0xf0;
-        outb(b1, UART_MCR(iobase));        /* restore old values */
-        outb(b2, UART_MSR(iobase));
-        if (b3 != 0x90)
-                return c_uart_unknown;
-        inb(UART_RBR(iobase));
-        inb(UART_RBR(iobase));
-        outb(0x01, UART_FCR(iobase));           /* enable FIFOs */
-        u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3];
-        if (u == c_uart_16450) {
-                outb(0x5a, UART_SCR(iobase));
-                b1 = inb(UART_SCR(iobase));
-                outb(0xa5, UART_SCR(iobase));
-                b2 = inb(UART_SCR(iobase));
-                if ((b1 != 0x5a) || (b2 != 0xa5))
-                        u = c_uart_8250;
-        }
-        return u;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int __init check_midi(unsigned int iobase)
-{
-        unsigned long timeout;
-        unsigned long flags;
-        unsigned char b;
-
-        if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT)
-                return 0;
-        if (check_region(iobase, MIDI_EXTENT))
-                return 0;
-        timeout = jiffies + (HZ / 100);
-        while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
-                if ((signed)(jiffies - timeout) > 0)
-                        return 0;
-        save_flags(flags);
-        cli();
-        outb(0xff, MIDI_DATA(iobase));
-        b = inb(MIDI_STATUS(iobase));
-        restore_flags(flags);
-        if (!(b & MIDI_WRITE_EMPTY))
-                return 0;
-        while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
-                if ((signed)(jiffies - timeout) > 0)
-                        return 0;
-        return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void output_status(struct hfmodem_state *dev, int ptt)
-{
-        int dcd = 0;
-
-	ptt = !!ptt;
-        if (dev->ptt_out.flags & SP_SER) {
-                outb(dcd | (ptt << 1), UART_MCR(dev->ptt_out.seriobase));
-                outb(0x40 & (-ptt), UART_LCR(dev->ptt_out.seriobase));
-        }
-        if (dev->ptt_out.flags & SP_PAR) {
-                outb(ptt | (dcd << 1), LPT_DATA(dev->ptt_out.pariobase));
-        }
-        if (dev->ptt_out.flags & SP_MIDI && ptt) {
-                outb(0, MIDI_DATA(dev->ptt_out.midiiobase));
-        }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void __init output_check(struct hfmodem_state *dev)
-{
-        enum uart u = c_uart_unknown;
-
-        if (((u = check_uart(dev->ptt_out.seriobase))) != c_uart_unknown)
-		printk(KERN_INFO "%s: PTT output: uart found at address 0x%x type %s\n",
-		       hfmodem_drvname, dev->ptt_out.seriobase, uart_str[u]);
-	else {
-		if (dev->ptt_out.seriobase > 0)
-			printk(KERN_WARNING "%s: PTT output: no uart found at address 0x%x\n",
-			       hfmodem_drvname, dev->ptt_out.seriobase);
-		dev->ptt_out.seriobase = 0;
-	}
-        if (check_lpt(dev, dev->ptt_out.pariobase)) 
-		printk(KERN_INFO "%s: PTT output: parallel port found at address 0x%x\n",
-		       hfmodem_drvname, dev->ptt_out.pariobase);
-	else {
-		if (dev->ptt_out.pariobase > 0)
-			printk(KERN_WARNING "%s: PTT output: no parallel port found at address 0x%x\n",
-			       hfmodem_drvname, dev->ptt_out.pariobase);
-		dev->ptt_out.pariobase = 0;
-		dev->ptt_out.pardev = NULL;
-	}
-	if (dev->ptt_out.midiiobase > 0 && dev->ptt_out.midiiobase <= 0x1000-MIDI_EXTENT &&
-            check_midi(dev->ptt_out.midiiobase))
-		printk(KERN_INFO "%s: PTT output: midi port found at address 0x%x\n",
-		       hfmodem_drvname, dev->ptt_out.midiiobase);
-	else {
-		if (dev->ptt_out.midiiobase > 0)
-			printk(KERN_WARNING "%s: PTT output: no midi port found at address 0x%x\n",
-			       hfmodem_drvname, dev->ptt_out.midiiobase);
-		dev->ptt_out.midiiobase = 0;
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-static void output_open(struct hfmodem_state *dev)
-{
-        dev->ptt_out.flags = 0;
-        if (dev->ptt_out.seriobase > 0) {
-		if (!check_region(dev->ptt_out.seriobase, SER_EXTENT)) {
-			request_region(dev->ptt_out.seriobase, SER_EXTENT, "hfmodem ser ptt");
-			dev->ptt_out.flags |= SP_SER;
-			outb(0, UART_IER(dev->ptt_out.seriobase));
-			/* 5 bits, 1 stop, no parity, no break, Div latch access */
-			outb(0x80, UART_LCR(dev->ptt_out.seriobase));
-			outb(0, UART_DLM(dev->ptt_out.seriobase));
-			outb(1, UART_DLL(dev->ptt_out.seriobase)); /* as fast as possible */
-			/* LCR and MCR set by output_status */
-		} else
-			printk(KERN_WARNING "%s: PTT output: serial port at 0x%x busy\n",
-			       hfmodem_drvname, dev->ptt_out.seriobase);
-	}
-        if (dev->ptt_out.pariobase > 0) {
-		if (parport_claim(dev->ptt_out.pardev)) 
-			printk(KERN_WARNING "%s: PTT output: parallel port at 0x%x busy\n",
-			       hfmodem_drvname, dev->ptt_out.pariobase);
-		else 
-			dev->ptt_out.flags |= SP_PAR;
-	}
-        if (dev->ptt_out.midiiobase > 0) {
-		if (!check_region(dev->ptt_out.midiiobase, MIDI_EXTENT)) {
-			request_region(dev->ptt_out.midiiobase, MIDI_EXTENT, "hfmodem midi ptt");
-			dev->ptt_out.flags |= SP_MIDI;
-		} else
-			printk(KERN_WARNING "%s: PTT output: midi port at 0x%x busy\n",
-			       hfmodem_drvname, dev->ptt_out.midiiobase);
-	}
-	output_status(dev, 0);
-        printk(KERN_INFO "%s: PTT output:", hfmodem_drvname);
-        if (dev->ptt_out.flags & SP_SER)
-                printk(" serial interface at 0x%x", dev->ptt_out.seriobase);
-        if (dev->ptt_out.flags & SP_PAR)
-                printk(" parallel interface at 0x%x", dev->ptt_out.pariobase);
-        if (dev->ptt_out.flags & SP_MIDI)
-                printk(" mpu401 (midi) interface at 0x%x", dev->ptt_out.midiiobase);
-        if (!dev->ptt_out.flags)
-                printk(" none");
-        printk("\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-static void output_close(struct hfmodem_state *dev)
-{
-        /* release regions used for PTT output */
-        output_status(dev, 0);
-        if (dev->ptt_out.flags & SP_SER)
-                release_region(dev->ptt_out.seriobase, SER_EXTENT);
-        if (dev->ptt_out.flags & SP_PAR)
-		parport_release(dev->ptt_out.pardev);
-        if (dev->ptt_out.flags & SP_MIDI)
-                release_region(dev->ptt_out.midiiobase, MIDI_EXTENT);
-        dev->ptt_out.flags = 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define INC_SAMPLE   (1000000/HFMODEM_SRATE)
-#define INC_FRAGMENT (HFMODEM_FRAGSAMPLES*1000000/HFMODEM_SRATE)
-#define SIZE         (HFMODEM_FRAGSAMPLES*HFMODEM_NUMFRAGS)
-
-static void hfmodem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct hfmodem_state *dev = (struct hfmodem_state *)dev_id;
-	unsigned int dmaptr;
-	__s16 *s;
-	unsigned int curfrag, nfrags;
-	int i;
-	hfmodem_time_t l1time;
-
-	dmaptr = dev->scops->intack(dev);
-	l1time = hfmodem_refclock_current(dev, ((SIZE+dmaptr-dev->dma.last_dmaptr) % SIZE) * 
-					  INC_SAMPLE, 1);
-	curfrag = (dev->dma.last_dmaptr = dmaptr) / HFMODEM_FRAGSAMPLES;
-	l1time -= INC_SAMPLE * (SIZE+dmaptr-dev->dma.fragptr*HFMODEM_FRAGSAMPLES) % SIZE;
-	sti();
-	/*
-	 * handle receiving
-	 */
-	if (dev->dma.ptt_frames <= 0) {
-		while (dev->dma.fragptr != curfrag) {
-			if (dev->dma.fragptr < HFMODEM_EXCESSFRAGS) {
-				s = dev->dma.buf + SIZE + HFMODEM_FRAGSAMPLES * dev->dma.fragptr;
-				memcpy(s, s - SIZE, HFMODEM_FRAGSIZE);
-			} else
-				s = dev->dma.buf + HFMODEM_FRAGSAMPLES * dev->dma.fragptr;
-			if (dev->sbuf.kbuf && dev->sbuf.kptr && dev->sbuf.rem > 0) {
-				i = HFMODEM_FRAGSAMPLES;
-				if (i > dev->sbuf.rem)
-					i = dev->sbuf.rem;
-				memcpy(dev->sbuf.kptr, s, i * sizeof(s[0]));
-				dev->sbuf.rem -= i;
-				dev->sbuf.kptr += i;
-			}
-			hfmodem_input_samples(dev, l1time, INC_SAMPLE, s);
-			l1time += INC_FRAGMENT;
-			dev->dma.fragptr++;
-			if (dev->dma.fragptr >= HFMODEM_NUMFRAGS)
-				dev->dma.fragptr = 0;
-		}
-		/*
-		 * check for output
-		 */
-		if (hfmodem_next_tx_event(dev, l1time) > (long)INC_FRAGMENT/2)
-			goto int_return;
-		/*
-		 * start output
-		 */
-		output_status(dev, 1);
-		dev->scops->prepare_output(dev);
-		dev->dma.last_dmaptr = 0;
-		/*
-		 * clock adjust
-		 */
-		l1time = hfmodem_refclock_current(dev, 0, 0);
-		/*
-		 * fill first two fragments
-		 */
-		dev->dma.ptt_frames = 1;
-		for (i = 0; i < 2 && i < HFMODEM_NUMFRAGS; i++)
-			if (hfmodem_output_samples(dev, l1time+i*INC_FRAGMENT, INC_SAMPLE, 
-						   dev->dma.buf+i*HFMODEM_FRAGSAMPLES))
-				dev->dma.ptt_frames = i + 1;
-		dev->dma.lastfrag = 0;
-		dev->scops->trigger_output(dev);
-		/*
-		 * finish already pending rx requests
-		 */
-		hfmodem_finish_pending_rx_requests(dev);
-		goto int_return;
-	}
-	/*
-	 * handle transmitting
-	 */
-	nfrags = HFMODEM_NUMFRAGS + curfrag - dev->dma.lastfrag;
-	dev->dma.lastfrag = curfrag;
-	if (nfrags >= HFMODEM_NUMFRAGS)
-		nfrags -= HFMODEM_NUMFRAGS;
-	dev->dma.ptt_frames -= nfrags;
-	if (dev->dma.ptt_frames < 0)
-		dev->dma.ptt_frames = 0;
-	while (dev->dma.ptt_frames < HFMODEM_NUMFRAGS && dev->dma.ptt_frames < 4 && 
-	       hfmodem_output_samples(dev, l1time+dev->dma.ptt_frames*INC_FRAGMENT, 
-				      INC_SAMPLE, dev->dma.buf + HFMODEM_FRAGSAMPLES * 
-				      ((curfrag + dev->dma.ptt_frames) % HFMODEM_NUMFRAGS)))
-		dev->dma.ptt_frames++;
-	if (dev->dma.ptt_frames > 0)
-		goto int_return;
-	/* 
-	 * start receiving
-	 */
-	output_status(dev, 0);
-	dev->dma.last_dmaptr = 0;
-	dev->dma.lastfrag = 0;
-	dev->dma.fragptr = 0;
-	dev->dma.ptt_frames = 0;
-	dev->scops->prepare_input(dev);
-	dev->scops->trigger_input(dev);
-	hfmodem_refclock_current(dev, 0, 0);  /* needed to reset the time difference */
-int_return:
-	hfmodem_wakeup(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int hfmodem_close(struct inode *inode, struct file *file)
-{
-	struct hfmodem_state *dev = &hfmodem_state[0];
-
-	if (!dev->active)
-		return -EPERM;
-	dev->active = 0;
-	dev->scops->stop(dev);
-        free_irq(dev->io.irq, dev);        
-	disable_dma(dev->io.dma);
-	free_dma(dev->io.dma);
-        release_region(dev->io.base_addr, dev->scops->extent);
-	kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
-	hfmodem_clear_rq(dev);
-	if (dev->sbuf.kbuf) {
-		kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
-		dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
-		dev->sbuf.size = dev->sbuf.rem = 0;
-	}
-	output_close(dev);
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int hfmodem_open(struct inode *inode, struct file *file)
-{
-	struct hfmodem_state *dev = &hfmodem_state[0];
-
-	if (dev->active)
-		return -EBUSY;
-	if (!dev->scops)
-		return -EPERM;
-	/*
-	 * clear vars
-	 */
-	memset(&dev->l1, 0, sizeof(dev->l1));
-	dev->dma.last_dmaptr = 0;
-	dev->dma.lastfrag = 0;
-	dev->dma.fragptr = 0;
-	dev->dma.ptt_frames = 0;
-	/*
-	 * allocate memory
-	 */
-	if (!(dev->dma.buf = kmalloc(HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS), GFP_KERNEL | GFP_DMA)))
-		return -ENOMEM;
-	/*
-	 * allocate resources
-	 */
-        if (request_dma(dev->io.dma, hfmodem_drvname)) {
-                kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
-                return -EBUSY;
-        }
-        if (request_irq(dev->io.irq, hfmodem_interrupt, SA_INTERRUPT, hfmodem_drvname, dev)) {
-                free_dma(dev->io.dma);
-                kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
-                return -EBUSY;
-        }
-        request_region(dev->io.base_addr, dev->scops->extent, hfmodem_drvname);
-	
-	/* clear requests */
-      	dev->active++;
-	MOD_INC_USE_COUNT;
-	hfmodem_refclock_init(dev);
-	output_open(dev);
-	dev->scops->init(dev);
-	dev->scops->prepare_input(dev);
-	dev->scops->trigger_input(dev);
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static struct file_operations hfmodem_fops = {
-	NULL,		    /* hfmodem_seek */
-	NULL,               /* hfmodem_read */
-	NULL,               /* hfmodem_write */
-	NULL, 		    /* hfmodem_readdir */
-#if LINUX_VERSION_CODE >= 0x20100
-	hfmodem_poll,       /* hfmodem_poll */
-#else 
-	hfmodem_select,     /* hfmodem_select */
-#endif
-	hfmodem_ioctl,      /* hfmodem_ioctl */
-	NULL,		    /* hfmodem_mmap */
-	hfmodem_open,       /* hfmodem_open */
-	NULL,		    /* flush */
-	hfmodem_close,      /* hfmodem_close */
-	NULL,               /* hfmodem_fsync */
-	NULL,               /* hfmodem_fasync */
-	NULL,               /* hfmodem_check_media_change */
-	NULL                /* hfmodem_revalidate */
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct miscdevice hfmodem_device = {
-	HFMODEM_MINOR, hfmodem_drvname, &hfmodem_fops
-};
-
-/* --------------------------------------------------------------------- */
-
-#ifdef MODULE
-
-/*
- * Command line parameters
- */
-
-static int hw = 0;
-static unsigned int iobase = 0x220;
-static unsigned int irq = 7;
-static unsigned int dma = 1;
-
-static unsigned int serio = 0;
-static unsigned int pario = 0;
-static unsigned int midiio = 0;
-
-#if LINUX_VERSION_CODE >= 0x20115
-
-MODULE_PARM(hw, "i");
-MODULE_PARM_DESC(hw, "hardware type: 0=SBC, 1=WSS");
-MODULE_PARM(iobase, "i");
-MODULE_PARM_DESC(iobase, "io base address");
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(irq, "interrupt number");
-MODULE_PARM(dma, "i");
-MODULE_PARM_DESC(dma, "dma number (>=4 for SB16/32/64/etc, <=3 for the rest)");
-MODULE_PARM(serio, "i");
-MODULE_PARM_DESC(serio, "address of serial port to output PTT");
-MODULE_PARM(pario, "i");
-MODULE_PARM_DESC(pario, "address of parallel port to output PTT");
-MODULE_PARM(midiio, "i");
-MODULE_PARM_DESC(midiio, "address of midi (MPU401) port to output PTT");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("HF FSK modem code");
-
-/* these are the module parameters from refclock.c */
-
-MODULE_PARM(scale_tvusec, "i");
-MODULE_PARM_DESC(scale_tvusec, "Scaling value for the tv_usec field (can be obta
-ined by refclock)");
-
-#ifdef __i386__
-MODULE_PARM(scale_rdtsc, "i");
-MODULE_PARM_DESC(scale_rdtsc, "Scaling value for the rdtsc counter (can be obtai
-ned by refclock)");
-MODULE_PARM(rdtsc_ok, "i");
-MODULE_PARM_DESC(rdtsc_ok, "Set to 0 to disable the use of the rdtsc instruction
-");
-#endif /* __i386__ */
-
-#endif
-
-int __init init_module(void)
-{
-	int i;
-
-	printk(hfmodem_drvinfo);
-	memset(hfmodem_state, 0, sizeof(hfmodem_state));
-        memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache));
-	hfmodem_state[0].io.base_addr = iobase;
-	hfmodem_state[0].io.irq = irq;
-	hfmodem_state[0].io.dma = dma;
-	hfmodem_state[0].ptt_out.seriobase = serio;
-	hfmodem_state[0].ptt_out.pariobase = pario;
-	hfmodem_state[0].ptt_out.midiiobase = midiio;
-	init_waitqueue_head(&hfmodem_state[0].wait);
-	hfmodem_refclock_probe();
-	output_check(&hfmodem_state[0]);
-#if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC)
-        if (hw) 
-                i = hfmodem_wssprobe(&hfmodem_state[0]);
-        else
-                i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#else
-        i = -EINVAL;
-#ifdef CONFIG_HFMODEM_WSS
-        i = hfmodem_wssprobe(&hfmodem_state[0]);
-#endif
-#ifdef CONFIG_HFMODEM_SBC
-        i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#endif
-#endif
-	if (i)
-		return i;
-	if ((i =  misc_register(&hfmodem_device))) {
-		printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname);
-		return i;
-	}
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	struct hfmodem_state *dev = &hfmodem_state[0];
-
-	if (dev->ptt_out.pariobase > 0)
-		parport_unregister_device(dev->ptt_out.pardev);
-	misc_deregister(&hfmodem_device);
-}
-
-#else /* MODULE */
-/* --------------------------------------------------------------------- */
-
-static int hw = 0;
-
-void __init hfmodem_setup(char *str, int *ints)
-{
-        if (ints[0] < 7) {
-                printk(KERN_WARNING "%s: setup: too few parameters\n", hfmodem_drvname);
-                return;
-        }       
-        memset(hfmodem_state, 0, sizeof(hfmodem_state));
-        memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache));
-        hw = ints[1];
-        hfmodem_state[0].io.base_addr = ints[2];
-        hfmodem_state[0].io.irq = ints[3];
-        hfmodem_state[0].io.dma = ints[4];
-        if (ints[0] >= 8)
-                hfmodem_state[0].ptt_out.seriobase = ints[5];
-        if (ints[0] >= 9)
-                hfmodem_state[0].ptt_out.pariobase = ints[6];
-        if (ints[0] >= 10)
-                hfmodem_state[0].ptt_out.midiiobase = ints[7];
-        hfmodem_refclock_setscale(ints[ints[0]-2], ints[ints[0]-1], ints[ints[0]]);
-}
-
-void __init hfmodem_init(void)
-{
-        int i;
-
-	printk(hfmodem_drvinfo);
- 	init_waitqueue_head(&hfmode_state[0].wait);
-       hfmodem_refclock_probe();
-        output_check(&hfmodem_state[0]);
-#if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC)
-        if (hw) 
-                i = hfmodem_wssprobe(&hfmodem_state[0]);
-        else
-                i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#else
-        i = -EINVAL;
-#ifdef CONFIG_HFMODEM_WSS
-        i = hfmodem_wssprobe(&hfmodem_state[0]);
-#endif
-#ifdef CONFIG_HFMODEM_SBC
-        i = hfmodem_sbcprobe(&hfmodem_state[0]);
-#endif
-#endif
-        if (i) {
-                printk(KERN_ERR "%s: soundcard probe failed\n", hfmodem_drvname);
-                return;
-        }
-        if ((i =  misc_register(&hfmodem_device))) {
-                printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname);
-                return;
-        }
-}
-
-/* --------------------------------------------------------------------- */
-#endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/modem.c linux/drivers/char/hfmodem/modem.c
--- v2.3.12/linux/drivers/char/hfmodem/modem.c	Fri Feb 27 09:11:09 1998
+++ linux/drivers/char/hfmodem/modem.c	Wed Dec 31 16:00:00 1969
@@ -1,792 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      modem.c  --  Linux soundcard HF FSK driver,
- *                   Modem code.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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.
- *
- *
- */
-
-/*****************************************************************************/
-      
-
-#include <linux/wait.h>
-#include <linux/malloc.h>
-#include <linux/hfmodem.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
-struct hfmodem_correlator_cache hfmodem_correlator_cache[HFMODEM_CORRELATOR_CACHE];
-
-/* --------------------------------------------------------------------- */
-
-#include "tables.h"
-
-#define M_PI        3.14159265358979323846      /* pi */
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ int isimplecos(unsigned int arg)
-{
-	return isintab[((arg+0x4000) >> (16-SINTABBITS)) & (SINTABSIZE-1)];
-}
-
-extern __inline__ int isimplesin(unsigned int arg)
-{
-	return isintab[(arg >> (16-SINTABBITS)) & (SINTABSIZE-1)];
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ int itblcos(unsigned int arg)
-{
-	unsigned int x;
-	int dx;
-	int s, c;
-
-	x = (arg + (0x8000 >> SINTABBITS)) & (0xffffu & (0xffffu << (16-SINTABBITS)));
-	dx = arg - x;
-	x >>= (16-SINTABBITS);
-	c = isintab[x+(0x4000 >> (16-SINTABBITS))];
-	s = isintab[x];
-	return c - ((s * dx * (int)(M_PI*64.0)) >> 21);
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void itblcossin(unsigned int arg, int *cos, int *sin)
-{
-	unsigned int x;
-	int dx;
-	int s, c;
-
-	x = (arg + (0x8000 >> SINTABBITS)) & (0xffffu & (0xffffu << (16-SINTABBITS)));
-	dx = arg - x;
-	x >>= (16-SINTABBITS);
-	c = isintab[x+(0x4000 >> (16-SINTABBITS))];
-	s = isintab[x];
-	*cos = c - ((s * dx * (int)(M_PI*64.0)) >> 21);
-	*sin = s + ((c * dx * (int)(M_PI*64.0)) >> 21);
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned short random_seed;
-
-extern __inline__ unsigned short random_num(void)
-{
-        random_seed = 28629 * random_seed + 157;
-        return random_seed;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * correlator cache routines
- */
-
-extern __inline__ void cc_lock(unsigned int u)
-{
-	if (u >= HFMODEM_CORRELATOR_CACHE)
-		return;
-	hfmodem_correlator_cache[u].refcnt++;
-}
-
-extern __inline__ void cc_unlock(unsigned int u)
-{
-	if (u >= HFMODEM_CORRELATOR_CACHE)
-		return;
-	if ((--hfmodem_correlator_cache[u].refcnt) <= 0) {
-		unsigned int i;
-
-		for (i = 0; i < HFMODEM_CORRELATOR_CACHE; i++) 
-			if (hfmodem_correlator_cache[i].lru < 32767)
-				hfmodem_correlator_cache[i].lru++;
-		hfmodem_correlator_cache[u].lru = 0;
-		hfmodem_correlator_cache[u].refcnt = 0;
-	}
-}
-
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int cc_lookup(unsigned short phinc0, unsigned short phinc1)
-{
-	unsigned int j;
-
-	/* find correlator cache entry */
-	for (j = 0; j < HFMODEM_CORRELATOR_CACHE; j++) 
-		if (hfmodem_correlator_cache[j].phase_incs[0] == phinc0 &&
-		    hfmodem_correlator_cache[j].phase_incs[1] == phinc1)
-			return j;
-	return ~0;
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int cc_replace(void)
-{
-	unsigned int j, k = HFMODEM_CORRELATOR_CACHE;
-	int l = -1;
-
-	for (j = 0; j < HFMODEM_CORRELATOR_CACHE; j++)
-		if (hfmodem_correlator_cache[j].refcnt <= 0 && hfmodem_correlator_cache[j].lru > l) {
-			k = j;
-			l = hfmodem_correlator_cache[j].lru;
-		}
-	if (k < HFMODEM_CORRELATOR_CACHE)
-		return k;
-	printk(KERN_ERR "%s: modem: out of filter coefficient cache entries\n", hfmodem_drvname);
-	return random_num() % HFMODEM_CORRELATOR_CACHE;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define SH1  8     /* min. ceil(log2(L1CORR_LEN)) - (31-(2*15-1)) */
-#define SH2  (3*15-2*SH1)
-
-#ifdef __i386__
-
-extern __inline__ int icorr(int n, const int *coeff, const short *inp)
-{
-	int ret, rethi, tmp1 = 0, tmp2 = 0;
-
-	__asm__("\n1:\n\t"
-		"movswl (%0),%%eax\n\t"
-		"imull (%1)\n\t"
-		"subl $2,%0\n\t"
-		"addl $4,%1\n\t"
-		"addl %%eax,%3\n\t"
-		"adcl %%edx,%4\n\t"
-		"decl %2\n\t"
-		"jne 1b\n\t"
-		: "=&S" (inp), "=&D" (coeff), "=&c" (n), "=m" (tmp1), "=m" (tmp2)
-		: "0" (inp), "1" (coeff), "2" (n)
-		: "ax", "dx");
-	__asm__("shrdl %2,%1,%0\n\t"
-		"# sarl %2,%1\n\t"
-		: "=&r" (ret), "=&r" (rethi)
-		: "i" (SH1), "0" (tmp1), "1" (tmp2));
-
-
-	return ret;
-}
-
-#else /* __i386__ */
-
-extern __inline__ int icorr(int n, const int *coeff, const short *inp)
-{
-	long long sum = 0;
-	int i;
-
-	for (i = n; i > 0; i--, coeff++, inp--)
-		sum += (*coeff) * (*inp);
-	sum >>= SH1;
-	return sum;
-}
-
-#endif /* __i386__ */
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ long long isqr(int x) __attribute__ ((const));
-
-extern __inline__ long long isqr(int x)
-{
-	return ((long long)x) * ((long long)x);
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ hfmodem_soft_t do_filter(struct hfmodem_l1_rxslot *slot, short *s)
-{
-	unsigned int cc = slot->corr_cache;
-	long long ll;
-
-	if (cc >= HFMODEM_CORRELATOR_CACHE) {
-		printk(KERN_ERR "do_filter: correlator cache index overrange\n");
-		return 0;
-	}
-	ll = isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[1][0], s)) +
-		isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[1][1], s)) -
-		isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[0][0], s)) -
-		isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[0][1], s));
-	ll >>= SH2;
-       	return (ll * slot->scale) >> 23;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void cc_prepare(struct hfmodem_l1_rxslot *slot, unsigned short phinc0, unsigned short phinc1)
-{
-	unsigned int j, k, l, ph, phinc;
-
-	slot->scale = (1<<23) / (slot->corrlen*slot->corrlen);
-
-	j = cc_lookup(phinc0, phinc1);
-	if (j >= HFMODEM_CORRELATOR_CACHE) {
-		j = cc_replace();
-		/* calculate the correlator values */
-		printk(KERN_DEBUG "%s: corr cache calc: %u  phases: 0x%04x 0x%04x\n", 
-		       hfmodem_drvname, j, phinc0, phinc1);
-		hfmodem_correlator_cache[j].phase_incs[0] = phinc0;
-		hfmodem_correlator_cache[j].phase_incs[1] = phinc1;
-		for (k = 0; k < 2; k++) {
-			phinc = hfmodem_correlator_cache[j].phase_incs[k];
-			for (ph = l = 0; l < HFMODEM_MAXCORRLEN; l++, ph = (ph + phinc) & 0xffff)
-				itblcossin(ph, &hfmodem_correlator_cache[j].correlator[k][0][l],
-					   &hfmodem_correlator_cache[j].correlator[k][1][l]);
-		}
-		hfmodem_correlator_cache[j].refcnt = 0;
-
-#if 0
-		printk(KERN_DEBUG "%s: corr: %u ph: 0x%04x 0x%04x\n", hfmodem_drvname, j, 
-		       hfmodem_correlator_cache[j].phase_incs[0],
-		       hfmodem_correlator_cache[j].phase_incs[1]);
-		for (l = 0; l < HFMODEM_MAXCORRLEN; l++)
-			printk(KERN_DEBUG "%s: corr: %6d %6d %6d %6d\n", hfmodem_drvname, 
-			       hfmodem_correlator_cache[j].correlator[0][0][l],
-			       hfmodem_correlator_cache[j].correlator[0][1][l],
-			       hfmodem_correlator_cache[j].correlator[1][0][l],
-			       hfmodem_correlator_cache[j].correlator[1][1][l]);
-#endif
-	}
-	slot->corr_cache = j;
-	cc_lock(j);
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_clear_rq(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-	unsigned int i;
-
-	save_flags(flags);
-	cli();
-	for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-		if (dev->l1.rxslots[i].state == ss_unused)
-			continue;
-		dev->l1.rxslots[i].state = ss_unused;
-		kfree_s(dev->l1.rxslots[i].data, dev->l1.rxslots[i].nbits * sizeof(hfmodem_soft_t));
-	}
-	for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-		if (dev->l1.txslots[i].state == ss_unused)
-			continue;
-		dev->l1.txslots[i].state = ss_unused;
-		kfree_s(dev->l1.txslots[i].data, (dev->l1.txslots[i].nbits + 7) >> 3);
-	}
-	for (i = 0; i < HFMODEM_CORRELATOR_CACHE; i++)
-		hfmodem_correlator_cache[i].refcnt = 0;
-	restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct hfmodem_state *dev = &hfmodem_state[0];
-	struct hfmodem_ioctl_fsk_tx_request txrq;
-	struct hfmodem_ioctl_fsk_rx_request rxrq;
-	struct hfmodem_ioctl_mixer_params mix;
-	struct hfmodem_ioctl_sample_params spar;
-	unsigned long flags;
-	unsigned int len;
-	int ret, i, idx;
-	void *data, *userdata;
-	hfmodem_id_t id;
-	hfmodem_time_t tm = 0;
-	
-	if (!dev->active)
-		return -EBUSY;
-	switch(cmd) {
-	default:
-		return -EINVAL;
-		
-	case HFMODEM_IOCTL_FSKTXREQUEST:
-		if ((ret = copy_from_user(&txrq, (void *)arg, sizeof(txrq))))
-			return ret;
-		if (txrq.nbits > HFMODEM_MAXBITS)
-			return -EINVAL;
-		len = (txrq.nbits + 7) >> 3;
-		if (!(data = kmalloc(len, GFP_KERNEL)))
-			return -ENOMEM;
-		if (copy_from_user(data, txrq.data, len)) {
-			kfree_s(data, len);
-			return -EFAULT;
-		}
-		save_flags(flags);
-		cli();
-		for (i = 0; i < HFMODEM_NUMTXSLOTS && dev->l1.txslots[i].state != ss_unused; i++);
-		if (i >= HFMODEM_NUMTXSLOTS) {
-			restore_flags(flags);
-			kfree_s(data, len);
-			return -EBUSY;
-		}
-		dev->l1.txslots[i].state = ss_ready;
-		dev->l1.txslots[i].tstart = txrq.tstart;
-		dev->l1.txslots[i].tinc = txrq.tinc;
-		dev->l1.txslots[i].data = data;
-		dev->l1.txslots[i].nbits = txrq.nbits;
-		dev->l1.txslots[i].cntbits = 0;
-		dev->l1.txslots[i].inv = txrq.inv ? 0xff : 0;
-		dev->l1.txslots[i].id = txrq.id;
-		dev->l1.txslots[i].phase_incs[0] = ((txrq.freq[0]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE)
-			& 0xffff;
-		dev->l1.txslots[i].phase_incs[1] = ((txrq.freq[1]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE)
-			& 0xffff;
-		restore_flags(flags);
-		return 0;
-		
-	case HFMODEM_IOCTL_FSKRXREQUEST:
-		if ((ret = copy_from_user(&rxrq, (void *)arg, sizeof(rxrq))))
-			return ret;
-		if (rxrq.nbits > HFMODEM_MAXBITS)
-			return -EINVAL;
-		if (rxrq.baud < HFMODEM_MINBAUD || rxrq.baud > HFMODEM_MAXBAUD)
-			return -EINVAL;
-		len = rxrq.nbits * sizeof(hfmodem_soft_t);
-		if (verify_area(VERIFY_WRITE, rxrq.data, len))
-			return -EFAULT;
-		if (!(data = kmalloc(len, GFP_KERNEL)))
-			return -ENOMEM;
-		save_flags(flags);
-		cli();
-		for (i = 0; i < HFMODEM_NUMRXSLOTS && dev->l1.rxslots[i].state != ss_unused; i++);
-		if (i >= HFMODEM_NUMRXSLOTS) {
-			restore_flags(flags);
-			kfree_s(data, len);
-			return -EBUSY;
-		}
-		dev->l1.rxslots[i].state = ss_ready;
-		dev->l1.rxslots[i].tstart = rxrq.tstart;
-		dev->l1.rxslots[i].tinc = rxrq.tinc;
-		dev->l1.rxslots[i].data = data;
-		dev->l1.rxslots[i].userdata = rxrq.data;
-		dev->l1.rxslots[i].nbits = rxrq.nbits;
-		dev->l1.rxslots[i].cntbits = 0;
-		dev->l1.rxslots[i].id = rxrq.id;
-		dev->l1.rxslots[i].corrlen = HFMODEM_SRATE/rxrq.baud;
-		cc_prepare(dev->l1.rxslots+i, 
-			   ((rxrq.freq[0]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE) & 0xffff,
-			   ((rxrq.freq[1]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE) & 0xffff);
-		restore_flags(flags);
-		return 0;
-		
-	case HFMODEM_IOCTL_CLEARRQ:
-		hfmodem_clear_rq(dev);
-		return 0;
-		
-	case HFMODEM_IOCTL_GETCURTIME:
-		return put_user(dev->l1.last_time + 20000L, (hfmodem_time_t *)arg); /* heuristic */
-	
-	case HFMODEM_IOCTL_WAITRQ:
-		save_flags(flags);
-		cli();
-		ret = 0;
-		for (idx = -1, i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-			if (dev->l1.rxslots[i].state == ss_unused)
-				continue;
-			if (dev->l1.rxslots[i].state != ss_retired) {
-				ret++;
-				continue;
-			}
-			if (idx < 0 || (signed)(tm - dev->l1.rxslots[i].tstart) > 0) {
-				idx = i;
-				tm = dev->l1.rxslots[i].tstart;
-			}
-		}
-		if (idx >= 0) {
-			cc_unlock(dev->l1.rxslots[idx].corr_cache);
-			id = dev->l1.rxslots[idx].id;
-			data = dev->l1.rxslots[idx].data;
-			userdata = dev->l1.rxslots[idx].userdata;
-			len = dev->l1.rxslots[idx].nbits * sizeof(hfmodem_soft_t);
-			dev->l1.rxslots[idx].state = ss_unused;
-			restore_flags(flags);
-			ret = copy_to_user(userdata, data, len);
-			kfree_s(data, len);
-			return (put_user(id, (hfmodem_id_t *)arg)) ? -EFAULT : ret;
-		}
-		for (idx = -1, i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-			if (dev->l1.txslots[i].state == ss_unused)
-				continue;
-			if (dev->l1.txslots[i].state != ss_retired) {
-				ret++;
-				continue;
-			}
-			if (idx < 0 || (signed)(tm - dev->l1.txslots[i].tstart) > 0) {
-				idx = i;
-				tm = dev->l1.txslots[i].tstart;
-			}
-		}
-		if (idx >= 0) {
-			id = dev->l1.txslots[idx].id;
-			data = dev->l1.txslots[idx].data;
-			len = (dev->l1.txslots[idx].nbits + 7) >> 3;
-			dev->l1.txslots[idx].state = ss_unused;
-			restore_flags(flags);
-			kfree_s(data, len);
-			return put_user(id, (hfmodem_id_t *)arg);
-		}
-		restore_flags(flags);
-		return ret ? -EAGAIN : -EPIPE;
-
-	case HFMODEM_IOCTL_MIXERPARAMS:
-		if ((ret = copy_from_user(&mix, (void *)arg, sizeof(mix))))
-			return ret;
-		dev->scops->mixer(dev, mix.src, mix.igain, mix.ogain);
-		return 0;
-		
-	case HFMODEM_IOCTL_SAMPLESTART:
-		save_flags(flags);
-		cli();
-		if (dev->sbuf.kbuf) 
-			kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
-		dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
-		dev->sbuf.size = dev->sbuf.rem = 0;
-		restore_flags(flags);
-		if ((ret = copy_from_user(&spar, (void *)arg, sizeof(spar))))
-			return ret;
-		if (spar.len == 0)
-			return 0;
-		if (spar.len < 2 || spar.len > 8192)
-			return -EINVAL;
-		if (verify_area(VERIFY_WRITE, spar.data, spar.len * sizeof(__s16)))
-			return -EFAULT;
-		if (!(dev->sbuf.kbuf = kmalloc(spar.len * sizeof(__s16), GFP_KERNEL)))
-			return -ENOMEM;
-		save_flags(flags);
-		cli();
-		dev->sbuf.kptr = dev->sbuf.kbuf;
-		dev->sbuf.size = spar.len * sizeof(__s16);
-		dev->sbuf.rem = spar.len;
-		dev->sbuf.ubuf = spar.data;
-		restore_flags(flags);
-		return 0;
-		
-	case HFMODEM_IOCTL_SAMPLEFINISHED:
-		save_flags(flags);
-		cli();
-		if (dev->sbuf.rem > 0) {
-			restore_flags(flags);
-			return -EAGAIN;
-		}
-		if (!dev->sbuf.kbuf || !dev->sbuf.size) {
-			restore_flags(flags);
-			return -EPIPE;
-		}
-		restore_flags(flags);
-		ret = copy_to_user(dev->sbuf.ubuf, dev->sbuf.kbuf, dev->sbuf.size);
-		kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
-		dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
-		dev->sbuf.size = dev->sbuf.rem = 0;
-		return ret;
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-#if LINUX_VERSION_CODE >= 0x20100
-
-unsigned int hfmodem_poll(struct file *file, poll_table *wait)
-{
-	struct hfmodem_state *dev = &hfmodem_state[0];
-	unsigned long flags;
-	int i, cnt1, cnt2;
-	
-	poll_wait(file, &dev->wait, wait);
-	save_flags(flags);
-	cli();
-	for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-		if (dev->l1.txslots[i].state == ss_retired)
-			cnt1++;
-		if (dev->l1.txslots[i].state != ss_unused)
-			cnt2++;
-	}
-	for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-		if (dev->l1.rxslots[i].state == ss_retired)
-			cnt1++;
-		if (dev->l1.rxslots[i].state != ss_unused)
-			cnt2++;
-	}
-	restore_flags(flags);
-        if (cnt1 || !cnt2)
-                return POLLIN | POLLRDNORM;
-        return 0;
-}
-
-#else 
-
-int hfmodem_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
-{
-	struct hfmodem_state *dev = &hfmodem_state[0];
-	unsigned long flags;
-	int i, cnt1, cnt2;
-	
-	if (sel_type == SEL_IN) {
-		save_flags(flags);
-		cli();
-		for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-			if (dev->l1.txslots[i].state == ss_retired)
-				cnt1++;
-			if (dev->l1.txslots[i].state != ss_unused)
-				cnt2++;
-		}
-		for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-			if (dev->l1.rxslots[i].state == ss_retired)
-				cnt1++;
-			if (dev->l1.rxslots[i].state != ss_unused)
-				cnt2++;
-		}
-		restore_flags(flags);
-		if (cnt1 || !cnt2)
-			return 1;
-		select_wait(&dev->wait, wait);
-    	}
-	return 0;
-}
-
-#endif
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int l1fsk_phinc(struct hfmodem_l1_txslot *txs, unsigned int nbit)
-{
-	return txs->phase_incs[!!((txs->data[nbit >> 3] ^ txs->inv) & (1 << (nbit & 7)))];
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_input_samples(struct hfmodem_state *dev, hfmodem_time_t tstart, 
-			 hfmodem_time_t tinc, __s16 *samples)
-{
-	hfmodem_time_t tst, tend;
-	__s16 *s;
-	int i, j;
-	hfmodem_soft_t sample;
-
-	dev->l1.last_time = tstart + (HFMODEM_FRAGSAMPLES-1) * tinc;
-	for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-		struct hfmodem_l1_rxslot *rxs = dev->l1.rxslots + i;
-
-		if (rxs->state == ss_unused || rxs->state == ss_retired)
-			continue;
-		tst = tstart - (rxs->corrlen-1) * tinc;
-		tend = tst + (HFMODEM_FRAGSAMPLES-1) * tinc;
-		if (rxs->state == ss_ready) {
-			if ((signed)(rxs->tstart - tend) > 0) 
-				continue;
-			rxs->state = ss_oper;
-		}
-		for (s = samples, j = 0; j < HFMODEM_FRAGSAMPLES; j++, s++, tst += tinc)
-			if ((signed)(rxs->tstart - tst) <= 0) {
-				sample = do_filter(rxs, s);
-				while ((signed)(rxs->tstart - tst) <= 0 && 
-				       rxs->cntbits < rxs->nbits) {
-					rxs->data[rxs->cntbits] = sample;
-					rxs->cntbits++;
-					rxs->tstart += rxs->tinc;
-				}
-				if (rxs->cntbits >= rxs->nbits) {
-					rxs->state = ss_retired;
-					break;
-				}
-			}
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ unsigned int output_one_sample(struct hfmodem_state *dev, hfmodem_time_t tm)
-{
-	int i, j, k;
-	struct hfmodem_l1_txslot *txs;
-	/*
-	 * first activate new output slots
-	 */
-	for (j = -1, i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-		txs = dev->l1.txslots + i;
-		if (txs->state == ss_ready && (signed)(txs->tstart - tm) <= 0) {
-			for (k = 0; k < HFMODEM_NUMTXSLOTS; k++) {
-				if (dev->l1.txslots[k].state != ss_oper)
-					continue;
-				dev->l1.txslots[k].state = ss_retired;
-			}
-			txs->state = ss_oper;
-			txs->tstart += txs->tinc;
-			txs->phinc = l1fsk_phinc(txs, 0);
-			txs->cntbits = 1;
-		};
-		if (txs->state != ss_oper)
-			continue;
-		j = i;
-	}
-	if (j < 0 || j >= HFMODEM_NUMTXSLOTS)
-		return 0;
-	/*
-	 * calculate the current slot
-	 */
-	txs = dev->l1.txslots + j;
-	while ((signed)(txs->tstart - tm) <= 0) {
-		if (txs->cntbits >= txs->nbits) {
-			txs->state = ss_retired;
-			return 0;
-		}
-		txs->tstart += txs->tinc;
-		txs->phinc = l1fsk_phinc(txs, txs->cntbits);
-		txs->cntbits++;
-	}
-	return txs->phinc;
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_output_samples(struct hfmodem_state *dev, hfmodem_time_t tstart, 
-			   hfmodem_time_t tinc, __s16 *samples)
-{
-	int i, j;
-	hfmodem_time_t tend = tstart + (HFMODEM_FRAGSAMPLES-1) * tinc;
-
-	for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-		if (dev->l1.txslots[i].state == ss_oper)
-			break;
-		if (dev->l1.txslots[i].state == ss_ready && 
-		    (signed)(dev->l1.txslots[i].tstart - tend) <= 0)
-			break;
-	}
-	if (i >= HFMODEM_NUMTXSLOTS)
-		return 0;
-	for (j = 0; j < HFMODEM_FRAGSAMPLES; j++, tstart += tinc, samples++) {
-		*samples = isimplecos(dev->l1.tx_phase);
-		dev->l1.tx_phase += output_one_sample(dev, tstart);
-	}
-	return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-long hfmodem_next_tx_event(struct hfmodem_state *dev, hfmodem_time_t curr)
-{
-	long diff = LONG_MAX, t;
-	int i;
-
-	for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-		if (dev->l1.txslots[i].state == ss_oper)
-			if (diff > 0)
-				diff = 0;
-		if (dev->l1.txslots[i].state == ss_ready) {
-			t = dev->l1.txslots[i].tstart - curr;
-			if (t < diff)
-				diff = t;
-		}
-	}
-	return diff;
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_finish_pending_rx_requests(struct hfmodem_state *dev)
-{
-	int i;
-
-	for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-		if (dev->l1.rxslots[i].state != ss_oper)
-			continue;
-		while (dev->l1.rxslots[i].cntbits < dev->l1.rxslots[i].nbits) {
-			dev->l1.rxslots[i].data[dev->l1.rxslots[i].cntbits] = 0;
-			dev->l1.rxslots[i].cntbits++;
-		}
-		dev->l1.rxslots[i].state = ss_retired;
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_wakeup(struct hfmodem_state *dev)
-{
-	int i, cnt1, cnt2;
-	
-	for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
-		if (dev->l1.txslots[i].state == ss_retired)
-			cnt1++;
-		if (dev->l1.txslots[i].state != ss_unused)
-			cnt2++;
-	}
-	for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
-		if (dev->l1.rxslots[i].state == ss_retired)
-			cnt1++;
-		if (dev->l1.rxslots[i].state != ss_unused)
-			cnt2++;
-	}
-	if (cnt1 || !cnt2)
-		wake_up_interruptible(&dev->wait);
-}
-
-/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/refclock.c linux/drivers/char/hfmodem/refclock.c
--- v2.3.12/linux/drivers/char/hfmodem/refclock.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/hfmodem/refclock.c	Wed Dec 31 16:00:00 1969
@@ -1,154 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      refclock.c  --  Linux soundcard HF FSK driver,
- *                      Reference clock routines.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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.
- *
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/hfmodem.h>
-#include <asm/processor.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-/*
- * command line params
- */
-
-static unsigned int scale_tvusec = 1UL<<24;
-
-#ifdef __i386__
-static unsigned int scale_rdtsc = 0;
-static int rdtsc_ok = 1;
-#endif /* __i386__ */
-
-/* --------------------------------------------------------------------- */
-
-#ifdef __i386__
-static void __init i386_capability(void)
-{
-	if (boot_cpu_data.x86_capability & X86_FEATURE_TSC)
-		rdtsc_ok = 1;
-	else
-		printk(KERN_INFO "%s: cpu does not support the rdtsc instruction\n", hfmodem_drvname);
-}
-#endif /* __i386__ */   
-
-/* --------------------------------------------------------------------- */
-
-void __init hfmodem_refclock_probe(void)
-{
-#ifdef __i386__
-	if (rdtsc_ok) {
-		rdtsc_ok = 0;
-		i386_capability();
-		if (rdtsc_ok) {
-			unsigned int tmp0, tmp1, tmp2, tmp3;
-			__asm__("rdtsc" : "=a" (tmp0), "=d" (tmp1));
-			__asm__("rdtsc" : "=a" (tmp2), "=d" (tmp3));
-			if (tmp0 == tmp2 && tmp1 == tmp3) {
-				rdtsc_ok = 0;
-				printk(KERN_WARNING "%s: rdtsc unusable, does not change\n",
-				       hfmodem_drvname);
-			}
-		}
-	}
-	printk(KERN_INFO "%s: using %s as timing source\n", hfmodem_drvname,
-	       rdtsc_ok ? "rdtsc" : "gettimeofday");
-#endif /* __i386__ */
-}
-
-/* --------------------------------------------------------------------- */
-
-void hfmodem_refclock_init(struct hfmodem_state *dev)
-{
-	struct timeval tv;
-
-	dev->clk.lasttime = 0;
-#ifdef __i386__
-	if (rdtsc_ok) {
-		__asm__("rdtsc;" : "=&d" (dev->clk.starttime_hi), "=&a" (dev->clk.starttime_lo));
-		return;
-	}
-#endif /* __i386__ */
-	do_gettimeofday(&tv);
-	dev->clk.last_tvusec = tv.tv_usec;
-	dev->clk.time_cnt = 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-hfmodem_time_t hfmodem_refclock_current(struct hfmodem_state *dev, hfmodem_time_t expected, int exp_valid)
-{
-	struct timeval tv;
-	hfmodem_time_t curtime;
-	long diff;
-
-#ifdef __i386__
-	if (rdtsc_ok) {
-		unsigned int tmp0, tmp1;
-		unsigned int tmp2, tmp3;
-		
-		__asm__("rdtsc;\n\t"
-			"subl %2,%%eax\n\t"
-			"sbbl %3,%%edx\n\t" : "=&a" (tmp0), "=&d" (tmp1) 
-			: "m" (dev->clk.starttime_lo), "m" (dev->clk.starttime_hi) : "ax", "dx");
-		__asm__("mull %1" : "=d" (tmp2) : "m" (scale_rdtsc), "a" (tmp0) : "ax");
-		__asm__("mull %1" : "=a" (tmp3) : "m" (scale_rdtsc), "a" (tmp1) : "dx");
-		curtime = tmp2 + tmp3;
-		goto time_known;
-	}
-#endif /* __i386__ */
-	do_gettimeofday(&tv);
-	dev->clk.time_cnt += (unsigned)(1000000 + tv.tv_usec - dev->clk.last_tvusec) % 1000000;
-	dev->clk.last_tvusec = tv.tv_usec;
-	curtime = (dev->clk.time_cnt * scale_tvusec) >> 24;
-  time_known:
-	if (exp_valid && abs(diff = (curtime - dev->clk.lasttime - expected)) >= 1000)
-		printk(KERN_DEBUG "%s: refclock adjustment %ld more than 1ms\n", 
-		       hfmodem_drvname, diff);
-	return (dev->clk.lasttime = curtime);
-}
-
-/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/sbc.c linux/drivers/char/hfmodem/sbc.c
--- v2.3.12/linux/drivers/char/hfmodem/sbc.c	Tue Aug  5 09:48:55 1997
+++ linux/drivers/char/hfmodem/sbc.c	Wed Dec 31 16:00:00 1969
@@ -1,741 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      sbc.c  --  Linux soundcard HF FSK driver, 
- *                 Soundblaster specific functions.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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.
- *
- *
- */
-
-/*****************************************************************************/
-     
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/hfmodem.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-/* --------------------------------------------------------------------- */
-/* 
- * the sbc converter's registers 
- */
-#define DSP_RESET(iobase)        (iobase+0x6)
-#define DSP_READ_DATA(iobase)    (iobase+0xa)
-#define DSP_WRITE_DATA(iobase)   (iobase+0xc)
-#define DSP_WRITE_STATUS(iobase) (iobase+0xc)
-#define DSP_DATA_AVAIL(iobase)   (iobase+0xe)
-#define DSP_MIXER_ADDR(iobase)   (iobase+0x4)
-#define DSP_MIXER_DATA(iobase)   (iobase+0x5)
-#define DSP_INTACK_16BIT(iobase) (iobase+0xf)
-#define SBC_EXTENT               16
-
-/* --------------------------------------------------------------------- */
-/*
- * SBC commands
- */
-
-#define SBC_OUTPUT             0x14
-#define SBC_INPUT              0x24
-#define SBC_BLOCKSIZE          0x48
-#define SBC_HI_OUTPUT          0x91 
-#define SBC_HI_INPUT           0x99 
-#define SBC_LO_OUTPUT_AUTOINIT 0x1c
-#define SBC_LO_INPUT_AUTOINIT  0x2c
-#define SBC_HI_OUTPUT_AUTOINIT 0x90 
-#define SBC_HI_INPUT_AUTOINIT  0x98
-#define SBC_IMMED_INT          0xf2
-#define SBC_GET_REVISION       0xe1
-#define ESS_GET_REVISION       0xe7
-#define ESS_EXTENDED_MODE      0xc6
-#define SBC_SPEAKER_ON         0xd1
-#define SBC_SPEAKER_OFF        0xd3
-#define SBC_DMA_ON             0xd0
-#define SBC_DMA_OFF            0xd4
-#define SBC_SAMPLE_RATE        0x40
-#define SBC_SAMPLE_RATE_OUT    0x41
-#define SBC_SAMPLE_RATE_IN     0x42
-#define SBC_MONO_8BIT          0xa0
-#define SBC_MONO_16BIT         0xa4
-#define SBC_STEREO_8BIT        0xa8
-#define SBC_STEREO_16BIT       0xac
-
-#define SBC4_OUT8_AI           0xc6
-#define SBC4_IN8_AI            0xce
-#define SBC4_MODE_UNS_MONO     0x00
-#define SBC4_MODE_SIGN_MONO    0x10
-
-#define SBC4_OUT16_AI          0xb6
-#define SBC4_IN16_AI           0xbe
-#define SBC4_OUT16_AI_NO_FIFO  0xb4
-#define SBC4_IN16_AI_NO_FIFO   0xbc
-
-/* --------------------------------------------------------------------- */
-
-extern const struct hfmodem_scops sbc4_scops;
-extern const struct hfmodem_scops ess_scops;
-
-/* --------------------------------------------------------------------- */
-
-static int reset_dsp(struct hfmodem_state *dev)
-{
-        int i;
-
-        outb(1, DSP_RESET(dev->io.base_addr));
-	udelay(3);
-        outb(0, DSP_RESET(dev->io.base_addr));
-        for (i = 0; i < 0xffff; i++)
-                if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80)
-                        if (inb(DSP_READ_DATA(dev->io.base_addr)) == 0xaa)
-                                return 1;
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void write_dsp(struct hfmodem_state *dev, unsigned char data)
-{
-        int i;
-        
-        for (i = 0; i < 0xffff; i++)
-                if (!(inb(DSP_WRITE_STATUS(dev->io.base_addr)) & 0x80)) {
-                        outb(data, DSP_WRITE_DATA(dev->io.base_addr));
-                        return;
-                }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int read_dsp(struct hfmodem_state *dev, unsigned char *data)
-{
-        int i;
-
-        if (!data)
-                return 0;
-        for (i = 0; i < 0xffff; i++) 
-                if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80) {
-                        *data = inb(DSP_READ_DATA(dev->io.base_addr));
-                        return 1;
-                }
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void write_ess(struct hfmodem_state *dev, unsigned char reg, unsigned char data)
-{
-	write_dsp(dev, reg);
-	write_dsp(dev, data);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int read_ess(struct hfmodem_state *dev, unsigned char reg, unsigned char *data)
-{
-	write_dsp(dev, 0xc0);
-	write_dsp(dev, reg);
-	return read_dsp(dev, data);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int reset_ess(struct hfmodem_state *dev)
-{
-        int i;
-
-        outb(3, DSP_RESET(dev->io.base_addr)); /* reset FIFOs too */
-	udelay(3);
-        outb(0, DSP_RESET(dev->io.base_addr));
-        for (i = 0; i < 0xffff; i++)
-                if (inb(DSP_DATA_AVAIL(dev->io.base_addr)) & 0x80)
-                        if (inb(DSP_READ_DATA(dev->io.base_addr)) == 0xaa) {
-				write_dsp(dev, ESS_EXTENDED_MODE);
-                                return 1;
-			}
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int config_resources(struct hfmodem_state *dev)
-{
-        unsigned char irqreg = 0, dmareg = 0, realirq, realdma;
-        unsigned long flags;
-
-        switch (dev->io.irq) {
-        case 2:
-        case 9:
-                irqreg |= 0x01;
-                break;
-
-        case 5:
-                irqreg |= 0x02;
-                break;
-
-        case 7:
-                irqreg |= 0x04;
-                break;
-
-        case 10:
-                irqreg |= 0x08;
-                break;
-                
-        default:
-                return -ENODEV;
-        }
-
-        switch (dev->io.dma) {
-        case 0:
-                dmareg |= 0x01;
-                break;
-
-        case 1:
-                dmareg |= 0x02;
-                break;
-
-        case 3:
-                dmareg |= 0x08;
-                break;
-
-	case 5:
-		dmareg |= 0x20;
-		break;
-		
-	case 6:
-		dmareg |= 0x40;
-		break;
-		
-	case 7:
-		dmareg |= 0x80;
-		break;
-		
-         default:
-                return -ENODEV;
-        }
-        save_flags(flags);
-        cli();
-        outb(0x80, DSP_MIXER_ADDR(dev->io.base_addr));
-        outb(irqreg, DSP_MIXER_DATA(dev->io.base_addr));
-        realirq = inb(DSP_MIXER_DATA(dev->io.base_addr));
-        outb(0x81, DSP_MIXER_ADDR(dev->io.base_addr));
-        outb(dmareg, DSP_MIXER_DATA(dev->io.base_addr));
-        realdma = inb(DSP_MIXER_DATA(dev->io.base_addr));
-        restore_flags(flags);
-        if ((~realirq) & irqreg || (~realdma) & dmareg) {
-                printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device "
-                       "and IRQ/DMA specified wrongly?\n", hfmodem_drvname);
-                return -EINVAL;
-        }
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void sbc_int_ack_8bit(struct hfmodem_state *dev)
-{
-        inb(DSP_DATA_AVAIL(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void sbc_int_ack_16bit(struct hfmodem_state *dev)
-{
-        inb(DSP_INTACK_16BIT(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-static void set_mixer(struct hfmodem_state *dev, unsigned char reg, unsigned char data)
-{
-	outb(reg, DSP_MIXER_ADDR(dev->io.base_addr));
-	outb(data, DSP_MIXER_DATA(dev->io.base_addr));
-}	
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_sbcprobe(struct hfmodem_state *dev)
-{
-	unsigned char revhi, revlo, essrevhi, essrevlo, tmp;
-	int ret;
-
-	if (dev->io.base_addr <= 0 || dev->io.base_addr > 0x1000-SBC_EXTENT || 
-            dev->io.irq < 2 || dev->io.irq > 15 || dev->io.dma > 7 || dev->io.dma == 2)
-                return -ENXIO;
-        if (check_region(dev->io.base_addr, SBC_EXTENT))
-                return -EACCES;
-        /*
-         * check if a card is available
-         */
-        if (!reset_dsp(dev)) {
-                printk(KERN_ERR "%s: sbc: no card at io address 0x%x\n", 
-		       hfmodem_drvname, dev->io.base_addr);
-                return -ENODEV;
-        }
-	set_mixer(dev, 0, 0); /* reset mixer */
-        write_dsp(dev, SBC_GET_REVISION);
-        if (!read_dsp(dev, &revhi) || !read_dsp(dev, &revlo))
-                return -ENODEV;
-        printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%02d\n", hfmodem_drvname, revhi, revlo);
-	if (revhi == 3 && revlo == 1) {
-		write_dsp(dev, ESS_GET_REVISION);
-		if (!read_dsp(dev, &essrevhi) || !read_dsp(dev, &essrevlo))
-			return -ENODEV;
-		if (essrevhi == 0x48 && (essrevlo & 0xf0) == 0x80) {
-			printk(KERN_INFO "%s: ESS ES488 AudioDrive (rev %d): unsupported.\n",
-			       hfmodem_drvname, essrevlo & 0x0f);
-			return -ENODEV;
-		}
-		if (essrevhi == 0x68 && (essrevlo & 0xf0) == 0x80) {
-			printk(KERN_INFO "%s: ESS ES%s688 AudioDrive (rev %d)\n",
-			       hfmodem_drvname, ((essrevlo & 0x0f) >= 8) ? "1" : "", essrevlo & 0x0f);
-			if (dev->io.dma > 3) {
-				printk(KERN_INFO "%s: DMA number out of range\n", hfmodem_drvname);
-				return -ENXIO;
-			}
-			printk(KERN_INFO "%s: ess: irq: ", hfmodem_drvname);
-			read_ess(dev, 0xb1, &tmp);
-			switch (tmp & 0xf) {
-			case 0:
-				printk("2, 9, \"all others\"");
-				break;
-			       
-			case 5:
-				printk("5");
-				break;
-
-			case 10:
-				printk("7");
-				break;
-
-			case 15:
-				printk("10");
-				break;
-
-			default:
-				printk("unknown (%d)", tmp & 0xf);
-				break;
-			}
-			printk(" dma: ");
-			read_ess(dev, 0xb2, &tmp);
-			switch (tmp & 0xf) {
-			case 0:
-				printk("\"all others\"");
-				break;
-			       
-			case 5:
-				printk("0");
-				break;
-
-			case 10:
-				printk("1");
-				break;
-
-			case 15:
-				printk("3");
-				break;
-
-			default:
-				printk("unknown (%d)", tmp & 0xf);
-				break;
-			}
-			printk("\n");
-			dev->scops = &ess_scops;
-			return 0;
-		}
-	}
-	if (revhi < 4) {
-		printk(KERN_INFO "%s: at least SB16 required\n", hfmodem_drvname);
-		return -ENODEV;
-	}
-	if (dev->io.dma < 4) {
-		printk(KERN_INFO "%s: DMA number out of range\n", hfmodem_drvname);
-		return -ENXIO;
-	}
-	if ((ret = config_resources(dev)))
-		return ret;
-	dev->scops = &sbc4_scops;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_init(struct hfmodem_state *dev)
-{
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_prepare_input(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-        if (!reset_dsp(dev)) {
-                printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", hfmodem_drvname);
-                return;
-        }
-        save_flags(flags);
-        cli();
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        set_dma_mode(dev->io.dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-        set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-        enable_dma(dev->io.dma);
-        sbc_int_ack_16bit(dev);
-        write_dsp(dev, SBC_SAMPLE_RATE_IN); /* set sampling rate */
-        write_dsp(dev, HFMODEM_SRATE >> 8);
-        write_dsp(dev, HFMODEM_SRATE & 0xff);
-        write_dsp(dev, SBC_SPEAKER_OFF); 
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_trigger_input(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-        save_flags(flags);
-        cli();
-	write_dsp(dev, SBC4_IN16_AI_NO_FIFO);
-	write_dsp(dev, SBC4_MODE_UNS_MONO);
-	write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) & 0xff);
-	write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) >> 8);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_prepare_output(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-        if (!reset_dsp(dev)) {
-                printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", hfmodem_drvname);
-                return;
-        }
-        save_flags(flags);
-        cli();
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        set_dma_mode(dev->io.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-        set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-        enable_dma(dev->io.dma);
-        sbc_int_ack_16bit(dev);
-        write_dsp(dev, SBC_SAMPLE_RATE_OUT); /* set sampling rate */
-        write_dsp(dev, HFMODEM_SRATE >> 8);
-        write_dsp(dev, HFMODEM_SRATE & 0xff);
-        write_dsp(dev, SBC_SPEAKER_ON); 
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_trigger_output(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-        save_flags(flags);
-        cli();
-	write_dsp(dev, SBC4_OUT16_AI_NO_FIFO);
-	write_dsp(dev, SBC4_MODE_UNS_MONO);
-	write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) & 0xff);
-	write_dsp(dev, (HFMODEM_FRAGSAMPLES-1) >> 8);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_stop(struct hfmodem_state *dev)
-{
-	reset_dsp(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int sbc4_intack(struct hfmodem_state *dev)
-{
-	unsigned int dmaptr;
-	unsigned long flags;
-	unsigned char intsrc;
-
-	save_flags(flags);
-        cli();
-        outb(0x82, DSP_MIXER_ADDR(dev->io.base_addr));
-        intsrc = inb(DSP_MIXER_DATA(dev->io.base_addr));
-        if (intsrc & 0x01) 
-                sbc_int_ack_8bit(dev);
-        if (intsrc & 0x02)
-		sbc_int_ack_16bit(dev);
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        dmaptr = get_dma_residue(dev->io.dma);
-        enable_dma(dev->io.dma);
-	restore_flags(flags);
-	if (dmaptr == 0 || dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
-		dmaptr = HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
-	return (HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE - dmaptr) / 2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void sbc4_mixer(struct hfmodem_state *dev, int src, int igain, int ogain)
-{
-	unsigned long flags;
-	static const unsigned char srcbits[3] = { 0x18, 0x01, 0x06 };
-
-	save_flags(flags);
-	cli();
-	if (src >= 0 && src <= 2) {
-		set_mixer(dev, 0x3d, srcbits[src]);
-		set_mixer(dev, 0x3e, srcbits[src]);
-	}
-	if (ogain >= 0 && ogain <= 255) {
-		set_mixer(dev, 0x30, ogain);
-		set_mixer(dev, 0x31, ogain);
-	}
-	if (igain >= 0 && igain <= 255) {
-		set_mixer(dev, 0x36, igain);
-		set_mixer(dev, 0x37, igain);
-		set_mixer(dev, 0x38, igain);
-		set_mixer(dev, 0x39, igain);
-		set_mixer(dev, 0x3a, igain);
-	}
-	set_mixer(dev, 0x32, 0xff);
-	set_mixer(dev, 0x33, 0xff);
-	set_mixer(dev, 0x34, 0);
-	set_mixer(dev, 0x35, 0);
-	set_mixer(dev, 0x3b, 0); /* pc spkr vol */
-	set_mixer(dev, 0x3c, 0); /* output src */
-	set_mixer(dev, 0x3f, 0); /* inp gain */
-	set_mixer(dev, 0x40, 0);
-	set_mixer(dev, 0x41, 0); /* outp gain */
-	set_mixer(dev, 0x42, 0);
-	set_mixer(dev, 0x43, 1); /* mic agc off */
-	set_mixer(dev, 0x44, 8<<4); /* treble */
-	set_mixer(dev, 0x45, 8<<4); 
-	set_mixer(dev, 0x46, 8<<4); /* bass */
-	set_mixer(dev, 0x47, 8<<4); 	
-	restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void ess_prepare_input(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-	unsigned char tmp;
-
-        if (!reset_ess(dev)) {
-                printk(KERN_ERR "%s: sbc: cannot reset ess dsp\n", hfmodem_drvname);
-                return;
-        }
-        save_flags(flags);
-        cli();
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        set_dma_mode(dev->io.dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-        set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-        enable_dma(dev->io.dma);
-        sbc_int_ack_8bit(dev);
-	write_ess(dev, 0xa1, 128 - (397700 + HFMODEM_SRATE/2) / HFMODEM_SRATE);
-	/*
-	 * Set filter divider register
-	 * Rolloff at 90% of the half sampling rate
-	 */
-	write_ess(dev, 0xa2, 256-(7160000 / (82 * (HFMODEM_SRATE * 9 / 20))));
-        write_dsp(dev, SBC_SPEAKER_OFF); 
-	write_ess(dev, 0xb8, 0x0e); /* Auto init DMA mode */
-	read_ess(dev, 0xa8, &tmp);
-	write_ess(dev, 0xa8, (tmp & ~0x03) | 2);     /* Mono */
-	write_ess(dev, 0xb9, 2);    /* Demand mode (4 bytes/DMA request) */
-	/* 16 bit mono */
-	write_ess(dev, 0xb7, 0x71);
-	write_ess(dev, 0xb7, 0xf4);
-
-	read_ess(dev, 0xb1, &tmp);
-	write_ess(dev, 0xb1, (tmp & 0x0f) | 0x50);
-	read_ess(dev, 0xb2, &tmp);
-	write_ess(dev, 0xb2, (tmp & 0x0f) | 0x50);
- 
-	write_ess(dev, 0xa4, (unsigned char) ((-HFMODEM_FRAGSIZE) & 0xff));
-	write_ess(dev, 0xa5, (unsigned char) (((-HFMODEM_FRAGSIZE) >> 8) & 0xff));
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void ess_trigger_input(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-	unsigned char tmp;
-
-        save_flags(flags);
-        cli();
-	read_ess(dev, 0xb8, &tmp);
-	write_ess(dev, 0xb8, tmp | 0x0f);         /* Go */
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-void ess_prepare_output(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-	unsigned char tmp;
-
-        if (!reset_ess(dev)) {
-                printk(KERN_ERR "%s: sbc: cannot reset ess dsp\n", hfmodem_drvname);
-                return;
-        }
-        save_flags(flags);
-        cli();
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        set_dma_mode(dev->io.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-        set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-        enable_dma(dev->io.dma);
-        sbc_int_ack_8bit(dev);
-	write_ess(dev, 0xa1, 128 - (397700 + HFMODEM_SRATE/2) / HFMODEM_SRATE);
-	/*
-	 * Set filter divider register
-	 * Rolloff at 90% of the half sampling rate
-	 */
-	write_ess(dev, 0xa2, 256-(7160000 / (82 * (HFMODEM_SRATE * 9 / 20))));
-	write_ess(dev, 0xb8, 0x04); /* Auto init DMA mode */
-	read_ess(dev, 0xa8, &tmp);
-	write_ess(dev, 0xa8, (tmp & ~0x03) | 2);     /* Mono */
-	write_ess(dev, 0xb9, 2);    /* Demand mode (4 bytes/DMA request) */
-	/* 16 bit mono */
-	write_ess(dev, 0xb6, 0x00);
-	write_ess(dev, 0xb7, 0x71);
-	write_ess(dev, 0xb7, 0xf4);
-
-	read_ess(dev, 0xb1, &tmp);
-	write_ess(dev, 0xb1, (tmp & 0x0f) | 0x50);
-	read_ess(dev, 0xb2, &tmp);
-	write_ess(dev, 0xb2, (tmp & 0x0f) | 0x50);
-
-	write_ess(dev, 0xa4, (unsigned char) ((-HFMODEM_FRAGSIZE) & 0xff));
-	write_ess(dev, 0xa5, (unsigned char) (((-HFMODEM_FRAGSIZE) >> 8) & 0xff));
-
-        write_dsp(dev, SBC_SPEAKER_ON); 
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-void ess_trigger_output(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-	unsigned char tmp;
-
-        save_flags(flags);
-        cli();
-	read_ess(dev, 0xb8, &tmp);
-	write_ess(dev, 0xb8, tmp | 0x05);         /* Go */
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-unsigned int ess_intack(struct hfmodem_state *dev)
-{
-	unsigned int dmaptr;
-	unsigned long flags;
-	unsigned char st;
-#if 0
-	static unsigned int cnt = 0;
-#endif
-
-	save_flags(flags);
-        cli();
-	st = inb(DSP_WRITE_STATUS(dev->io.base_addr));
-	sbc_int_ack_8bit(dev);
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        dmaptr = get_dma_residue(dev->io.dma);
-        enable_dma(dev->io.dma);
-	restore_flags(flags);
-#if 0
-	cnt = (cnt + 1) & 0x3f;
-	if (!cnt)
-		printk(KERN_DEBUG "%s: ess: FIFO: full:%c empty:%c half empty:%c  IRQ: cpu:%c half empty:%c DMA:%c\n",
-		       hfmodem_drvname, '1'-!(st&0x20), '1'-!(st&0x10), '1'-!(st&0x8), 
-		       '1'-!(st&0x4), '1'-!(st&0x2), '1'-!(st&0x1));
-#endif
-	if (st & 0x20) /* FIFO full, 256 bytes */
-		dmaptr += 256;
-	else if (!(st & 0x10)) /* FIFO not empty, assume half full 128 bytes */
-		dmaptr += 128;
-	if (dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
-		dmaptr -= HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
-	if (dmaptr == 0 || dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
-		dmaptr = HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
-	return (HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE - dmaptr) / 2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void ess_mixer(struct hfmodem_state *dev, int src, int igain, int ogain)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	if (src >= 0 && src <= 2) 
-		set_mixer(dev, 0x0c, ((src+3) & 3) << 1);
-	if (ogain >= 0 && ogain <= 255)
-		set_mixer(dev, 0x22, (ogain & 0xf0) | ((ogain >> 4) & 0xf));
-	if (igain >= 0 && igain <= 255) {
-		set_mixer(dev, 0x36, igain);
-		set_mixer(dev, 0x37, igain);
-		set_mixer(dev, 0x38, igain);
-		set_mixer(dev, 0x39, igain);
-		set_mixer(dev, 0x3a, igain);
-	}
-	set_mixer(dev, 0x4, 0xff);
-	set_mixer(dev, 0xe, 0x0);
-	set_mixer(dev, 0x26, 0);
-	set_mixer(dev, 0x28, 0);
-	set_mixer(dev, 0x2e, 0);
-	restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct hfmodem_scops sbc4_scops = {
-	SBC_EXTENT, sbc4_init, sbc4_prepare_input, sbc4_trigger_input, 
-	sbc4_prepare_output, sbc4_trigger_output, sbc4_stop, sbc4_intack, sbc4_mixer
-};
-
-static const struct hfmodem_scops ess_scops = {
-	SBC_EXTENT, sbc4_init, ess_prepare_input, ess_trigger_input, 
-	ess_prepare_output, ess_trigger_output, sbc4_stop, ess_intack, ess_mixer
-};
-
-/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/hfmodem/wss.c linux/drivers/char/hfmodem/wss.c
--- v2.3.12/linux/drivers/char/hfmodem/wss.c	Tue Aug  5 09:48:55 1997
+++ linux/drivers/char/hfmodem/wss.c	Wed Dec 31 16:00:00 1969
@@ -1,437 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      wss.c  --  Linux soundcard HF FSK driver, 
- *                 WindowsSoundSystem specific functions.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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.
- *
- *
- */
-
-/*****************************************************************************/
-     
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
- 
-#include <linux/hfmodem.h>
-
-/* --------------------------------------------------------------------- */
-
-#define WSS_CONFIG(iobase)       (iobase+0)
-#define WSS_STATUS(iobase)       (iobase+3)
-#define WSS_CODEC_IA(iobase)     (iobase+4)
-#define WSS_CODEC_ID(iobase)     (iobase+5)
-#define WSS_CODEC_STATUS(iobase) (iobase+6)
-#define WSS_CODEC_DATA(iobase)   (iobase+7)
-
-#define WSS_EXTENT   8
-
-/* --------------------------------------------------------------------- */
-
-extern const struct hfmodem_scops wss_scops;
-
-/* --------------------------------------------------------------------- */
-
-static void write_codec(struct hfmodem_state *dev, unsigned char idx,
-                        unsigned char data)
-{
-        int timeout = 900000;
-
-        /* wait until codec ready */
-        while (timeout > 0 && inb(WSS_CODEC_IA(dev->io.base_addr)) & 0x80)
-                timeout--;
-        outb(idx, WSS_CODEC_IA(dev->io.base_addr));
-        outb(data, WSS_CODEC_ID(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned char read_codec(struct hfmodem_state *dev, unsigned char idx)
-{
-        int timeout = 900000;
-
-        /* wait until codec ready */
-        while (timeout > 0 && inb(WSS_CODEC_IA(dev->io.base_addr)) & 0x80)
-                timeout--;
-        outb(idx & 0x1f, WSS_CODEC_IA(dev->io.base_addr));
-        return inb(WSS_CODEC_ID(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-extern __inline__ void wss_ack_int(struct hfmodem_state *dev)
-{
-        outb(0, WSS_CODEC_STATUS(dev->io.base_addr));
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wss_srate_tab[16] = {
-        8000, 5510, 16000, 11025, 27420, 18900, 32000, 22050,
-        -1, 37800, -1, 44100, 48000, 33075, 9600, 6620
-};
-
-static int wss_srate_index(int srate)
-{
-        int i;
-
-        for (i = 0; i < (sizeof(wss_srate_tab)/sizeof(wss_srate_tab[0])); i++)
-                if (srate == wss_srate_tab[i] && wss_srate_tab[i] > 0)
-                        return i;
-        return -1;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wss_set_codec_fmt(struct hfmodem_state *dev, unsigned char fmt)
-{
-        unsigned long time;
-        unsigned long flags;
-
-        save_flags(flags);
-        cli();
-        /* Clock and data format register */
-        write_codec(dev, 0x48, fmt);
-	/* MCE and interface config reg */
-	write_codec(dev, 0x49, 0xc);
-        outb(0xb, WSS_CODEC_IA(dev->io.base_addr)); /* leave MCE */
-        /*
-         * wait for ACI start
-         */
-        time = 1000;
-        while (!(read_codec(dev, 0x0b) & 0x20))
-                if (!(--time)) {
-                        printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n", 
-                               hfmodem_drvname);
-                        restore_flags(flags);
-                        return -1;
-                }
-        /*
-         * wait for ACI end
-         */
-        sti();
-        time = jiffies + HZ/4;
-        while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0));
-        restore_flags(flags);
-        if ((signed)(jiffies - time) >= 0) {
-                printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n", 
-                       hfmodem_drvname);
-                return -1;
-        }
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wss_init_codec(struct hfmodem_state *dev)
-{
-        unsigned char tmp, revwss, revid;
-        static const signed char irqtab[16] = { 
-		-1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, -1, -1 
-	};
-        static const signed char dmatab[4] = { 1, 2, -1, 3 };
-	int fmt;
-        
-	if ((fmt = wss_srate_index(HFMODEM_SRATE)) < 0) {
-		printk(KERN_ERR "%s: WSS: sampling rate not supported\n", hfmodem_drvname);
-		return -1;
-	}
-	fmt &= 0x0f;
-#ifdef __BIG_ENDIAN
-	fmt |= 0xc0;
-#else /* __BIG_ENDIAN */
-	fmt |= 0x40;
-#endif /* __BIG_ENDIAN */
-        tmp = inb(WSS_STATUS(dev->io.base_addr));
-        if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 && 
-            (tmp & 0x3f) != 0x0f) {
-                printk(KERN_WARNING "%s: WSS card id register not found, "
-                       "address 0x%x, ID register 0x%02x\n", hfmodem_drvname,
-                       dev->io.base_addr, (int)tmp);
-                /* return -1; */
-                revwss = 0;
-        } else {
-                if ((tmp & 0x80) && ((dev->io.dma == 0) || ((dev->io.irq >= 8) && (dev->io.irq != 9)))) {
-                        printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 "
-                               "(except IRQ9) cannot be used on an 8bit "
-                               "card\n", hfmodem_drvname);
-                        return -1;
-                }               
-                if (dev->io.irq > 15 || irqtab[dev->io.irq] == -1) {
-                        printk(KERN_ERR "%s: WSS: invalid interrupt %d\n", 
-                               hfmodem_drvname, (int)dev->io.irq);
-                        return -1;
-                }
-                if (dev->io.dma > 3 || dmatab[dev->io.dma] == -1) {
-                        printk(KERN_ERR "%s: WSS: invalid dma channel %d\n", 
-                               hfmodem_drvname, (int)dev->io.dma);
-                        return -1;
-                }
-                tmp = irqtab[dev->io.irq] | dmatab[dev->io.dma];
-                /* irq probe */
-                outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->io.base_addr));
-                if (!(inb(WSS_STATUS(dev->io.base_addr)) & 0x40)) {
-                        outb(0, WSS_CONFIG(dev->io.base_addr));
-                        printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n", 
-                               hfmodem_drvname, dev->io.irq);
-                }
-                outb(tmp, WSS_CONFIG(dev->io.base_addr));
-                revwss = inb(WSS_STATUS(dev->io.base_addr)) & 0x3f;
-        }
-        /*
-         * initialize the codec
-         */
-        write_codec(dev, 9, 0);
-	write_codec(dev, 12, 0);
-        write_codec(dev, 0, 0x45);
-        if (read_codec(dev, 0) != 0x45)
-                goto codec_err;
-        write_codec(dev, 0, 0xaa);
-        if (read_codec(dev, 0) != 0xaa)
-                goto codec_err;
-        if (wss_set_codec_fmt(dev, fmt))
-                goto codec_err;
-        write_codec(dev, 0, 0x40); /* left input control */
-        write_codec(dev, 1, 0x40); /* right input control */
-        write_codec(dev, 2, 0x80); /* left aux#1 input control */
-        write_codec(dev, 3, 0x80); /* right aux#1 input control */
-        write_codec(dev, 4, 0x80); /* left aux#2 input control */
-        write_codec(dev, 5, 0x80); /* right aux#2 input control */
-        write_codec(dev, 6, 0x80); /* left dac control */
-        write_codec(dev, 7, 0x80); /* right dac control */
-        write_codec(dev, 0xa, 0x2); /* pin control register */
-        write_codec(dev, 0xd, 0x0); /* digital mix control */
-        revid = read_codec(dev, 0xc) & 0xf;
-        /*
-         * print revisions
-         */        
-	printk(KERN_INFO "%s: WSS revision %d, CODEC revision %d\n", 
-	       hfmodem_drvname, (int)revwss, (int)revid);
-        return 0;
- codec_err:
-        outb(0, WSS_CONFIG(dev->io.base_addr));
-        printk(KERN_ERR "%s: no WSS soundcard found at address 0x%x\n", 
-               hfmodem_drvname, dev->io.base_addr);
-        return -1;
-}
-
-/* --------------------------------------------------------------------- */
-
-int hfmodem_wssprobe(struct hfmodem_state *dev)
-{
-	if (dev->io.base_addr <= 0 || dev->io.base_addr > 0x1000-WSS_EXTENT || 
-            dev->io.irq < 2 || dev->io.irq > 15 || dev->io.dma > 3 || dev->io.dma == 2)
-                return -ENXIO;
-        if (check_region(dev->io.base_addr, WSS_EXTENT))
-                return -EACCES;
-        /*
-         * check if a card is available
-         */
-        if (wss_init_codec(dev)) {
-                printk(KERN_ERR "%s: sbc: no card at io address 0x%x\n", 
-		       hfmodem_drvname, dev->io.base_addr);
-                return -ENODEV;
-        }
-	dev->scops = &wss_scops;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_init(struct hfmodem_state *dev)
-{
-	wss_init_codec(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_stop(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-        unsigned char oldcodecmode;
-        long abrt;
-
-        save_flags(flags);
-        cli();
-        /*
-         * perform the final DMA sequence to disable the codec request
-         */
-        oldcodecmode = read_codec(dev, 9);
-        write_codec(dev, 9, 0xc); /* disable codec */
-        wss_ack_int(dev);
-        if (read_codec(dev, 11) & 0x10) {
-                disable_dma(dev->io.dma);
-                clear_dma_ff(dev->io.dma);
-                set_dma_mode(dev->io.dma, (oldcodecmode & 1) ? 
-			     (DMA_MODE_WRITE | DMA_MODE_AUTOINIT) : (DMA_MODE_READ | DMA_MODE_AUTOINIT));
-                set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-                set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-                enable_dma(dev->io.dma);
-                abrt = 0;
-                while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000));
-        }
-        disable_dma(dev->io.dma);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_prepare_input(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-	wss_stop(dev);
-	save_flags(flags);
-        cli();
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        set_dma_mode(dev->io.dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-        set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-        enable_dma(dev->io.dma);
-        write_codec(dev, 15, (HFMODEM_FRAGSAMPLES-1) & 0xff);
-        write_codec(dev, 14, (HFMODEM_FRAGSAMPLES-1) >> 8);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_trigger_input(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-        cli();
-        write_codec(dev, 9, 0x0e);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_prepare_output(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-	wss_stop(dev);
-        save_flags(flags);
-        cli();
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        set_dma_mode(dev->io.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->io.dma, virt_to_bus(dev->dma.buf));
-        set_dma_count(dev->io.dma, HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE);
-        enable_dma(dev->io.dma);
-        write_codec(dev, 15, (HFMODEM_FRAGSAMPLES-1) & 0xff);
-        write_codec(dev, 14, (HFMODEM_FRAGSAMPLES-1) >> 8);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_trigger_output(struct hfmodem_state *dev)
-{
-	unsigned long flags;
-
-        save_flags(flags);
-        cli();
-        write_codec(dev, 9, 0x0d);
-        restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int wss_intack(struct hfmodem_state *dev)
-{
-	unsigned int dmaptr, nums;
-	unsigned long flags;
-
-	save_flags(flags);
-        cli();
-	wss_ack_int(dev);
-        disable_dma(dev->io.dma);
-        clear_dma_ff(dev->io.dma);
-        dmaptr = get_dma_residue(dev->io.dma);
-	if (dmaptr == 0 || dmaptr > HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE)
-		dmaptr = HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE;
-	nums = (((dmaptr - 1) % HFMODEM_FRAGSIZE) - 1) / 2;
-        write_codec(dev, 15, nums  & 0xff);
-        write_codec(dev, 14, nums >> 8);
-        enable_dma(dev->io.dma);
-	restore_flags(flags);
-	return (HFMODEM_NUMFRAGS * HFMODEM_FRAGSIZE - dmaptr) / 2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wss_mixer(struct hfmodem_state *dev, int src, int igain, int ogain)
-{
-	unsigned long flags;
-	static const unsigned char srctoreg[3] = { 1, 2, 0 };
-	static const unsigned char regtosrc[4] = { 2, 0, 1, 0 };
-	unsigned char tmp;
-
-	save_flags(flags);
-	cli();
-	tmp = read_codec(dev, 0x00);
-	if (src < 0 || src > 2)
-		src = regtosrc[(tmp >> 6) & 3];
-	if (igain < 0 || igain > 255) {
-		if (src == 1)
-			igain = ((tmp & 0xf) + ((tmp & 0x20) ? 13 : 0)) << 3;
-		else
-			igain = (tmp & 0xf) << 4;
-	}
-	if (src == 1) {
-		if (igain > (28<<3))
-			tmp = 0x2f;
-		else if (igain >= (13<<3))
-			tmp = 0x20 + (((igain >> 3) - 13) & 0xf);
-		else 
-			tmp = (igain >> 3) & 0xf;
-	} else 
-		tmp = (igain >> 4) & 0xf;
-	tmp |= srctoreg[src] << 6;
-	write_codec(dev, 0, tmp);
-	write_codec(dev, 1, tmp);
-	if (ogain > 0 && ogain <= 255) {
-		tmp = 63 - (ogain >> 2);
-		write_codec(dev, 6, tmp);
-		write_codec(dev, 7, tmp);
-	} else if (ogain == 0) {
-		write_codec(dev, 6, 0x80);
-		write_codec(dev, 7, 0x80);
-	}
-	restore_flags(flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct hfmodem_scops wss_scops = {
-	WSS_EXTENT, wss_init, wss_prepare_input, wss_trigger_input, 
-	wss_prepare_output, wss_trigger_output, wss_stop, wss_intack, wss_mixer
-};
-
-/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.3.12/linux/drivers/char/isicom.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/isicom.c	Mon Aug  9 10:23:09 1999
@@ -14,7 +14,8 @@
  *					Printk clean up
  *	9/12/98	alan@redhat.com		Rough port to 2.1.x
  *
- *
+ *	10/6/99 sameer			Merged the ISA and PCI drivers to
+ *					a new unified driver.
  *	***********************************************************
  *
  *	To use this driver you also need the support package. You 
@@ -51,8 +52,21 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
+#include <linux/pci.h>
+
 #include <linux/isicom.h>
 
+static int device_id[] = {      0x2028,
+				0x2051,
+				0x2052,
+				0x2053,
+				0x2054,
+				0x2055,
+				0x2056,
+				0x2057,
+				0x2058
+			};
+
 static int isicom_refcount = 0;
 static int prev_card = 3;	/*	start servicing isi_card[0]	*/
 static struct isi_board * irq_to_board[16] = { NULL, };
@@ -147,7 +161,7 @@
 static int ISILoad_ioctl(struct inode *inode, struct file *filp,
 		         unsigned int cmd, unsigned long arg)
 {
-	unsigned int card, i, j, signature, status;
+	unsigned int card, i, j, signature, status, portcount = 0;
 	unsigned short word_count, base;
 	bin_frame frame;
 	/* exec_record exec_rec; */
@@ -180,19 +194,38 @@
 				printk(".");
 			}	
 			signature=(inw(base+0x4)) & 0xff;	
-				
-			if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
+			if (isi_card[card].isa) {
+					
+				if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
 #ifdef ISICOM_DEBUG				
-				printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
+					printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
 #endif				
-				printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
-				return -EIO;					
-			}
-				
+					printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
+					return -EIO;					
+				}
+			}	
+			else {
+				portcount = inw(base+0x2);
+				if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) {	
+#ifdef ISICOM_DEBUG
+					printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
+#endif
+					printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
+					return -EIO;
+				}
+			}	
 			switch(signature) {
 			case	0xa5:
 			case	0xbb:
-			case	0xdd:	isi_card[card].port_count = 8;
+			case	0xdd:	
+					if (isi_card[card].isa) 
+						isi_card[card].port_count = 8;
+					else {
+						if (portcount == 4)
+							isi_card[card].port_count = 4;
+						else
+							isi_card[card].port_count = 8;
+					}	
 				     	isi_card[card].shift_count = 12;
 				     	break;
 				        
@@ -310,7 +343,8 @@
 			outw(0x0, base);
 			outw(0x0, base);
 			InterruptTheCard(base);
-			
+			outw(0x0, base+0x4);    /* for ISI4608 cards */
+							
 			isi_card[card].status |= FIRMWARE_LOADED;
 			return 0;	
 			
@@ -455,28 +489,7 @@
 				txcount--;
 			}
 		}
-/*
- *	Replaced the code below with hopefully a faster loop - sameer
- */
 
-/*					
-		while (1) {
-			wrd = port->xmit_buf[port->xmit_tail++];
-			port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
-			port->xmit_cnt--;
-			if (--txcount > 0) {
-				wrd |= (port->xmit_buf[port->xmit_tail++] << 8);
-				port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
-				port->xmit_cnt--;
-				outw(wrd, base);
-				if (--txcount <= 0) break;
-			}
-			else {
-				outw(wrd, base);
-				break;
-			}
-		}
-*/
 		InterruptTheCard(base);
 		if (port->xmit_cnt <= 0)
 			port->status &= ~ISI_TXOK;
@@ -531,12 +544,34 @@
 	unsigned char channel;
 	short byte_count;
 	
-	card = irq_to_board[irq];
+	/*
+	 *      find the source of interrupt
+	 */
+	 
+	for(count = 0; count < BOARD_COUNT; count++) { 
+		card = &isi_card[count];
+		if (card->base != 0) {
+			if (((card->isa == YES) && (card->irq == irq)) || 
+				((card->isa == NO) && (card->irq == irq) && (inw(card->base+0x0e) & 0x02)))
+				break;
+		}
+		card = NULL;
+	}
+
 	if (!card || !(card->status & FIRMWARE_LOADED)) {
-		printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);
+/*		printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);*/
 		return;
 	}
+	
 	base = card->base;
+	if (card->isa == NO) {
+	/*
+	 *      disable any interrupts from the PCI card and lower the
+	 *      interrupt line
+	 */
+		outw(0x8000, base+0x04);
+		ClearInterrupt(base);
+	}
 	
 	inw(base);		/* get the dummy word out */
 	header = inw(base);
@@ -548,12 +583,18 @@
 	if ((channel+1) > card->port_count) {
 		printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n",
 				base, channel+1);
-		ClearInterrupt(base);		
+		if (card->isa)
+			ClearInterrupt(base);
+		else
+			outw(0x0000, base+0x04); /* enable interrupts */		
 		return;			
 	}
 	port = card->ports + channel;
 	if (!(port->flags & ASYNC_INITIALIZED)) {
-		ClearInterrupt(base);
+		if (card->isa)
+			ClearInterrupt(base);
+		else
+			outw(0x0000, base+0x04); /* enable interrupts */
 		return;
 	}	
 		
@@ -681,7 +722,10 @@
 		}
 		queue_task(&tty->flip.tqueue, &tq_timer);
 	}
-	ClearInterrupt(base);
+	if (card->isa == YES)
+		ClearInterrupt(base);
+	else
+		outw(0x0000, base+0x04); /* enable interrupts */	
 	return;
 } 
 
@@ -1023,12 +1067,11 @@
 		return -ENODEV;
 	}
 	
-	/*  open on higher 8 dev files on a 8 port card !!! */
-	if (card->port_count == 8) 
-		if (line > ((board * 16)+7)) {
-			printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n");
-			return -ENODEV;
-		}	
+	/*  open on a port greater than the port count for the card !!! */
+	if (line > ((board * 16) + card->port_count - 1)) {
+		printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n");
+		return -ENODEV;
+	}	
 	port = &isi_ports[line];	
 	if (isicom_paranoia_check(port, tty->device, "isicom_open"))
 		return -ENODEV;
@@ -1764,21 +1807,42 @@
 
 static int register_isr(void)
 {
-	int count, done=0;
+	int count, done=0, card;
+	unsigned char request;
 	for (count=0; count < BOARD_COUNT; count++ ) {
 		if (isi_card[count].base) {
-			if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) {
-				printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",
-					isi_card[count].irq, count+1);
+		/*
+		 * verify if the required irq has already been requested for
+		 * another ISI Card, if so we already have it, else request it
+		 */
+			request = YES;
+			for(card = 0; card < count; card++)
+			if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) {
+				request = NO;
+				if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO))
+					break;
+				/*
+				 * ISA cards cannot share interrupts with other
+				 * PCI or ISA devices hence disable this card.
+				 */
 				release_region(isi_card[count].base,16);
-				isi_card[count].base=0;
+				isi_card[count].base = 0;
+				break;
 			}
-			else {
-				printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", 
-				count+1, isi_card[count].base, isi_card[count].irq); 
-				
-				irq_to_board[isi_card[count].irq]=&isi_card[count];
-				done++;
+			if (request == YES) { 
+				if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) {
+					printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",
+						isi_card[count].irq, count+1);
+					release_region(isi_card[count].base,16);
+					isi_card[count].base=0;
+				}
+				else {
+					printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", 
+					count+1, isi_card[count].base, isi_card[count].irq); 
+					
+					irq_to_board[isi_card[count].irq]=&isi_card[count];
+					done++;
+				}
 			}
 		}	
 	}
@@ -1787,14 +1851,24 @@
 
 static void unregister_isr(void)
 {
-	int count;
-	for (count=0; count < BOARD_COUNT; count++ ) 
+	int count, card;
+	unsigned char freeirq;
+	for (count=0; count < BOARD_COUNT; count++ ) {
 		if (isi_card[count].base) {
-			free_irq(isi_card[count].irq, NULL);
+			freeirq = YES;
+			for(card = 0; card < count; card++)
+				if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) {
+					freeirq = NO;
+					break;
+				}
+			if (freeirq == YES) {
+				free_irq(isi_card[count].irq, NULL);
 #ifdef ISICOM_DEBUG			
-			printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);
-#endif			
+				printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);
+#endif	
+			}		
 		}
+	}
 }
 
 static int isicom_init(void)
@@ -1883,28 +1957,74 @@
 
 int init_module(void)
 {
-	int retval, card;
-
-	for(card=0; card < BOARD_COUNT; card++)
-	{	
-		isi_card[card].base=io[card];
-		isi_card[card].irq=irq[card];
-	}
-	
-	for (card=0 ;card < BOARD_COUNT; card++) {
-		if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)||
-		    (isi_card[card].irq==4)||(isi_card[card].irq==5)||
-		    (isi_card[card].irq==7)||(isi_card[card].irq==10)||
-		    (isi_card[card].irq==11)||(isi_card[card].irq==12)||
-		    (isi_card[card].irq==15))) {
+	struct pci_dev *dev = NULL;
+	int retval, card, idx, count;
+	unsigned char pciirq;
+	unsigned int ioaddr;
+	                
+	card = 0;
+	for(idx=0; idx < BOARD_COUNT; idx++) {	
+		if (io[idx]) {
+			isi_card[idx].base=io[idx];
+			isi_card[idx].irq=irq[idx];
+			isi_card[idx].isa=YES;
+			card++;
+		}
+		else {
+			isi_card[idx].base = 0;
+			isi_card[idx].irq = 0;
+		}
+	}
+	
+	for (idx=0 ;idx < card; idx++) {
+		if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)||
+		    (isi_card[idx].irq==4)||(isi_card[idx].irq==5)||
+		    (isi_card[idx].irq==7)||(isi_card[idx].irq==10)||
+		    (isi_card[idx].irq==11)||(isi_card[idx].irq==12)||
+		    (isi_card[idx].irq==15))) {
 			
-			if (isi_card[card].base) {
+			if (isi_card[idx].base) {
 				printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",
-					isi_card[card].irq, card+1);
-				isi_card[card].base=0;
+					isi_card[idx].irq, idx+1);
+				isi_card[idx].base=0;
+				card--;
 			}	
 		}
 	}	
+	
+	if (pci_present() && (card < BOARD_COUNT)) {
+		for (idx=0; idx < DEVID_COUNT; idx++) {
+			dev = NULL;
+			for (;;){
+				if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev)))
+					break;
+				if (card >= BOARD_COUNT)
+					break;
+					
+				/* found a PCI ISI card! */
+				ioaddr = dev->resource[3].start; /* i.e at offset 0x1c in the
+								* PCI configuration register
+								* space.
+								*/
+				ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+				pciirq = dev->irq;
+				printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]);
+				/*
+				 * allot the first empty slot in the array
+				 */				
+				for (count=0; count < BOARD_COUNT; count++) {				
+					if (isi_card[count].base == 0) {
+						isi_card[count].base = ioaddr;
+						isi_card[count].irq = pciirq;
+						isi_card[count].isa = NO;
+						card++;
+						break;
+					}
+				}
+			}				
+			if (card >= BOARD_COUNT) break;
+		}
+	}
 	
 	if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {
 		printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); 
diff -u --recursive --new-file v2.3.12/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.3.12/linux/drivers/char/istallion.c	Fri Apr 16 08:20:23 1999
+++ linux/drivers/char/istallion.c	Mon Aug  9 10:23:09 1999
@@ -4387,7 +4387,7 @@
  *	Probe and initialize the specified board.
  */
 
-__initfunc(static int stli_brdinit(stlibrd_t *brdp))
+static int __init stli_brdinit(stlibrd_t *brdp)
 {
 #if DEBUG
 	printk("stli_brdinit(brdp=%x)\n", (int) brdp);
@@ -5305,7 +5305,7 @@
 
 /*****************************************************************************/
 
-__initfunc(int stli_init(void))
+int __init stli_init(void)
 {
 	printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
diff -u --recursive --new-file v2.3.12/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.3.12/linux/drivers/char/keyboard.c	Sat May 22 12:57:24 1999
+++ linux/drivers/char/keyboard.c	Thu Aug  5 14:43:32 1999
@@ -155,6 +155,7 @@
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static int sysrq_pressed;
+int sysrq_enabled = 1;
 #endif
 
 /*
@@ -247,7 +248,7 @@
 		sysrq_pressed = !up_flag;
 		return;
 	} else if (sysrq_pressed) {
-		if (!up_flag) {
+		if (!up_flag && sysrq_enabled) {
 			handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
 			return;
 		}
diff -u --recursive --new-file v2.3.12/linux/drivers/char/logibusmouse.c linux/drivers/char/logibusmouse.c
--- v2.3.12/linux/drivers/char/logibusmouse.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/logibusmouse.c	Mon Aug  2 09:54:29 1999
@@ -0,0 +1,157 @@
+/*
+ * Logitech Bus Mouse Driver for Linux
+ * by James Banks
+ *
+ * Mods by Matthew Dillon
+ *   calls verify_area()
+ *   tracks better when X is busy or paging
+ *
+ * Heavily modified by David Giller
+ *   changed from queue- to counter- driven
+ *   hacked out a (probably incorrect) mouse_select
+ *
+ * Modified again by Nathan Laredo to interface with
+ *   0.96c-pl1 IRQ handling changes (13JUL92)
+ *   didn't bother touching select code.
+ *
+ * Modified the select() code blindly to conform to the VFS
+ *   requirements. 92.07.14 - Linus. Somebody should test it out.
+ *
+ * Modified by Johan Myreen to make room for other mice (9AUG92)
+ *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
+ *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
+ *   renamed this file mouse.c => busmouse.c
+ *
+ * Minor addition by Cliff Matthews
+ *   added fasync support
+ *
+ * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk> 
+ *
+ * Replaced dumb busy loop with udelay()  16 Nov 95
+ *   Nathan Laredo <laredo@gnu.ai.mit.edu>
+ *
+ * Track I/O ports with request_region().  12 Dec 95 Philip Blundell
+ *
+ * Converted to use new generic busmouse code.  5 Apr 1998
+ *   Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/logibusmouse.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "busmouse.h"
+
+static int msedev;
+static int mouse_irq = MOUSE_IRQ;
+
+#ifdef MODULE
+MODULE_PARM(mouse_irq, "i");
+#endif
+
+void __init bmouse_setup(char *str, int *ints)
+{
+	if (ints[0] > 0)
+		mouse_irq=ints[1];
+}
+
+static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	char dx, dy;
+	unsigned char buttons;
+
+	outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
+	dx = (inb(MSE_DATA_PORT) & 0xf);
+	outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
+	dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
+	outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
+	dy = (inb(MSE_DATA_PORT) & 0xf);
+	outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
+	buttons = inb(MSE_DATA_PORT);
+	dy |= (buttons & 0xf) << 4;
+	buttons = ((buttons >> 5) & 0x07);
+	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
+	MSE_INT_ON();
+}
+
+/*
+ * close access to the mouse
+ */
+static int close_mouse(struct inode * inode, struct file * file)
+{
+	MSE_INT_OFF();
+	free_irq(mouse_irq, NULL);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * open access to the mouse
+ */
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+	if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL))
+		return -EBUSY;
+	MOD_INC_USE_COUNT;
+	MSE_INT_ON();
+	return 0;
+}
+
+static struct busmouse busmouse = {
+	LOGITECH_BUSMOUSE, "busmouse", open_mouse, close_mouse, 7
+};
+
+int __init bus_mouse_init(void)
+{
+	if (check_region(LOGIBM_BASE, LOGIBM_EXTENT))
+		return -EIO;
+
+	outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
+	outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
+	udelay(100L);	/* wait for reply from mouse */
+	if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE)
+		return -EIO;
+
+	outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
+	MSE_INT_OFF();
+	
+	request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse");
+
+	msedev = register_busmouse(&busmouse);
+	if (msedev < 0)
+		printk(KERN_WARNING "Unable to register busmouse driver.\n");
+	else
+		printk(KERN_INFO "Logitech busmouse installed.\n");
+	return msedev < 0 ? msedev : 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	return bus_mouse_init();
+}
+
+void cleanup_module(void)
+{
+	unregister_busmouse(msedev);
+	release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+}
+#endif
diff -u --recursive --new-file v2.3.12/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.3.12/linux/drivers/char/lp.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/char/lp.c	Mon Aug  9 10:23:09 1999
@@ -711,7 +711,7 @@
 
 static int parport_ptr = 0;
 
-__initfunc(void lp_setup(char *str, int *ints))
+void __init lp_setup(char *str, int *ints)
 {
 	if (!str) {
 		if (ints[0] == 0 || ints[1] == 0) {
@@ -755,6 +755,17 @@
 	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
 	       (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
 
+#ifdef CONFIG_LP_CONSOLE
+	if (!nr) {
+		if (port->modes & PARPORT_MODE_SAFEININT) {
+			register_console (&lpcons);
+			printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
+		} else
+			printk (KERN_ERR "lp%d: cannot run console on %s\n",
+				CONSOLE_LP, port->name);
+	}
+#endif
+
 	return 0;
 }
 
@@ -842,12 +853,6 @@
 			printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n");
 #endif
 	}
-#ifdef CONFIG_LP_CONSOLE
-	else {
-		register_console (&lpcons);
-		printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
-	}
-#endif
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v2.3.12/linux/drivers/char/lp_intern.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/lp_intern.c	Mon Aug  9 10:23:09 1999
@@ -219,7 +219,7 @@
 	NULL,
 };
 
-__initfunc(int lp_internal_init(void))
+int __init lp_internal_init(void)
 {
 #ifdef CONFIG_AMIGA
   if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL))
diff -u --recursive --new-file v2.3.12/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v2.3.12/linux/drivers/char/lp_m68k.c	Fri Jan 15 17:46:27 1999
+++ linux/drivers/char/lp_m68k.c	Mon Aug  9 10:23:09 1999
@@ -474,7 +474,7 @@
 EXPORT_SYMBOL(register_parallel);
 EXPORT_SYMBOL(unregister_parallel);
 
-__initfunc(int lp_m68k_init(void))
+int __init lp_m68k_init(void)
 {
 	extern char m68k_debug_device[];
 
@@ -507,7 +507,7 @@
 /*
  * Currently we do not accept any lp-parameters, but that may change.
  */
-__initfunc(void lp_setup(char *str, int *ints))
+void __init lp_setup(char *str, int *ints)
 {	
 }
 
diff -u --recursive --new-file v2.3.12/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.12/linux/drivers/char/mem.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/char/mem.c	Mon Aug  9 12:28:41 1999
@@ -17,6 +17,7 @@
 #include <linux/joystick.h>
 #include <linux/i2c.h>
 #include <linux/raw.h>
+#include <linux/capability.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -459,11 +460,23 @@
 	}
 }
 
+static int open_port(struct inode * inode, struct file * filp)
+{
+	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static int open_mem(struct inode * inode, struct file * filp)
+{
+	return (capable(CAP_SYS_RAWIO)
+		|| !(filp->f_mode & FMODE_WRITE)) ? 0 : -EPERM;
+}
+
 #define mmap_kmem	mmap_mem
 #define zero_lseek	null_lseek
 #define full_lseek      null_lseek
 #define write_zero	write_null
 #define read_full       read_zero
+#define open_kmem	open_mem
 
 static struct file_operations mem_fops = {
 	memory_lseek,
@@ -473,7 +486,7 @@
 	NULL,		/* mem_poll */
 	NULL,		/* mem_ioctl */
 	mmap_mem,
-	NULL,		/* no special open code */
+	open_mem,
 	NULL,		/* flush */
 	NULL,		/* no special release code */
 	NULL		/* fsync */
@@ -487,7 +500,7 @@
 	NULL,		/* kmem_poll */
 	NULL,		/* kmem_ioctl */
 	mmap_kmem,
-	NULL,		/* no special open code */
+	open_kmem,
 	NULL,		/* flush */
 	NULL,		/* no special release code */
 	NULL		/* fsync */
@@ -515,7 +528,7 @@
 	NULL,		/* port_poll */
 	NULL,		/* port_ioctl */
 	NULL,		/* port_mmap */
-	NULL,		/* no special open code */
+	open_port,
 	NULL,		/* flush */
 	NULL,		/* no special release code */
 	NULL		/* fsync */
@@ -598,7 +611,7 @@
 	NULL		/* fsync */
 };
 
-__initfunc(int chr_dev_init(void))
+int __init chr_dev_init(void)
 {
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
diff -u --recursive --new-file v2.3.12/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.3.12/linux/drivers/char/misc.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/misc.c	Mon Aug  9 12:14:28 1999
@@ -28,7 +28,7 @@
  *  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  * Changes for kmod (from kerneld):
- 	Cyrus Durgin <cider@speakeasy.org>
+ *	Cyrus Durgin <cider@speakeasy.org>
  */
 
 #include <linux/module.h>
@@ -43,14 +43,13 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-#endif
 
 #include <linux/tty.h>
 #include <linux/selection.h>
 #include <linux/kmod.h>
 
+#include "busmouse.h"
+
 /*
  * Head entry for the doubly linked miscdevice list
  */
@@ -62,14 +61,7 @@
 #define DYNAMIC_MINORS 64 /* like dynamic majors */
 static unsigned char misc_minors[DYNAMIC_MINORS / 8];
 
-extern int bus_mouse_init(void);
-extern int qpmouse_init(void);
-extern int ms_bus_mouse_init(void);
-extern int atixl_busmouse_init(void);
-extern int amiga_mouse_init(void);
-extern int atari_mouse_init(void);
-extern int sun_mouse_init(void);
-extern int adb_mouse_init(void);
+extern int psaux_init(void);
 #ifdef CONFIG_SGI_NEWPORT_GFX
 extern void gfx_register(void);
 #endif
@@ -86,9 +78,12 @@
 extern int dsp56k_init(void);
 extern int nvram_init(void);
 extern int radio_init(void);
-extern void hfmodem_init(void);
 extern int pc110pad_init(void);
 extern int pmu_device_init(void);
+extern int qpmouse_init(void);
+extern int ds1620_init(void);
+extern int nwbutton_init(void);
+extern int nwflash_init(void);
 
 static int misc_read_proc(char *buf, char **start, off_t offset,
 			  int len, int *eof, void *private)
@@ -185,37 +180,19 @@
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 
-static struct proc_dir_entry *proc_misc;	
+static struct proc_dir_entry *proc_misc;
 
 int __init misc_init(void)
 {
 	proc_misc = create_proc_entry("misc", 0, 0);
 	if (proc_misc)
 		proc_misc->read_proc = misc_read_proc;
-#ifdef CONFIG_BUSMOUSE
+#ifdef CONFIG_MOUSE
 	bus_mouse_init();
 #endif
 #if defined CONFIG_82C710_MOUSE
 	qpmouse_init();
 #endif
-#ifdef CONFIG_MS_BUSMOUSE
-	ms_bus_mouse_init();
-#endif
-#ifdef CONFIG_ATIXL_BUSMOUSE
- 	atixl_busmouse_init();
-#endif
-#ifdef CONFIG_AMIGAMOUSE
-	amiga_mouse_init();
-#endif
-#ifdef CONFIG_ATARIMOUSE
-	atari_mouse_init();
-#endif
-#ifdef CONFIG_SUN_MOUSE
-	sun_mouse_init();
-#endif
-#ifdef CONFIG_ADBMOUSE
-	adb_mouse_init();
-#endif
 #ifdef CONFIG_PC110_PAD
 	pc110pad_init();
 #endif
@@ -240,9 +217,6 @@
 #ifdef CONFIG_DTLK
 	dtlk_init();
 #endif
-#ifdef CONFIG_APM
-	apm_bios_init();
-#endif
 #ifdef CONFIG_H8
 	h8_init();
 #endif
@@ -261,18 +235,12 @@
 #ifdef CONFIG_ATARI_DSP56K
 	dsp56k_init();
 #endif
-#ifdef CONFIG_HFMODEM
-	hfmodem_init();
-#endif
 #ifdef CONFIG_NVRAM
 	nvram_init();
 #endif
 #ifdef CONFIG_MISC_RADIO
 	radio_init();
 #endif
-#ifdef CONFIG_HFMODEM
-	hfmodem_init();
-#endif
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_device_init();
 #endif
@@ -281,6 +249,15 @@
 #endif
 #ifdef CONFIG_SGI
 	streamable_init ();
+#endif
+#ifdef CONFIG_DS1620
+	ds1620_init();
+#endif
+#ifdef CONFIG_NWBUTTON
+	nwbutton_init();
+#endif
+#ifdef CONFIG_NWFLASH
+	nwflash_init();
 #endif
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
diff -u --recursive --new-file v2.3.12/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v2.3.12/linux/drivers/char/msbusmouse.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/msbusmouse.c	Tue Aug  3 10:04:42 1999
@@ -27,6 +27,9 @@
  *
  * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  *
+ * Converted to use new generic busmouse code.  5 Apr 1998
+ *   Russell King <rmk@arm.uk.linux.org>
+ *
  * version 0.3b
  */
 
@@ -35,7 +38,7 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
-#include <linux/busmouse.h>
+#include <linux/logibusmouse.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
@@ -48,7 +51,9 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 
-static struct mouse_status mouse;
+#include "busmouse.h"
+
+static int msedev;
 static int mouse_irq = MOUSE_IRQ;
 
 #ifdef MODULE
@@ -81,35 +86,17 @@
 	outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT);
 	outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT);
 
-	if (dx != 0 || dy != 0 || buttons != mouse.buttons || ((~buttons) & 0x07)) {
-		add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
-		mouse.buttons = buttons;
-		mouse.dx += dx;
-		mouse.dy += dy;
-		mouse.ready = 1;
-		wake_up_interruptible(&mouse.wait);
-		if (mouse.fasyncptr)
-			kill_fasync(mouse.fasyncptr, SIGIO);
-	}
-}
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
-	if (retval < 0)
-		return retval;
-	return 0;
+	/* why did the original have:
+	 * if (dx != 0 || dy != 0 || buttons != mouse.buttons ||
+	 *    ((~buttons) & 0x07))
+	 *    ^^^^^^^^^^^^^^^^^^^ this?
+	 */
+	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
 }
 
 static int release_mouse(struct inode * inode, struct file * file)
 {
-	fasync_mouse(-1, file, 0);
-	if (--mouse.active)
-		return 0;
 	MS_MSE_INT_OFF();
-	mouse.ready = 0; 
 	free_irq(mouse_irq, NULL);
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -117,86 +104,24 @@
 
 static int open_mouse(struct inode * inode, struct file * file)
 {
-	if (!mouse.present)
-		return -EINVAL;
-	if (mouse.active++)
-		return 0;
-	if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL)) {
-		mouse.active--;
+	if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL))
 		return -EBUSY;
-	}
-	mouse.ready = mouse.dx = mouse.dy = 0;	
-	mouse.buttons = 0x80;
+
 	outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
 	MOD_INC_USE_COUNT;
 	MS_MSE_INT_ON();	
 	return 0;
 }
 
-static ssize_t write_mouse(struct file * file,
-       const char * buffer, size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-static ssize_t read_mouse(struct file * file,
-       char * buffer, size_t count, loff_t *ppos)
-{
-	int i, dx, dy;
-
-	if (count < 3)
-		return -EINVAL;
-	if (!mouse.ready)
-		return -EAGAIN;
-	put_user(mouse.buttons | 0x80, buffer);
-	dx = mouse.dx < -127 ? -127 : mouse.dx > 127 ?  127 :  mouse.dx;
-	dy = mouse.dy < -127 ?  127 : mouse.dy > 127 ? -127 : -mouse.dy;
-	put_user((char)dx, buffer + 1);
-	put_user((char)dy, buffer + 2);
-	for (i = 3; i < count; i++)
-		put_user(0x00, buffer + i);
-	mouse.dx -= dx;
-	mouse.dy += dy;
-	mouse.ready = 0;
-	return i;	
-}
-
-static unsigned int mouse_poll(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &mouse.wait, wait);
-	if (mouse.ready) 
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations ms_bus_mouse_fops = {
-	NULL,		/* mouse_seek */
-	read_mouse,
-	write_mouse,
-	NULL, 		/* mouse_readdir */
-	mouse_poll, 	/* mouse_poll */
-	NULL, 		/* mouse_ioctl */
-	NULL,		/* mouse_mmap */
-	open_mouse,
-	NULL,		/* flush */
-	release_mouse,
-	NULL,
-	fasync_mouse,
-};
-
-static struct miscdevice ms_bus_mouse = {
-	MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops
+static struct busmouse msbusmouse = {
+	MICROSOFT_BUSMOUSE, "msbusmouse", open_mouse, release_mouse, 0
 };
 
 __initfunc(int ms_bus_mouse_init(void))
 {
+	int present = 0;
 	int mse_byte, i;
 
-	mouse.present = mouse.active = mouse.ready = 0;
-	mouse.buttons = 0x80;
-	mouse.dx = mouse.dy = 0;
-	init_waitqueue_head(&mouse.wait);
-
 	if (check_region(MS_MSE_CONTROL_PORT, 0x04))
 		return -ENODEV;
 
@@ -207,32 +132,30 @@
 		for (i = 0; i < 4; i++) {
 			if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) {
 				if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte)
-					mouse.present = 1;
+					present = 1;
 				else
-					mouse.present = 0;
+					present = 0;
 			} else
-				mouse.present = 0;
+				present = 0;
 		}
 	}
-	if (mouse.present == 0)
+	if (present == 0)
 		return -EIO;
 	MS_MSE_INT_OFF();
 	request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
-	printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
-	misc_register(&ms_bus_mouse);
-	return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-	return ms_bus_mouse_init();
+	msedev = register_busmouse(&msbusmouse);
+	if (msedev < 0)
+		printk(KERN_WARNING "Unable to register msbusmouse driver.\n");
+	else
+		printk(KERN_INFO "Microsoft BusMouse detected and installed.\n");
+	return msedev < 0 ? msedev : 0;
 }
 
-void cleanup_module(void)
+void ms_bus_mouse_exit(void)
 {
-	misc_deregister(&ms_bus_mouse);
+	unregister_busmouse(msedev);
 	release_region(MS_MSE_CONTROL_PORT, 0x04);
 }
-#endif
 
+module_init(ms_bus_mouse_init)
+module_exit(ms_bus_mouse_exit)
diff -u --recursive --new-file v2.3.12/linux/drivers/char/nvram.c linux/drivers/char/nvram.c
--- v2.3.12/linux/drivers/char/nvram.c	Mon Aug 24 13:14:09 1998
+++ linux/drivers/char/nvram.c	Thu Aug  5 14:34:01 1999
@@ -413,7 +413,7 @@
 };
 
 
-__initfunc(int nvram_init(void))
+int __init nvram_init(void)
 {
 	/* First test whether the driver should init at all */
 	if (!CHECK_DRIVER_INIT())
@@ -479,7 +479,7 @@
 #ifdef CONFIG_PROC_FS
 
 static char *floppy_types[] = {
-	"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M"
+	"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", "3.5'' 2.88M"
 };
 
 static char *gfx_types[] = {
@@ -521,14 +521,14 @@
 	PRINT_PROC( "HD 0 type      : " );
 	type = nvram[4] >> 4;
 	if (type)
-		PRINT_PROC( " %02x\n", type == 0x0f ? nvram[11] : type );
+		PRINT_PROC( "%02x\n", type == 0x0f ? nvram[11] : type );
 	else
 		PRINT_PROC( "none\n" );
 
 	PRINT_PROC( "HD 1 type      : " );
 	type = nvram[4] & 0x0f;
 	if (type)
-		PRINT_PROC( " %02x\n", type == 0x0f ? nvram[12] : type );
+		PRINT_PROC( "%02x\n", type == 0x0f ? nvram[12] : type );
 	else
 		PRINT_PROC( "none\n" );
 
diff -u --recursive --new-file v2.3.12/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.3.12/linux/drivers/char/pc_keyb.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/char/pc_keyb.c	Mon Aug  2 16:40:36 1999
@@ -518,10 +518,13 @@
 #endif
 
 /* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+static int __init kbd_reset_setup(char *str)
 {
 	kbd_startup_reset = 1;
+	return 1;
 }
+
+__setup("kbd-reset", kbd_reset_setup);
 
 #define KBD_NO_DATA	(-1)	/* No data */
 #define KBD_BAD_DATA	(-2)	/* Parity or other error */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.3.12/linux/drivers/char/pcxx.c	Sat May 15 15:05:36 1999
+++ linux/drivers/char/pcxx.c	Thu Aug  5 14:34:01 1999
@@ -894,7 +894,7 @@
  * Driver setup function when linked into the kernel to optionally parse multible
  * "digi="-lines and initialize the driver at boot time. No probing.
  */
-__initfunc(void pcxx_setup(char *str, int *ints))
+void __init pcxx_setup(char *str, int *ints)
 {
 
 	struct board_info board;
@@ -1085,7 +1085,7 @@
  * function to initialize the driver with the given parameters, which are either
  * the default values from this file or the parameters given at boot.
  */
-__initfunc(int pcxe_init(void))
+int __init pcxe_init(void)
 {
 	ulong memory_seg=0, memory_size=0;
 	int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
diff -u --recursive --new-file v2.3.12/linux/drivers/char/planb.c linux/drivers/char/planb.c
--- v2.3.12/linux/drivers/char/planb.c	Sat May 15 15:05:36 1999
+++ linux/drivers/char/planb.c	Thu Aug  5 14:34:01 1999
@@ -2359,7 +2359,7 @@
 int init_module(void)
 {
 #else
-__initfunc(int init_planbs(struct video_init *unused))
+int __init init_planbs(struct video_init *unused)
 {
 #endif
 	int i;
diff -u --recursive --new-file v2.3.12/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.12/linux/drivers/char/ppdev.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/char/ppdev.c	Fri Jul 30 12:28:26 1999
@@ -21,6 +21,8 @@
  *   CLAIM	(register device first time) parport_claim_or_block
  *   RELEASE	parport_release
  *   SETMODE	set the IEEE 1284 protocol to use for read/write
+ *   SETPHASE	set the IEEE 1284 phase of a particular mode.  Not to be
+ *              confused with ioctl(fd, SETPHASER, &stun). ;-)
  *   DATADIR	data_forward / data_reverse
  *   WDATA	write_data
  *   RDATA	read_data
@@ -56,7 +58,6 @@
 	struct pardevice * pdev;
 	wait_queue_head_t irq_wait;
 	atomic_t irqc;
-	int mode;
 	unsigned int flags;
 	int irqresponse;
 	unsigned char irqctl;
@@ -84,105 +85,6 @@
 	return -ESPIPE;
 }
 
-/* This looks a bit like parport_read.  The difference is that we don't
- * determine the mode to use from the port data, but rather from the
- * mode the driver told us to use. */
-static ssize_t do_read (struct pp_struct *pp, void *buf, size_t len)
-{
-	size_t (*fn) (struct parport *, void *, size_t, int);
-	struct parport *port = pp->pdev->port;
-	int addr = pp->mode & IEEE1284_ADDR;
-	int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
-
-	switch (mode) {
-	case IEEE1284_MODE_COMPAT:
-		/* This is a write-only mode. */
-		return -EIO;
-
-	case IEEE1284_MODE_NIBBLE:
-		fn = port->ops->nibble_read_data;
-		break;
-
-	case IEEE1284_MODE_BYTE:
-		fn = port->ops->byte_read_data;
-		break;
-
-	case IEEE1284_MODE_EPP:
-		if (addr)
-			fn = port->ops->epp_read_addr;
-		else
-			fn = port->ops->epp_read_data;
-		break;
-
-	case IEEE1284_MODE_ECP:
-	case IEEE1284_MODE_ECPRLE:
-		fn = port->ops->ecp_read_data;
-		break;
-
-	case IEEE1284_MODE_ECPSWE:
-		fn = parport_ieee1284_ecp_read_data;
-		break;
-
-	default:
-		printk (KERN_DEBUG "%s: unknown mode 0x%02x\n",
-			pp->pdev->name, pp->mode);
-		return -EINVAL;
-	}
-
-	return (*fn) (port, buf, len, 0);
-}
-
-/* This looks a bit like parport_write.  The difference is that we don't
- * determine the mode to use from the port data, but rather from the
- * mode the driver told us to use. */
-static ssize_t do_write (struct pp_struct *pp, const void *buf, size_t len)
-{
-	size_t (*fn) (struct parport *, const void *, size_t, int);
-	struct parport *port = pp->pdev->port;
-	int addr = pp->mode & IEEE1284_ADDR;
-	int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
-
-	switch (mode) {
-	case IEEE1284_MODE_NIBBLE:
-	case IEEE1284_MODE_BYTE:
-		/* Read-only modes. */
-		return -EIO;
-
-	case IEEE1284_MODE_COMPAT:
-		fn = port->ops->compat_write_data;
-		break;
-
-	case IEEE1284_MODE_EPP:
-		if (addr)
-			fn = port->ops->epp_write_addr;
-		else
-			fn = port->ops->epp_write_data;
-		break;
-
-	case IEEE1284_MODE_ECP:
-	case IEEE1284_MODE_ECPRLE:
-		if (addr)
-			fn = port->ops->ecp_write_addr;
-		else
-			fn = port->ops->ecp_write_data;
-		break;
-
-	case IEEE1284_MODE_ECPSWE:
-		if (addr)
-			fn = parport_ieee1284_ecp_write_addr;
-		else
-			fn = parport_ieee1284_ecp_write_data;
-		break;
-
-	default:
-		printk (KERN_DEBUG "%s: unknown mode 0x%02x\n",
-			pp->pdev->name, pp->mode);
-		return -EINVAL;
-	}
-
-	return (*fn) (port, buf, len, 0);
-}
-
 static ssize_t pp_read (struct file * file, char * buf, size_t count,
 			loff_t * ppos)
 {
@@ -206,7 +108,7 @@
 	while (bytes_read < count) {
 		ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
 
-		got = do_read (pp, kbuffer, need);
+		got = parport_read (pp->pdev->port, kbuffer, need);
 
 		if (got <= 0) {
 			if (!bytes_read)
@@ -265,7 +167,7 @@
 			break;
 		}
 
-		wrote = do_write (pp, kbuffer, n);
+		wrote = parport_write (pp->pdev->port, kbuffer, n);
 
 		if (wrote < 0) {
 			if (!bytes_written)
@@ -341,6 +243,17 @@
 	return 0;
 }
 
+static enum ieee1284_phase init_phase (int mode)
+{
+	switch (mode & ~(IEEE1284_DEVICEID
+			 | IEEE1284_ADDR)) {
+	case IEEE1284_MODE_NIBBLE:
+	case IEEE1284_MODE_BYTE:
+		return IEEE1284_PH_REV_IDLE;
+	}
+	return IEEE1284_PH_FWD_IDLE;
+}
+
 static int pp_ioctl(struct inode *inode, struct file *file,
 		    unsigned int cmd, unsigned long arg)
 {
@@ -351,7 +264,6 @@
 	/* First handle the cases that don't take arguments. */
 	if (cmd == PPCLAIM) {
 		struct ieee1284_info *info;
-		int first_claim = 0;
 
 		if (pp->flags & PP_CLAIMED) {
 			printk (KERN_DEBUG CHRDEV
@@ -364,8 +276,6 @@
 			int err = register_device (minor, pp);
 			if (err)
 				return err;
-
-			first_claim = 1;
 		}
 
 		parport_claim_or_block (pp->pdev);
@@ -379,24 +289,8 @@
 		info = &pp->pdev->port->ieee1284;
 		pp->saved_state.mode = info->mode;
 		pp->saved_state.phase = info->phase;
-		if (pp->mode != info->mode) {
-			int phase = IEEE1284_PH_FWD_IDLE;
-
-			if (first_claim) {
-				info->mode = pp->mode;
-				switch (pp->mode & ~(IEEE1284_DEVICEID
-						     | IEEE1284_ADDR)) {
-				case IEEE1284_MODE_NIBBLE:
-				case IEEE1284_MODE_BYTE:
-					phase = IEEE1284_PH_REV_IDLE;
-				}
-				info->phase = phase;
-			} else {
-				/* Just restore the state. */
-				info->mode = pp->state.mode;
-				info->phase = pp->state.phase;
-			}
-		}
+		info->mode = pp->state.mode;
+		info->phase = pp->state.phase;
 
 		return 0;
 	}
@@ -423,7 +317,27 @@
 		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
 			return -EFAULT;
 		/* FIXME: validate mode */
-		pp->mode = mode;
+		pp->state.mode = mode;
+		pp->state.phase = init_phase (mode);
+
+		if (pp->flags & PP_CLAIMED) {
+			pp->pdev->port->ieee1284.mode = mode;
+			pp->pdev->port->ieee1284.phase = pp->state.phase;
+		}
+
+		return 0;
+	}
+
+	if (cmd == PPSETPHASE) {
+		int phase;
+		if (copy_from_user (&phase, (int *) arg, sizeof (phase)))
+			return -EFAULT;
+		/* FIXME: validate phase */
+		pp->state.phase = phase;
+
+		if (pp->flags & PP_CLAIMED)
+			pp->pdev->port->ieee1284.phase = phase;
+
 		return 0;
 	}
 
@@ -559,7 +473,8 @@
 	if (!pp)
 		return -ENOMEM;
 
-	pp->mode = IEEE1284_MODE_COMPAT;
+	pp->state.mode = IEEE1284_MODE_COMPAT;
+	pp->state.phase = init_phase (pp->state.mode);
 	pp->flags = 0;
 	atomic_set (&pp->irqc, 0);
 	init_waitqueue_head (&pp->irq_wait);
diff -u --recursive --new-file v2.3.12/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h
--- v2.3.12/linux/drivers/char/ppdev.h	Wed Jul 28 14:47:42 1999
+++ linux/drivers/char/ppdev.h	Fri Jul 30 12:28:26 1999
@@ -69,3 +69,6 @@
 
 /* Clear (and return) interrupt count. */
 #define PPCLRIRQ	_IOR(PP_IOCTL, 0x93, int)
+
+/* Set the IEEE 1284 phase that we're in (e.g. IEEE1284_PH_FWD_IDLE) */
+#define PPSETPHASE	_IOW(PP_IOCTL, 0x94, int)
diff -u --recursive --new-file v2.3.12/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.3.12/linux/drivers/char/pty.c	Wed May 12 08:41:15 1999
+++ linux/drivers/char/pty.c	Thu Aug  5 14:34:01 1999
@@ -334,7 +334,7 @@
         tty->termios->c_cflag |= (CS8 | CREAD);
 }
 
-__initfunc(int pty_init(void))
+int __init pty_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/char/q40_keyb.c linux/drivers/char/q40_keyb.c
--- v2.3.12/linux/drivers/char/q40_keyb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/q40_keyb.c	Mon Aug  9 12:32:28 1999
@@ -0,0 +1,471 @@
+/*
+ * linux/drivers/char/q40_keyb.c
+ *
+ */
+
+#include <linux/config.h>
+
+#include <asm/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+#include <asm/irq.h>
+#include <asm/q40ints.h>
+
+/* Some configuration switches are present in the include file... */
+
+#define KBD_REPORT_ERR
+
+/* Simple translation table for the SysRq keys */
+
+#define SYSRQ_KEY 0x54
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char q40kbd_sysrq_xlate[128] =
+	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
+	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
+	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
+	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
+	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
+	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+	"\r\000/";					/* 0x60 - 0x6f */
+#endif
+
+/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
+/* 0x00 means not a valid entry or no conversion known                    */
+
+unsigned static char q40cl[256] =
+{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   f, */
+ 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00,     /* 0x00 - 0x0f */
+ 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00,     /* 0x10 - 0x1f */
+ 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00,     /* 0x20 - 0x2f  'f' is at 0x2b, what is 0x28 ???*/
+ 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00,     /* 0x30 - 0x3f */
+ 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00,     /* 0x40 - 0x4f */
+ 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00,     /* 0x50 - 0x5f*/
+ 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,     /* 0x60 - 0x6f */
+ 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00,     /* 0x70 - 0x7f */
+ 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x80 - 0x8f  0x84/0x37 is SySrq*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x90 - 0x9f */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xa0 - 0xaf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xb0 - 0xbf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xc0 - 0xcf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xd0 - 0xdf */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xe0 - 0xef */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xf0 - 0xff */
+};
+
+/* another table, AT 0xe0 codes to PC 0xe0 codes, 
+   0xff special entry for SysRq - DROPPED right now  */
+static unsigned char q40ecl[]=
+{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   f, */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x00 - 0x0f*/
+ 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x10 - 0x1f */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x20 - 0x2f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x30 - 0x3f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00,     /* 0x40 - 0x4f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,     /* 0x50 - 0x5f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,     /* 0x60 - 0x6f*/
+ 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00,     /* 0x70 - 0x7f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x80 - 0x8f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x90 - 0x9f*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xa0 - 0xaf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xb0 - 0xbf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xc0 - 0xcf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xd0 - 0xdf*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xe0 - 0xef*/
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00      /* 0xf0 - 0xff*/
+};
+
+
+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL   97
+#define E0_KPSLASH 98
+#define E0_PRSCR   99
+#define E0_RALT    100
+#define E0_BREAK   101  /* (control-pause) */
+#define E0_HOME    102
+#define E0_UP      103
+#define E0_PGUP    104
+#define E0_LEFT    105
+#define E0_RIGHT   106
+#define E0_END     107
+#define E0_DOWN    108
+#define E0_PGDN    109
+#define E0_INS     110
+#define E0_DEL     111
+
+#define E1_PAUSE   119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85           /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86     124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
+  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
+  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
+  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO   112
+/* LK450 */
+#define E0_F13     113
+#define E0_F14     114
+#define E0_HELP    115
+#define E0_DO      116
+#define E0_F17     117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for  the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK	124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW	125
+#define E0_MSRW	126
+#define E0_MSTM	127
+
+/* this can be changed using setkeys : */
+static unsigned char e0_keys[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
+  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
+  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
+  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
+  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
+  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
+  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
+  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
+  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
+};
+
+static unsigned int prev_scancode = 0;   /* remember E0, E1 */
+
+int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+	  return -EINVAL;
+	if (scancode < 128)
+	  high_keys[scancode - SC_LIM] = keycode;
+	else
+	  e0_keys[scancode - 128] = keycode;
+	return 0;
+}
+
+int q40kbd_getkeycode(unsigned int scancode)
+{
+	return
+	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
+	    e0_keys[scancode - 128];
+}
+
+
+#define disable_keyboard()	
+#define enable_keyboard()	
+
+
+
+int q40kbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+	if (scancode == 0xff) {
+		/* in scancode mode 1, my ESC key generates 0xff */
+		/* the calculator keys on a FOCUS 9000 generate 0xff */
+#ifndef KBD_IS_FOCUS_9000
+#ifdef KBD_REPORT_ERR
+		if (!raw_mode)
+		  printk(KERN_DEBUG "Keyboard error\n");
+#endif
+#endif
+		prev_scancode = 0;
+		return 0;
+	}
+
+	if (scancode == 0xe0 || scancode == 0xe1) {
+		prev_scancode = scancode;
+		return 0;
+ 	}
+ 	return 1;
+}
+
+int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode)
+{
+  /*printk("translate ...\n");*/
+	if (prev_scancode) {
+	  /*
+	   * usually it will be 0xe0, but a Pause key generates
+	   * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+	   */
+	  if (prev_scancode != 0xe0) {
+	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
+		  prev_scancode = 0x100;
+		  return 0;
+	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
+		  *keycode = E1_PAUSE;
+		  prev_scancode = 0;
+	      } else {
+#ifdef KBD_REPORT_UNKN
+		  if (!raw_mode)
+		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+		  prev_scancode = 0;
+		  return 0;
+	      }
+	  } else {
+	      prev_scancode = 0;
+	      /*
+	       *  The keyboard maintains its own internal caps lock and
+	       *  num lock statuses. In caps lock mode E0 AA precedes make
+	       *  code and E0 2A follows break code. In num lock mode,
+	       *  E0 2A precedes make code and E0 AA follows break code.
+	       *  We do our own book-keeping, so we will just ignore these.
+	       */
+	      /*
+	       *  For my keyboard there is no caps lock mode, but there are
+	       *  both Shift-L and Shift-R modes. The former mode generates
+	       *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+	       *  So, we should also ignore the latter. - aeb@cwi.nl
+	       */
+	      if (scancode == 0x2a || scancode == 0x36)
+		return 0;
+
+	      if (e0_keys[scancode])
+		*keycode = e0_keys[scancode];
+	      else {
+#ifdef KBD_REPORT_UNKN
+		  if (!raw_mode)
+		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+			   scancode);
+#endif
+		  return 0;
+	      }
+	  }
+	} else if (scancode >= SC_LIM) {
+	    /* This happens with the FOCUS 9000 keyboard
+	       Its keys PF1..PF12 are reported to generate
+	       55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+	       Moreover, unless repeated, they do not generate
+	       key-down events, so we have to zero up_flag below */
+	    /* Also, Japanese 86/106 keyboards are reported to
+	       generate 0x73 and 0x7d for \ - and \ | respectively. */
+	    /* Also, some Brazilian keyboard is reported to produce
+	       0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+	  *keycode = high_keys[scancode - SC_LIM];
+
+	  if (!*keycode) {
+	      if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+			 " - ignored\n", scancode);
+#endif
+	      }
+	      return 0;
+	  }
+ 	} else
+	  *keycode = scancode;
+ 	return 1;
+}
+
+char q40kbd_unexpected_up(unsigned char keycode)
+{
+	/* unexpected, but this can happen: maybe this was a key release for a
+	   FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+	if (keycode >= SC_LIM || keycode == 85)
+	    return 0;
+	else
+	    return 0200;
+}
+
+static int keyup=0;
+static int qprev=0;
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	unsigned char status;
+
+	disable_keyboard();
+	spin_lock_irqsave(&kbd_controller_lock, flags);
+	kbd_pt_regs = regs;
+
+	status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
+	if (status ) 
+	  {
+	    unsigned char scancode,qcode;
+	    
+	    qcode = master_inb(KEYCODE_REG);
+	    
+	    if (qcode != 0xf0)
+	      {
+		if (qcode == 0xe0)
+		  {
+		    qprev=0xe0;
+		    handle_scancode(qprev);
+		    goto exit;
+		  }
+		
+		scancode=qprev ? q40ecl[qcode] : q40cl[qcode];
+#if 0
+/* next line is last resort to hanlde some oddities */
+		if (qprev && !scancode) scancode=q40cl[qcode];
+#endif
+		qprev=0;
+		if (!scancode)
+		  {
+		    printk("unknown scancode %x\n",qcode);
+		    goto exit;
+		  }
+		if (scancode==0xff)  /* SySrq */
+		  scancode=SYSRQ_KEY;
+
+		handle_scancode(scancode | (keyup ? 0200 : 0));
+		keyup=0;
+		mark_bh(KEYBOARD_BH);
+
+	      }
+	    else
+	      keyup=1;
+	  }
+exit:
+	spin_unlock_irqrestore(&kbd_controller_lock, flags);
+	master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
+	enable_keyboard();
+}
+
+
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+int kbd_is_sysrq(unsigned char keycode)
+{
+	return( keycode == SYSRQ_KEY );
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+
+
+
+#define KBD_NO_DATA	(-1)	/* No data */
+#define KBD_BAD_DATA	(-2)	/* Parity or other error */
+
+static int __init kbd_read_input(void)
+{
+	int retval = KBD_NO_DATA;
+	unsigned char status;
+
+	status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
+	if (status) {
+		unsigned char data = master_inb(KEYCODE_REG);
+
+		retval = data;
+		master_outb(-1,KEYBOARD_UNLOCK_REG);
+	}
+	return retval;
+}
+
+extern void q40kbd_leds(unsigned char leds)
+{ /* nothing can be done */ }
+
+static void __init kbd_clear_input(void)
+{
+	int maxread = 100;	/* Random number */
+
+	do {
+		if (kbd_read_input() == KBD_NO_DATA)
+			break;
+	} while (--maxread);
+}
+
+
+void __init q40kbd_init_hw(void)
+{
+#if 0
+	/* Get the keyboard controller registers (incomplete decode) */
+	request_region(0x60, 16, "keyboard");
+#endif
+	/* Flush any pending input. */
+	kbd_clear_input();
+
+	/* Ok, finally allocate the IRQ, and off we go.. */
+	request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL);
+	master_outb(-1,KEYBOARD_UNLOCK_REG);
+	master_outb(1,KEY_IRQ_ENABLE_REG);
+
+}
+
diff -u --recursive --new-file v2.3.12/linux/drivers/char/raw.c linux/drivers/char/raw.c
--- v2.3.12/linux/drivers/char/raw.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/char/raw.c	Mon Aug  9 12:28:41 1999
@@ -13,6 +13,7 @@
 #include <linux/major.h>
 #include <linux/blkdev.h>
 #include <linux/raw.h>
+#include <linux/capability.h>
 #include <asm/uaccess.h>
 
 #define dprintk(x...) 
@@ -233,6 +234,15 @@
 		}
 
 		if (command == RAW_SETBIND) {
+			/*
+			 * This is like making block devices, so demand the
+			 * same capability
+			 */
+			if (!capable(CAP_SYS_ADMIN)) {
+				err = -EPERM;
+				break;
+			}
+
 			/* 
 			 * For now, we don't need to check that the underlying
 			 * block device is present or not: we can do that when
diff -u --recursive --new-file v2.3.12/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v2.3.12/linux/drivers/char/riscom8.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/riscom8.c	Thu Aug  5 14:34:01 1999
@@ -232,7 +232,7 @@
 }
 
 /* Reset and setup CD180 chip */
-__initfunc(static void rc_init_CD180(struct riscom_board const * bp))
+static void __init rc_init_CD180(struct riscom_board const * bp)
 {
 	unsigned long flags;
 	
@@ -257,7 +257,7 @@
 }
 
 /* Main probing routine, also sets irq. */
-__initfunc(static int rc_probe(struct riscom_board *bp))
+static int __init rc_probe(struct riscom_board *bp)
 {
 	unsigned char val1, val2;
 	int irqs = 0;
@@ -1820,7 +1820,7 @@
  * addresses in this case.
  *
  */ 
-__initfunc(void riscom8_setup(char *str, int * ints))
+void __init riscom8_setup(char *str, int * ints)
 {
 	int i;
 
@@ -1836,7 +1836,7 @@
 /* 
  * This routine must be called by kernel at boot time 
  */
-__initfunc(int riscom8_init(void))
+int __init  riscom8_init(void)
 {
 	int i;
 	int found = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/char/rocket.c linux/drivers/char/rocket.c
--- v2.3.12/linux/drivers/char/rocket.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/rocket.c	Thu Aug  5 15:04:52 1999
@@ -1958,7 +1958,7 @@
 }
 #endif
      
-__initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn))
+int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
 {
 	int	num_aiops, aiop, max_num_aiops, num_chan, chan;
 	unsigned int	aiopio[MAX_AIOPS_PER_BOARD];
@@ -1973,15 +1973,7 @@
 	if (!dev)
 		return 0;
 
-#if (LINUX_VERSION_CODE >= 0x020163) /* 2.1.99 */
-	rcktpt_io_addr[i] = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-#else
-	ret = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
-		&port);
-	if (ret)
-		return 0;
-	rcktpt_io_addr[i] = port & PCI_BASE_ADDRESS_IO_MASK;
-#endif	
+	rcktpt_io_addr[i] = dev->resource[0].start;
 	switch(dev->device) {
 	case PCI_DEVICE_ID_RP4QUAD:
 		str = "Quadcable";
@@ -2047,7 +2039,7 @@
 	return(1);
 }
 
-__initfunc(static int init_PCI(int boards_found))
+static int __init init_PCI(int boards_found)
 {
 	unsigned char	bus, device_fn;
 	int	i, count = 0;
@@ -2102,7 +2094,7 @@
 }
 #endif
 
-__initfunc(static int init_ISA(int i, int *reserved_controller))
+static int __init init_ISA(int i, int *reserved_controller)
 {
 	int	num_aiops, num_chan;
 	int	aiop, chan;
@@ -2154,7 +2146,7 @@
 /*
  * The module "startup" routine; it's run when the module is loaded.
  */
-__initfunc(int rp_init(void))
+int __init rp_init(void)
 {
 	int i, retval, pci_boards_found, isa_boards_found;
 	int	reserved_controller = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.3.12/linux/drivers/char/rtc.c	Wed Jun  9 14:44:25 1999
+++ linux/drivers/char/rtc.c	Thu Aug  5 14:34:02 1999
@@ -524,7 +524,7 @@
 	&rtc_fops
 };
 
-__initfunc(int rtc_init(void))
+int __init rtc_init(void)
 {
 	unsigned long flags;
 #ifdef __alpha__
diff -u --recursive --new-file v2.3.12/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v2.3.12/linux/drivers/char/softdog.c	Wed Jun  2 11:29:13 1999
+++ linux/drivers/char/softdog.c	Thu Aug  5 14:34:02 1999
@@ -178,7 +178,7 @@
 	&softdog_fops
 };
 
-__initfunc(void watchdog_init(void))
+void __init watchdog_init(void)
 {
 	misc_register(&softdog_miscdev);
 	init_timer(&watchdog_ticktock);
diff -u --recursive --new-file v2.3.12/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.3.12/linux/drivers/char/stallion.c	Wed May 26 09:31:45 1999
+++ linux/drivers/char/stallion.c	Thu Aug  5 14:34:02 1999
@@ -2280,7 +2280,7 @@
  *	interrupt across multiple boards.
  */
 
-__initfunc(static int stl_mapirq(int irq, char *name))
+static int __init stl_mapirq(int irq, char *name)
 {
 	int	rc, i;
 
@@ -2311,7 +2311,7 @@
  *	Initialize all the ports on a panel.
  */
 
-__initfunc(static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp))
+static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
 {
 	stlport_t	*portp;
 	int		chipmask, i;
@@ -2700,7 +2700,7 @@
  *	since the initial search and setup is very different.
  */
 
-__initfunc(static int stl_brdinit(stlbrd_t *brdp))
+static int __init stl_brdinit(stlbrd_t *brdp)
 {
 	int	i;
 
@@ -3204,7 +3204,7 @@
 
 /*****************************************************************************/
 
-__initfunc(int stl_init(void))
+int __init stl_init(void)
 {
 	printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
 
diff -u --recursive --new-file v2.3.12/linux/drivers/char/sx.c linux/drivers/char/sx.c
--- v2.3.12/linux/drivers/char/sx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sx.c	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,2684 @@
+
+/* sx.c -- driver for the Specialix SX series cards. 
+ *
+ *  This driver will also support the older SI, and XIO cards.
+ *
+ *
+ *   (C) 1998 R.E.Wolff@BitWizard.nl
+ *
+ *  Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous
+ *  version of this driver. Some fragments may have been copied. (none
+ *  yet :-)
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (sx.txt) first.
+ *
+ *
+ *
+ *      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.
+ *
+ * Revision history:
+ * $Log: sx.c,v $
+ * Revision 1.26  1999/08/05 15:22:14  wolff
+ * - Port to 2.3.x
+ * - Reformatted to Linus' liking.
+ *
+ * Revision 1.25  1999/07/30 14:24:08  wolff
+ * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0).
+ *
+ * Revision 1.24  1999/07/28 09:41:52  wolff
+ * - I noticed the remark about use-count straying in sx.txt. I checked
+ *   sx_open, and found a few places where that could happen. I hope it's
+ *   fixed now.
+ *
+ * Revision 1.23  1999/07/28 08:56:06  wolff
+ * - Fixed crash when sx_firmware run twice.
+ * - Added sx_slowpoll as a module parameter (I guess nobody really wanted
+ *   to change it from the default... )
+ * - Fixed a stupid editing problem I introduced in 1.22.
+ * - Fixed dropping characters on a termios change.
+ *
+ * Revision 1.22  1999/07/26 21:01:43  wolff
+ * Russell Brown noticed that I had overlooked 4 out of six modem control
+ * signals in sx_getsignals. Ooops.
+ *
+ * Revision 1.21  1999/07/23 09:11:33  wolff
+ * I forgot to free dynamically allocated memory when the driver is unloaded.
+ *
+ * Revision 1.20  1999/07/20 06:25:26  wolff
+ * The "closing wait" wasn't honoured. Thanks to James Griffiths for
+ * reporting this.
+ *
+ * Revision 1.19  1999/07/11 08:59:59  wolff
+ * Fixed an oops in close, when an open was pending. Changed the memtest
+ * a bit. Should also test the board in word-mode, however my card fails the
+ * memtest then. I still have to figure out what is wrong...
+ *
+ * Revision 1.18  1999/06/10 09:38:42  wolff
+ * Changed the format of the firmware revision from %04x to %x.%02x .
+ *
+ * Revision 1.17  1999/06/04 09:44:35  wolff
+ * fixed problem: reference to pci stuff when config_pci was off...
+ * Thanks to Jorge Novo for noticing this.
+ *
+ * Revision 1.16  1999/06/02 08:30:15  wolff
+ * added/removed the workaround for the DCD bug in the Firmware.
+ * A bit more debugging code to locate that...
+ *
+ * Revision 1.15  1999/06/01 11:35:30  wolff
+ * when DCD is left low (floating?), on TA's the firmware first tells us
+ * that DCD is high, but after a short while suddenly comes to the
+ * conclusion that it is low. All this would be fine, if it weren't that
+ * Unix requires us to send a "hangup" signal in that case. This usually
+ * all happens BEFORE the program has had a chance to ioctl the device
+ * into clocal mode..
+ *
+ * Revision 1.14  1999/05/25 11:18:59  wolff
+ * Added PCI-fix.
+ * Added checks for return code of sx_sendcommand.
+ * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...)
+ *
+ * Revision 1.13  1999/04/29 15:18:01  wolff
+ * Fixed an "oops" that showed on SuSE 6.0 systems.
+ * Activate DTR again after stty 0.
+ *
+ * Revision 1.12  1999/04/29 07:49:52  wolff
+ * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming
+ *     the connection would be dropped anyway. That is not always the case,
+ *     and confuses people).
+ * Told the card to always monitor the modem signals.
+ * Added support for dynamic  gs_debug adjustments.
+ * Now tells the rest of the system the number of ports.
+ *
+ * Revision 1.11  1999/04/24 11:11:30  wolff
+ * Fixed two stupid typos in the memory test.
+ *
+ * Revision 1.10  1999/04/24 10:53:39  wolff
+ * Added some of Christian's suggestions.
+ * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the
+ * card to send the signal to the process.....)
+ *
+ * Revision 1.9  1999/04/23 07:26:38  wolff
+ * Included Christian Lademann's 2.0 compile-warning fixes and interrupt
+ *    assignment redesign.
+ * Cleanup of some other stuff.
+ *
+ * Revision 1.8  1999/04/16 13:05:30  wolff
+ * fixed a DCD change unnoticed bug.
+ *
+ * Revision 1.7  1999/04/14 22:19:51  wolff
+ * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!)
+ *
+ * Revision 1.6  1999/04/13 18:40:20  wolff
+ * changed misc-minor to 161, as assigned by HPA.
+ *
+ * Revision 1.5  1999/04/13 15:12:25  wolff
+ * Fixed use-count leak when "hangup" occurred.
+ * Added workaround for a stupid-PCIBIOS bug.
+ *
+ *
+ * Revision 1.4  1999/04/01 22:47:40  wolff
+ * Fixed < 1M linux-2.0 problem.
+ * (vremap isn't compatible with ioremap in that case)
+ *
+ * Revision 1.3  1999/03/31 13:45:45  wolff
+ * Firmware loading is now done through a separate IOCTL.
+ *
+ * Revision 1.2  1999/03/28 12:22:29  wolff
+ * rcs cleanup
+ *
+ * Revision 1.1  1999/03/28 12:10:34  wolff
+ * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS). 
+ *
+ * Revision 0.12  1999/03/28 09:20:10  wolff
+ * Fixed problem in 0.11, continueing cleanup.
+ *
+ * Revision 0.11  1999/03/28 08:46:44  wolff
+ * cleanup. Not good.
+ *
+ * Revision 0.10  1999/03/28 08:09:43  wolff
+ * Fixed loosing characters on close.
+ *
+ * Revision 0.9  1999/03/21 22:52:01  wolff
+ * Ported back to 2.2.... (minor things)
+ *
+ * Revision 0.8  1999/03/21 22:40:33  wolff
+ * Port to 2.0
+ *
+ * Revision 0.7  1999/03/21 19:06:34  wolff
+ * Fixed hangup processing.
+ *
+ * Revision 0.6  1999/02/05 08:45:14  wolff
+ * fixed real_raw problems. Inclusion into kernel imminent.
+ *
+ * Revision 0.5  1998/12/21 23:51:06  wolff
+ * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it
+ * shouldn't have. THATs why I want to have transmit interrupts even when
+ * the buffer is empty.
+ *
+ * Revision 0.4  1998/12/17 09:34:46  wolff
+ * PPP works. ioctl works. Basically works!
+ *
+ * Revision 0.3  1998/12/15 13:05:18  wolff
+ * It works! Wow! Gotta start implementing IOCTL and stuff....
+ *
+ * Revision 0.2  1998/12/01 08:33:53  wolff
+ * moved over to 2.1.130
+ *
+ * Revision 0.1  1998/11/03 21:23:51  wolff
+ * Initial revision. Detects SX card.
+ *
+ * */
+
+
+#define RCS_ID "$Id: sx.c,v 1.26 1999/08/05 15:22:14 wolff Exp $"
+#define RCS_REV "$Revision: 1.26 $"
+
+
+#include <linux/module.h>
+#include <linux/config.h> 
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+
+/* The 3.0.0 version of sxboards/sxwindow.h  uses BYTE and WORD.... */
+#define BYTE u8
+#define WORD u16
+
+/* .... but the 3.0.4 version uses _u8 and _u16. */
+#define _u8 u8
+#define _u16 u16
+
+#include "sxboards.h"
+#include "sxwindow.h"
+
+
+/* I don't think that this driver can handle more than 256 ports on
+   one machine. You'll have to increase the number of boards in sx.h
+   if you want more than 4 boards.  */
+
+
+/* ************************************************************** */
+/* * This section can be removed when 2.0 becomes outdated....  * */
+/* ************************************************************** */
+
+
+#if LINUX_VERSION_CODE < 0x020100    /* Less than 2.1.0 */
+#define TWO_ZERO
+#else
+#if LINUX_VERSION_CODE < 0x020200   /* less than 2.2.x */
+#warning "Please use a 2.2.x kernel. "
+#else
+#if LINUX_VERSION_CODE < 0x020300   /* less than 2.3.x */
+#define TWO_TWO
+#else
+#define TWO_THREE
+#endif
+#endif
+#endif
+
+#ifdef TWO_ZERO
+
+/* Here is the section that makes the 2.2 compatible driver source 
+   work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, 
+   and provide for compatibility stuff here if possible. */
+
+#include <linux/bios32.h>
+
+#define Get_user(a,b)                a = get_user(b)
+#define Put_user(a,b)                0,put_user(a,b)
+#define copy_to_user(a,b,c)          memcpy_tofs(a,b,c)
+
+static inline int copy_from_user(void *to,const void *from, int c) 
+{
+  memcpy_fromfs(to, from, c);
+  return 0;
+}
+
+#define pci_present                  pcibios_present
+#define pci_read_config_word         pcibios_read_config_word
+#define pci_read_config_dword        pcibios_read_config_dword
+
+static inline unsigned char get_irq (unsigned char bus, unsigned char fn)
+{
+	unsigned char t; 
+	pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t);
+	return t;
+}
+
+static inline void *ioremap(unsigned long base, long length)
+{
+	if (base < 0x100000) return (void *)base;
+	return vremap (base, length);
+}
+
+#define my_iounmap(x, b)             (((long)x<0x100000)?0:vfree ((void*)x))
+
+#define capable(x)                   suser()
+
+#define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+
+#define test_and_set_bit(nr, addr)   set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) clear_bit(nr, addr)
+
+/* Not yet implemented on 2.0 */
+#define ASYNC_SPD_SHI  -1
+#define ASYNC_SPD_WARP -1
+
+
+/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it
+   to the "name" field that does exist. As long as the assignments are
+   done in the right order, there is nothing to worry about. */
+#define driver_name           name 
+
+/* Should be in a header somewhere. They are in tty.h on 2.2 */
+#define TTY_HW_COOK_OUT       14 /* Flag to tell ntty what we can handle */
+#define TTY_HW_COOK_IN        15 /* in hardware - output and input       */
+
+/* The return type of a "close" routine. */
+#define INT                   void
+#define NO_ERROR              /* Nothing */
+
+#else
+
+/* The 2.2.x compatibility section. */
+#include <asm/uaccess.h>
+
+
+#define Get_user(a,b)         get_user(a,b)
+#define Put_user(a,b)         put_user(a,b)
+#define get_irq(pdev)         pdev->irq
+
+#define INT                   int
+#define NO_ERROR              0
+
+#define my_iounmap(x,b)       (iounmap((char *)(b)))
+
+#endif
+
+#ifndef TWO_THREE
+/* These are new in 2.3. The source now uses 2.3 syntax, and here is 
+   the compatibility define... */
+#define wait_queue_head_t struct wait_queue *
+#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
+#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
+
+#endif
+
+
+
+#include "generic_serial.h"
+#include "sx.h"
+
+
+/* ************************************************************** */
+/* *                End of compatibility section..              * */
+/* ************************************************************** */
+
+
+
+/* Why the hell am I defining these here? */
+#define SX_TYPE_NORMAL 1
+#define SX_TYPE_CALLOUT 2
+
+#ifndef SX_NORMAL_MAJOR
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define SX_NORMAL_MAJOR  32
+#define SX_CALLOUT_MAJOR 33
+#endif
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+
+
+/* Configurable options: 
+   (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef SX_PARANOIA_CHECK
+
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 100
+   Hz, but it is user configurable. I don't recommend going above 1000
+   Hz. The interrupt ratelimit might trigger if the interrupt is
+   shared with a very active other device. */
+#define IRQ_RATE_LIMIT 20
+
+/* Sharing interrupts is possible now. If the other device wants more
+   than 2000 interrupts per second, we'd gracefully decline further
+   interrupts. That's not what we want. On the other hand, if the
+   other device interrupts 2000 times a second, don't use the SX
+   interrupt. Use polling. */
+#undef IRQ_RATE_LIMIT
+
+
+#if 0
+/* Not implemented */
+/* 
+ * The following defines are mostly for testing purposes. But if you need
+ * some nice reporting in your syslog, you can define them also.
+ */
+#define SX_REPORT_FIFO
+#define SX_REPORT_OVERRUN
+#endif 
+
+
+/* Function prototypes */
+static void sx_disable_tx_interrupts (void * ptr); 
+static void sx_enable_tx_interrupts (void * ptr); 
+static void sx_disable_rx_interrupts (void * ptr); 
+static void sx_enable_rx_interrupts (void * ptr); 
+static int  sx_get_CD (void * ptr); 
+static void sx_shutdown_port (void * ptr);
+static void sx_set_real_termios (void  *ptr);
+static void sx_hungup (void  *ptr);
+static void sx_close (void  *ptr);
+static int sx_chars_in_buffer (void * ptr);
+static int sx_init_board (struct sx_board *board);
+static int sx_init_portstructs (int nboards, int nports);
+static int sx_fw_ioctl (struct inode *inode, struct file *filp,
+		         unsigned int cmd, unsigned long arg);
+static int sx_fw_open(struct inode *inode, struct file *filp);
+static INT sx_fw_release(struct inode *inode, struct file *filp);
+static int sx_init_drivers(void);
+void my_hd (unsigned char *addr, int len);
+
+
+
+static struct tty_driver sx_driver, sx_callout_driver;
+
+static struct tty_struct * sx_table[SX_NPORTS] = { NULL, };
+static struct termios ** sx_termios;
+static struct termios ** sx_termios_locked;
+
+struct sx_board boards[SX_NBOARDS];
+struct sx_port *sx_ports;
+int sx_refcount;
+int sx_initialized = 0;
+int sx_nports = 0;
+int sx_debug = 0;
+
+
+/* You can have the driver poll your card. 
+    - Set sx_poll to 1 to poll every timer tick (10ms on Intel). 
+      This is used when the card cannot use an interrupt for some reason.
+
+    - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If 
+      the driver misses an interrupt (report this if it DOES happen to you!)
+      everything will continue to work.... 
+ */
+int sx_poll = 1;
+int sx_slowpoll = 0;
+
+/* The card limits the number of interrupts per second. 
+   At 115k2 "100" should be sufficient. 
+   If you're using higher baudrates, you can increase this...
+ */
+
+int sx_maxints = 100;
+
+/* These are the only open spaces in my computer. Yours may have more
+   or less.... */
+int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, 
+                       0xc8000, 0xd8000, 0xe8000};
+int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, 
+                       0xc8000, 0xd8000, 0xe8000};
+
+#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int))
+#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int))
+
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts. 
+   Some architectures may need more. */
+int sx_irqmask = -1;
+
+#ifndef TWO_ZERO
+#ifdef MODULE
+MODULE_PARM(sx_poll, "i");
+MODULE_PARM(sx_slowpoll, "i");
+MODULE_PARM(sx_maxints, "i");
+MODULE_PARM(sx_debug, "i");
+MODULE_PARM(sx_irqmask, "i");
+#endif
+#endif
+
+static struct real_driver sx_real_driver = {
+	sx_disable_tx_interrupts,
+	sx_enable_tx_interrupts,
+	sx_disable_rx_interrupts,
+	sx_enable_rx_interrupts,
+	sx_get_CD,
+	sx_shutdown_port, 
+	sx_set_real_termios, 
+	sx_chars_in_buffer,
+	sx_close,
+	sx_hungup,
+	NULL
+};
+
+
+/* 
+   This driver can spew a whole lot of debugging output at you. If you
+   need maximum performance, you should disable the DEBUG define. To
+   aid in debugging in the field, I'm leaving the compile-time debug
+   features enabled, and disable them "runtime". That allows me to
+   instruct people with problems to enable debugging without requiring
+   them to recompile... 
+*/
+#define DEBUG
+
+
+#ifdef DEBUG
+#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
+#else
+#define sx_dprintk(f, str...) /* nothing */
+#endif
+
+
+
+#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n")
+#define func_exit()  sx_dprintk (SX_DEBUG_FLOW, "sx: exit  " __FUNCTION__ "\n")
+
+#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \
+                                  "(port %d)\n", port->line)
+
+
+
+
+/* 
+ *  Firmware loader driver specific routines
+ *
+ */
+
+static struct file_operations sx_fw_fops = {
+	NULL,	/*	lseek	*/
+	NULL,	/*	read	*/
+	NULL,	/*	write	*/
+	NULL,	/*	readdir	*/
+	NULL,	/*	select	*/
+	sx_fw_ioctl,
+	NULL,	/*	mmap	*/
+	sx_fw_open,
+#ifndef TWO_ZERO
+	NULL,	/*	flush	*/
+#endif
+	sx_fw_release,
+	NULL,	/*	fsync	*/
+	NULL,	/*	fasync	*/
+	NULL,	/*	check_media_change	*/
+	NULL,	/*	revalidate	*/
+};
+
+struct miscdevice sx_fw_device = {
+	SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
+};
+
+
+
+
+
+#ifdef SX_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int sx_paranoia_check(struct sx_port const * port,
+				    kdev_t device, const char *routine)
+{
+
+	static const char *badmagic =
+	  KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n";
+	static const char *badinfo =
+	  KERN_ERR "sx: Warning: null sx port for device %s in %s\n";
+ 
+	if (!port) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (port->magic != SX_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+
+	return 0;
+}
+#else
+#define sx_paranoia_check(a,b,c) 0
+#endif
+
+/* The timeouts. First try 30 times as fast as possible. Then give
+   the card some time to breathe between accesses. (Otherwise the
+   processor on the card might not be able to access its OWN bus... */
+
+#define TIMEOUT_1 30
+#define TIMEOUT_2 1000000
+
+
+/* This needs redoing for Alpha -- REW -- Done. */
+
+inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
+{
+	writeb (byte, board->base+offset);
+}
+
+inline u8 read_sx_byte (struct sx_board *board, int offset)
+{
+	return readb (board->base+offset);
+}
+
+
+inline void write_sx_word (struct sx_board *board, int offset, u16 word)
+{
+	writew (word, board->base+offset);
+}
+
+inline u16 read_sx_word (struct sx_board *board, int offset)
+{
+	return readw (board->base + offset);
+}
+
+
+int sx_busy_wait_eq (struct sx_board *board, 
+                     int offset,
+                     int mask,
+                     int correctval)
+{
+	int i;
+
+	func_enter ();
+
+	for (i=0; i < TIMEOUT_1 > 0;i++) 
+		if ((read_sx_byte (board, offset) & mask) == correctval) {
+			func_exit ();
+			return 1;
+		}
+
+	for (i=0; i < TIMEOUT_2 > 0;i++) {
+		if ((read_sx_byte (board, offset) & mask) == correctval) {
+			func_exit ();
+			return 1;
+		}
+		udelay (1);
+	}
+
+	func_exit ();
+	return 0;
+}
+
+
+int sx_busy_wait_neq (struct sx_board *board, 
+                      int offset,
+                      int mask,
+                      int badval)
+{
+	int i;
+
+	func_enter ();
+
+	for (i=0; i < TIMEOUT_1 > 0;i++) 
+		if ((read_sx_byte (board, offset) & mask) != badval) {
+			func_exit ();
+			return 1;
+		}
+
+	for (i=0; i < TIMEOUT_2 > 0;i++) {
+		if ((read_sx_byte (board, offset) & mask) != badval) {
+			func_exit ();
+			return 1;
+		}
+		udelay (1);
+	}
+
+	func_exit ();
+	return 0;
+}
+
+
+
+/* 5.6.4 of 6210028 r2.3 */
+int sx_reset (struct sx_board *board)
+{
+	func_enter ();
+
+	if (IS_SX_BOARD (board)) {
+
+		write_sx_byte (board, SX_CONFIG, 0);
+		write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */
+
+		if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) {
+			printk (KERN_INFO "sx: Card doesn't respond to reset....\n");
+			return 0;
+		}
+	} else {
+		/* Gory details of the SI/ISA board */
+		write_sx_byte (board, SI2_ISA_RESET,    SI2_ISA_RESET_SET);
+		write_sx_byte (board, SI2_ISA_IRQ11,    SI2_ISA_IRQ11_CLEAR);
+		write_sx_byte (board, SI2_ISA_IRQ12,    SI2_ISA_IRQ12_CLEAR);
+		write_sx_byte (board, SI2_ISA_IRQ15,    SI2_ISA_IRQ15_CLEAR);
+		write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+		write_sx_byte (board, SI2_ISA_IRQSET,   SI2_ISA_IRQSET_CLEAR);
+	}
+
+	func_exit ();
+	return 1;
+}
+
+
+/* This doesn't work on machines where "NULL" isn't 0 */
+/* If you have one of those, someone will need to write 
+   the equivalent of this, which will amount to about 3 lines. I don't
+   want to complicate this right now. -- REW
+   (See, I do write comments every now and then :-) */
+#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
+
+
+#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
+#define MODU_OFFSET(board,addr,elem)    (addr + OFFSETOF (_SXMODULE, elem))
+#define  BRD_OFFSET(board,elem)                (OFFSETOF (_SXCARD, elem))
+
+
+#define sx_write_channel_byte(port, elem, val) \
+   write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
+
+#define sx_read_channel_byte(port, elem) \
+   read_sx_byte (port->board, CHAN_OFFSET (port, elem))
+
+#define sx_write_channel_word(port, elem, val) \
+   write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
+
+#define sx_read_channel_word(port, elem) \
+   read_sx_word (port->board, CHAN_OFFSET (port, elem))
+
+
+#define sx_write_module_byte(board, addr, elem, val) \
+   write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
+
+#define sx_read_module_byte(board, addr, elem) \
+   read_sx_byte (board, MODU_OFFSET (board, addr, elem))
+
+#define sx_write_module_word(board, addr, elem, val) \
+   write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
+
+#define sx_read_module_word(board, addr, elem) \
+   read_sx_word (board, MODU_OFFSET (board, addr, elem))
+
+
+#define sx_write_board_byte(board, elem, val) \
+   write_sx_byte (board, BRD_OFFSET (board, elem), val)
+
+#define sx_read_board_byte(board, elem) \
+   read_sx_byte (board, BRD_OFFSET (board, elem))
+
+#define sx_write_board_word(board, elem, val) \
+   write_sx_word (board, BRD_OFFSET (board, elem), val)
+
+#define sx_read_board_word(board, elem) \
+   read_sx_word (board, BRD_OFFSET (board, elem))
+
+
+int sx_start_board (struct sx_board *board)
+{
+	if (IS_SX_BOARD (board)) {
+		write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN);
+	} else {
+		/* Don't bug me about the clear_set. 
+		   I haven't the foggiest idea what it's about -- REW*/
+		write_sx_byte (board, SI2_ISA_RESET,    SI2_ISA_RESET_CLEAR);
+		write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+	}
+	return 1;
+}
+
+#define SX_IRQ_REG_VAL(board) \
+        ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0)
+
+/* Note. The SX register is write-only. Therefore, we have to enable the
+   bus too. This is a no-op, if you don't mess with this driver... */
+int sx_start_interrupts (struct sx_board *board)
+{
+
+	/* Don't call this with board->irq == 0 */
+
+	if (IS_SX_BOARD(board)) {
+		write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) | 
+		                                 SX_CONF_BUSEN | 
+		                                 SX_CONF_HOSTIRQ);
+	} else {
+		switch (board->irq) {
+		case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break;
+		case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break;
+		case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break;
+		default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n", 
+		                board->irq);
+		return 0;
+		}
+		write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+	}
+
+	return 1;
+}
+
+
+int sx_send_command (struct sx_port *port, 
+                     int command,
+                     int mask,
+                     int newstat)
+{
+	func_enter2 ();
+	write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command);
+	func_exit ();
+	return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat);
+}
+
+
+char *mod_type_s (int module_type)
+{
+	switch (module_type) {
+	case TA4:       return "TA4";
+	case TA8:       return "TA8";
+	case TA4_ASIC:  return "TA4_ASIC";
+	case TA8_ASIC:  return "TA8_ASIC";
+	case MTA_CD1400:return "MTA_CD1400";
+	case SXDC:      return "SXDC";
+	default:return "Unknown/invalid";
+	}
+}
+
+
+char *pan_type_s (int pan_type)
+{
+	switch (pan_type) {
+	case MOD_RS232DB25:     return "MOD_RS232DB25";
+	case MOD_RS232RJ45:     return "MOD_RS232RJ45";
+	case MOD_RS422DB25:     return "MOD_RS422DB25";
+	case MOD_PARALLEL:      return "MOD_PARALLEL";
+	case MOD_2_RS232DB25:   return "MOD_2_RS232DB25";
+	case MOD_2_RS232RJ45:   return "MOD_2_RS232RJ45";
+	case MOD_2_RS422DB25:   return "MOD_2_RS422DB25";
+	case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE";
+	case MOD_2_PARALLEL:    return "MOD_2_PARALLEL";
+	case MOD_BLANK:         return "empty";
+	default:return "invalid";
+	}
+}
+
+
+int mod_compat_type (int module_type)
+{
+	return module_type >> 4;
+}
+
+
+static void sx_setsignals (struct sx_port *port, int dtr, int rts)
+{
+	int t;
+	func_enter2 ();
+
+	t = sx_read_channel_byte (port, hi_op);
+	if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR);
+	if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS);
+	sx_write_channel_byte (port, hi_op, t);
+	sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
+	func_exit ();
+}
+
+
+
+static int sx_getsignals (struct sx_port *port)
+{
+	int i_stat,o_stat;
+
+	o_stat = sx_read_channel_byte (port, hi_op);
+	i_stat = sx_read_channel_byte (port, hi_ip);
+
+	sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d  (%d/%d) %02x/%02x\n",
+	            (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
+	            port->c_dcd, sx_get_CD (port),
+	            sx_read_channel_byte (port, hi_ip),
+	            sx_read_channel_byte (port, hi_state));
+
+	return (((o_stat & OP_DTR)?TIOCM_DTR:0) |
+	        ((o_stat & OP_RTS)?TIOCM_RTS:0) |
+	        ((i_stat & IP_CTS)?TIOCM_CTS:0) |
+	        ((i_stat & IP_DCD)?TIOCM_CAR:0) |
+	        ((i_stat & IP_DSR)?TIOCM_DSR:0) |
+	        ((i_stat & IP_RI)?TIOCM_RNG:0)
+	        );
+}
+
+
+static void sx_set_baud (struct sx_port *port)
+{
+	int t;
+
+	if (port->board->ta_type == MOD_SXDC) {
+		switch (port->gs.baud) {
+		  /* Save some typing work... */
+#define e(x) case x:t= BAUD_ ## x ; break
+			e(50);e(75);e(110);e(150);e(200);e(300);e(600);
+                        e(1200);e(1800);e(2000);e(2400);e(4800);e(7200);
+                        e(9600);e(14400);e(19200);e(28800);e(38400);
+                        e(56000);e(57600);e(64000);e(76800);e(115200);
+			e(128000);e(150000);e(230400);e(256000);e(460800);
+                        e(921600);
+		case 134    :t = BAUD_134_5;   break;
+		case 0      :t = -1;
+								 break;
+		default:
+			/* Can I return "invalid"? */
+			t = BAUD_9600;
+			printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud);
+			break;
+		}
+#undef e
+		if (t > 0) {
+			/* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
+			sx_setsignals (port, 1, -1); 
+			/* XXX This is not TA & MTA compatible */
+			sx_write_channel_byte (port, hi_csr, 0xff);
+
+			sx_write_channel_byte (port, hi_txbaud, t);
+			sx_write_channel_byte (port, hi_rxbaud, t);
+		} else {
+			sx_setsignals (port, 0, -1);
+		}
+	} else {
+		switch (port->gs.baud) {
+#define e(x) case x:t= CSR_ ## x ; break
+			e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800);
+                        e(1800);e(9600);
+			e(19200);e(57600);e(38400);
+			/* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
+		case 110: 
+			if (port->board->ta_type == MOD_TA) {
+				t = CSR_110;
+				break;
+			} else {
+				t = CSR_9600;
+				printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+				break;
+			}
+		case 115200: 
+			if (port->board->ta_type == MOD_TA) {
+				t = CSR_9600;
+				printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+				break;
+			} else {
+				t = CSR_110;
+				break;
+			}
+		case 0      :t = -1;
+								 break;
+		default:
+			t = CSR_9600;
+			printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+			break;
+		}
+#undef e
+		if (t >= 0) {
+			sx_setsignals (port, 1, -1);
+			sx_write_channel_byte (port, hi_csr, t * 0x11);
+		} else {
+			sx_setsignals (port, 0, -1);
+		}
+	}
+}
+
+
+/* Simon Allen's version of this routine was 225 lines long. 85 is a lot
+   better. -- REW */
+
+static void sx_set_real_termios (void *ptr)
+{
+	struct sx_port *port = ptr;
+
+	func_enter2();
+
+	/* What is this doing here? -- REW
+	   Ha! figured it out. It is to allow you to get DTR active again
+	   if you've dropped it with stty 0. Moved to set_baud, where it
+	   belongs (next to the drop dtr if baud == 0) -- REW */
+	/* sx_setsignals (port, 1, -1); */
+
+	sx_set_baud (port);
+
+#define CFLAG port->gs.tty->termios->c_cflag
+	sx_write_channel_byte (port, hi_mr1,
+	                       (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) |
+	                       (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) |
+	                       (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) |
+	                       (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) |
+	                       (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) |
+	                       (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) |
+	                       (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) );
+
+	sx_write_channel_byte (port, hi_mr2,
+	                       (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) |
+	                       (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP));
+
+	switch (CFLAG & CSIZE) {
+	case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break;
+	case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break;
+	case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
+	case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
+	default:
+		printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);
+		break;
+	}
+
+	sx_write_channel_byte (port, hi_prtcl, 
+	                       (I_IXON   (port->gs.tty)?SP_TXEN:0) |
+	                       (I_IXOFF  (port->gs.tty)?SP_RXEN:0) |
+	                       (I_IXANY  (port->gs.tty)?SP_TANY:0) |
+	                       SP_DCEN);
+
+	sx_write_channel_byte (port, hi_break, 
+	                       I_OTHER(port->gs.tty) ? 0:
+	                       (I_IGNBRK(port->gs.tty)?BR_IGN:0 |
+	                        I_BRKINT(port->gs.tty)?BR_INT:0));
+
+	sx_write_channel_byte (port, hi_txon,  START_CHAR (port->gs.tty));
+	sx_write_channel_byte (port, hi_rxon,  START_CHAR (port->gs.tty));
+	sx_write_channel_byte (port, hi_txoff, STOP_CHAR  (port->gs.tty));
+	sx_write_channel_byte (port, hi_rxoff, STOP_CHAR  (port->gs.tty));
+
+	if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) {
+		if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
+			printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n");
+		}
+	} else {
+		sx_dprintk (SX_DEBUG_TERMIOS, 
+		            "sx: Not sending reconfigure: port isn't open (%02x).\n", 
+		            sx_read_channel_byte (port, hi_hstat));
+	}
+
+
+	/* Tell line discipline whether we will do input cooking */
+	if(I_OTHER(port->gs.tty)) {
+		clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+	} else {
+		set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
+	}
+	sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", 
+	            port->gs.tty->termios->c_iflag, 
+	            I_OTHER(port->gs.tty));
+
+
+/* Tell line discipline whether we will do output cooking.
+ * If OPOST is set and no other output flags are set then we can do output
+ * processing.  Even if only *one* other flag in the O_OTHER group is set
+ * we do cooking in software.
+ */
+	if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
+		set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+	} else {
+		clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
+	}
+	sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", 
+	            port->gs.tty->termios->c_oflag, 
+	            O_OTHER(port->gs.tty));
+	/* port->c_dcd = sx_get_CD (port); */
+	func_exit ();
+}
+
+
+
+/* ********************************************************************** *
+ *                   the interrupt related routines                       *
+ * ********************************************************************** */
+
+/* Note:
+   Other drivers use the macro "MIN" to calculate how much to copy.
+   This has the disadvantage that it will evaluate parts twice. That's
+   expensive when it's IO (and the compiler cannot optimize those away!).
+   Moreover, I'm not sure that you're race-free. 
+
+   I assign a value, and then only allow the value to decrease. This
+   is always safe. This makes the code a few lines longer, and you
+   know I'm dead against that, but I think it is required in this
+   case.  */
+
+
+void sx_transmit_chars (struct sx_port *port)
+{
+	int c;
+	int tx_ip;
+	int txroom;
+
+	func_enter2 ();
+	sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n", 
+	            port, port->gs.xmit_cnt);
+
+	if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) {
+		return;
+	}
+
+	while (1) {
+		c = port->gs.xmit_cnt;
+
+		sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c);
+		tx_ip  = sx_read_channel_byte (port, hi_txipos);
+
+		/* Took me 5 minutes to deduce this formula. 
+		   Luckily it is literally in the manual in section 6.5.4.3.5 */
+		txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff;
+
+		/* Don't copy more bytes than there is room for in the buffer */
+		if (c > txroom)
+			c = txroom;
+		sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom );
+
+		/* Don't copy past the end of the hardware transmit buffer */
+		if (c > 0x100 - tx_ip) 
+			c = 0x100 - tx_ip;
+
+		sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip );
+
+		/* Don't copy pas the end of the source buffer */
+		if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) 
+                	c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
+
+		sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n", 
+		            c, SERIAL_XMIT_SIZE- port->gs.xmit_tail);
+
+		/* If for one reason or another, we can't copy more data, we're done! */
+		if (c == 0) break;
+
+
+		memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip, 
+		             port->gs.xmit_buf + port->gs.xmit_tail, c);
+
+		/* Update the pointer in the card */
+		sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff);
+
+		/* Update the kernel buffer end */
+		port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
+
+		/* This one last. (this is essential)
+		   It would allow others to start putting more data into the buffer! */
+		port->gs.xmit_cnt -= c;
+	}
+
+	if (port->gs.xmit_cnt == 0) {
+		sx_disable_tx_interrupts (port);
+	}
+
+	if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    port->gs.tty->ldisc.write_wakeup)
+			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+		sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
+		            port->gs.wakeup_chars); 
+		wake_up_interruptible(&port->gs.tty->write_wait);
+	}
+
+	clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks);
+	func_exit ();
+}
+
+
+/* Note the symmetry between receiving chars and transmitting them!
+   Note: The kernel should have implemented both a receive buffer and
+   a transmit buffer. */
+
+/* Inlined: Called only once. Remove the inline when you add another call */
+inline void sx_receive_chars (struct sx_port *port)
+{
+	int c;
+	int rx_op;
+	struct tty_struct *tty;
+	int copied=0;
+
+	/* func_enter2 (); */
+	tty = port->gs.tty;
+	while (1) {
+		rx_op = sx_read_channel_byte (port, hi_rxopos);
+		c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff;
+
+		sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c); 
+
+		/* Don't copy more bytes than there is room for in the buffer */
+		if (tty->flip.count + c > TTY_FLIPBUF_SIZE) 
+			c = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+		sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); 
+
+		/* Don't copy past the end of the hardware receive buffer */
+		if (rx_op + c > 0x100) c = 0x100 - rx_op;
+
+		sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+
+		/* If for one reason or another, we can't copy more data, we're done! */
+		if (c == 0) break;
+
+		sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c, 
+		            read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),
+		            CHAN_OFFSET(port, hi_rxbuf)); 
+		memcpy_fromio (tty->flip.char_buf_ptr, 
+		               port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);
+		memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c);
+
+		/* Update the kernel buffer end */
+		tty->flip.count += c;
+		tty->flip.char_buf_ptr += c;
+		tty->flip.flag_buf_ptr += c;
+
+		/* This one last. ( Not essential.)
+		   It allows the card to start putting more data into the buffer! 
+		   Update the pointer in the card */
+		sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff);
+
+		copied += c;
+	}
+	if (copied) {
+		struct timeval tv;
+
+		do_gettimeofday (&tv);
+		sx_dprintk (SX_DEBUG_RECEIVE, 
+		            "pushing flipq port %d (%3d chars): %d.%06d  (%d/%d)\n", 
+		            port->line, copied, 
+		            (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw);
+
+		/* Tell the rest of the system the news. Great news. New characters! */
+		tty_flip_buffer_push (tty);
+		/*    tty_schedule_flip (tty); */
+	}
+
+	/* func_exit (); */
+}
+
+/* Inlined: it is called only once. Remove the inline if you add another 
+   call */
+inline void sx_check_modem_signals (struct sx_port *port)
+{
+	int hi_state;
+	int c_dcd;
+
+	hi_state = sx_read_channel_byte (port, hi_state);
+	sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
+	            port->c_dcd, sx_get_CD (port));
+
+	if (hi_state & ST_BREAK) {
+		hi_state &= ~ST_BREAK;
+		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
+
+		sx_write_channel_byte (port, hi_state, hi_state);
+		if (port->gs.flags & ASYNC_SAK) {
+			do_SAK (port->gs.tty);
+		}
+	}
+	if (hi_state & ST_DCD) {
+		hi_state &= ~ST_DCD;
+		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
+		sx_write_channel_byte (port, hi_state, hi_state);
+		c_dcd = sx_get_CD (port);
+		sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
+		if (c_dcd != port->c_dcd) {
+			port->c_dcd = c_dcd;
+			if (sx_get_CD (port)) {
+				/* DCD went UP */
+				if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || 
+						 ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) &&
+						(sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) {
+					/* Are we blocking in open?*/
+					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n");
+					wake_up_interruptible(&port->gs.open_wait);
+				} else {
+					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n");
+				}
+			} else {
+				/* DCD went down! */
+				if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
+				      (port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
+					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n");
+					tty_hangup (port->gs.tty);
+				} else {
+					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n");
+				}
+			}
+		} else {
+			sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n");
+		}
+	}
+}
+
+
+/* This is what an interrupt routine should look like. 
+ * Small, elegant, clear.
+ */
+
+static void sx_interrupt (int irq, void *ptr, struct pt_regs *regs)
+{
+	struct sx_board *board = ptr;
+	struct sx_port *port;
+	int i;
+
+	/*   func_enter ();  */
+	sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq); 
+
+	/* AAargh! The order in which to do these things is essential and
+	   not trivial. 
+
+	   - Rate limit goes before "recursive". Otherwise a series of
+	     recursive calls will hang the machine in the interrupt routine. 
+
+	   - hardware twiddling goes before "recursive". Otherwise when we
+	     poll the card, and a recursive interrupt happens, we wont
+	     ack the card, so it might keep on interrupting us. (especially
+	     level sensitive interrupt systems like PCI).
+
+	   - Rate limit goes before hardware twiddling. Otherwise we won't
+	     catch a card that has gone bonkers.
+
+	   - The "initialized" test goes after the hardware twiddling. Otherwise
+	     the card will stick us in the interrupt routine again.
+
+	   - The initialized test goes before recursive. 
+	*/
+
+
+
+#ifdef IRQ_RATE_LIMIT
+	/* Aaargh! I'm ashamed. This costs more lines-of-code than the
+	   actual interrupt routine!. (Well, used to when I wrote that comment) */
+	{
+		static int lastjif;
+		static int nintr=0;
+
+		if (lastjif == jiffies) {
+			if (++nintr > IRQ_RATE_LIMIT) {
+				free_irq (board->irq, board);
+				printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n", 
+					      board->irq);
+			}
+		} else {
+			lastjif = jiffies;
+			nintr = 0;
+		}
+	}
+#endif
+
+
+	if (board->irq == irq) {
+		/* Tell the card we've noticed the interrupt. */
+
+		sx_write_board_word (board, cc_int_pending, 0);
+		if (IS_SX_BOARD (board)) {
+			write_sx_byte (board, SX_RESET_IRQ, 1);
+		} else {
+			write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+			write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+		}
+	}
+
+	if (!sx_initialized) return;
+	if (!(board->flags & SX_BOARD_INITIALIZED)) return;
+
+	if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) {
+		printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
+		return;
+	}
+
+	 for (i=0;i<board->nports;i++) {
+		port = &board->ports[i];
+		if (port->gs.flags & GS_ACTIVE) {
+			if (sx_read_channel_byte (port, hi_state)) {
+				sx_dprintk (SX_DEBUG_INTERRUPTS, 
+				            "Port %d: modem signal change?... \n", i);
+				sx_check_modem_signals (port); 
+			}
+			if (port->gs.xmit_cnt) {
+				sx_transmit_chars (port);
+			}
+			if (!(port->gs.flags & SX_RX_THROTTLE)) {
+				sx_receive_chars (port);
+			}
+		}
+	}
+
+	clear_bit (SX_BOARD_INTR_LOCK, &board->locks);
+
+	sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq); 
+	/*  func_exit ();  */
+}
+
+
+static void sx_pollfunc (unsigned long data)
+{
+	struct sx_board *board = (struct sx_board *) data;
+
+	func_enter ();
+
+	sx_interrupt (0, board, NULL);
+
+	board->timer.expires = jiffies + sx_poll;
+	add_timer (&board->timer);
+	func_exit ();
+}
+
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *              interface with the generic_serial driver                  *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */
+/* Hmm. Ok I figured it out. You don't.  */
+
+static void sx_disable_tx_interrupts (void * ptr) 
+{
+	struct sx_port *port = ptr; 
+	func_enter2();
+
+	port->gs.flags &= ~GS_TX_INTEN;
+
+	func_exit();
+}
+
+
+static void sx_enable_tx_interrupts (void * ptr) 
+{
+	struct sx_port *port = ptr; 
+	int data_in_buffer;
+	func_enter2();
+
+	/* First transmit the characters that we're supposed to */
+	sx_transmit_chars (port);
+
+	/* The sx card will never interrupt us if we don't fill the buffer
+	   past 25%. So we keep considering interrupts off if that's the case. */
+	data_in_buffer = (sx_read_channel_byte (port, hi_txipos) - 
+	                  sx_read_channel_byte (port, hi_txopos)) & 0xff;
+
+	/* XXX Must be "HIGH_WATER" for SI card according to doc. */
+	if (data_in_buffer < LOW_WATER) 
+		port->gs.flags &= ~GS_TX_INTEN;
+
+	func_exit();
+}
+
+
+static void sx_disable_rx_interrupts (void * ptr) 
+{
+	/*  struct sx_port *port = ptr; */
+	func_enter();
+
+	func_exit();
+}
+
+static void sx_enable_rx_interrupts (void * ptr) 
+{
+	/*  struct sx_port *port = ptr; */
+	func_enter();
+
+	func_exit();
+}
+
+
+/* Jeez. Isn't this simple? */
+static int sx_get_CD (void * ptr) 
+{
+	struct sx_port *port = ptr;
+	func_enter2();
+
+	func_exit();
+	return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0);
+}
+
+
+/* Jeez. Isn't this simple? */
+static int sx_chars_in_buffer (void * ptr) 
+{
+	struct sx_port *port = ptr;
+	func_enter2();
+
+	func_exit();
+	return ((sx_read_channel_byte (port, hi_txipos) - 
+	         sx_read_channel_byte (port, hi_txopos)) & 0xff);
+}
+
+
+static void sx_shutdown_port (void * ptr) 
+{
+	struct sx_port *port = ptr; 
+
+	func_enter();
+
+	port->gs.flags &= ~ GS_ACTIVE;
+	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
+		sx_setsignals (port, 0, 0);
+	}
+
+	func_exit();
+}
+
+
+
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *               interface with the rest of the system                    *
+ * ********************************************************************** */
+
+
+static int sx_fw_open(struct inode *inode, struct file *filp)
+{
+	func_enter ();
+	MOD_INC_USE_COUNT;
+	func_exit ();
+	return 0;
+}
+
+
+static INT sx_fw_release(struct inode *inode, struct file *filp)
+{
+	func_enter ();
+	MOD_DEC_USE_COUNT;
+	func_exit ();
+	return NO_ERROR;
+}
+
+
+static int sx_open  (struct tty_struct * tty, struct file * filp)
+{
+	struct sx_port *port;
+	int retval, line;
+
+	func_enter();
+
+	if (!sx_initialized) {
+		return -EIO;
+	}
+
+	line = MINOR(tty->device);
+	sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", 
+	            current->pid, line, tty, current->tty, sx_nports);
+
+	if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
+		return -ENODEV;
+
+	port = & sx_ports[line];
+	port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a
+	                    1 -> 0 transition. */
+
+
+	sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
+
+	tty->driver_data = port;
+	port->gs.tty = tty;
+	port->gs.count++;
+
+	sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
+
+	/*
+	 * Start up serial port
+	 */
+	retval = gs_init_port(&port->gs);
+	sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n");
+	if (retval) {
+		port->gs.count--;
+		return retval;
+	}
+
+	port->gs.flags |= GS_ACTIVE;
+	sx_setsignals (port, 1,1);
+
+	sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n", 
+	            port->gs.count);
+	if (port->gs.count == 1) {
+		MOD_INC_USE_COUNT;
+	}
+	sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n");
+
+#if 0
+	if (sx_debug & SX_DEBUG_OPEN)
+		my_hd ((unsigned char *)port, sizeof (*port));
+#else
+	if (sx_debug & SX_DEBUG_OPEN)
+		my_hd ((unsigned char *)port->board->base + port->ch_base, 
+		       sizeof (*port));
+#endif
+
+	if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+		printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
+		MOD_DEC_USE_COUNT;
+		port->gs.count--;
+		return -EIO;
+	}
+
+	retval = block_til_ready(port, filp);
+	sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", 
+	            retval, port->gs.count);
+
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		port->gs.count--;
+		return retval;
+	}
+	/* tty->low_latency = 1; */
+
+	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = port->gs.normal_termios;
+		else 
+			*tty->termios = port->gs.callout_termios;
+		sx_set_real_termios (port);
+	}
+
+	port->gs.session = current->session;
+	port->gs.pgrp = current->pgrp;
+	port->c_dcd = sx_get_CD (port);
+	sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+	func_exit();
+	return 0;
+
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+   here. The whole linux serial drivers stuff needs to be redesigned.
+   My guess is that this is a hack to minimize the impact of a bug
+   elsewhere. Thinking about it some more. (try it sometime) Try
+   running minicom on a serial port that is driven by a modularized
+   driver. Have the modem hangup. Then remove the driver module. Then
+   exit minicom.  I expect an "oops".  -- REW */
+static void sx_hungup (void *ptr)
+{
+	func_enter ();
+	MOD_DEC_USE_COUNT;
+	func_exit ();
+}
+
+
+static void sx_close (void *ptr)
+{
+	struct sx_port *port = ptr; 
+	/* Give the port 5 seconds to close down. */
+	int to = 5 * HZ; 
+
+	func_enter ();
+	sx_send_command (port, HS_CLOSE, 0, 0);
+
+	while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout (1);
+		if (signal_pending (current))
+				break;
+	}
+	current->state = TASK_RUNNING;
+	if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
+		if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
+			printk (KERN_ERR 
+			        "sx: sent the force_close command, but card didn't react\n");
+		} else
+			sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n");
+	}
+
+	sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", 
+	            5 * HZ - to - 1, port->gs.count);
+
+	MOD_DEC_USE_COUNT;
+	func_exit ();
+}
+
+
+
+/* This is relatively thorough. But then again it is only 20 lines. */
+#define MARCHUP    for (i=min;i<max;i++) 
+#define MARCHDOWN  for (i=max-1;i>=min;i--)
+#define W0         write_sx_byte (board, i, 0x55)
+#define W1         write_sx_byte (board, i, 0xaa)
+#define R0         if (read_sx_byte (board, i) != 0x55) return 1
+#define R1         if (read_sx_byte (board, i) != 0xaa) return 1
+
+/* This memtest takes a human-noticable time. You normally only do it
+   once a boot, so I guess that it is worth it. */
+int do_memtest (struct sx_board *board, int min, int max)
+{
+	int i;
+
+	/* This is a marchb. Theoretically, marchb catches much more than
+	   simpler tests. In practise, the longer test just catches more
+	   intermittent errors. -- REW
+	   (For the theory behind memory testing see: 
+	   Testing Semiconductor Memories by A.J. van de Goor.) */
+	MARCHUP	 {W0;}
+	MARCHUP   {R0;W1;R1;W0;R0;W1;}
+	MARCHUP   {R1;W0;W1;}
+	MARCHDOWN {R1;W0;W1;W0;}
+	MARCHDOWN {R0;W1;W0;}
+
+	return 0;
+}
+
+
+#undef MARCHUP
+#undef MARCHDOWN
+#undef W0
+#undef W1
+#undef R0
+#undef R1
+
+#define MARCHUP    for (i=min;i<max;i+=2) 
+#define MARCHDOWN  for (i=max-1;i>=min;i-=2)
+#define W0         write_sx_word (board, i, 0x55aa)
+#define W1         write_sx_word (board, i, 0xaa55)
+#define R0         if (read_sx_word (board, i) != 0x55aa) return 1
+#define R1         if (read_sx_word (board, i) != 0xaa55) return 1
+
+/* This memtest takes a human-noticable time. You normally only do it
+   once a boot, so I guess that it is worth it. */
+int do_memtest_w (struct sx_board *board, int min, int max)
+{
+	int i;
+
+	MARCHUP   {W0;}
+	MARCHUP   {R0;W1;R1;W0;R0;W1;}
+	MARCHUP   {R1;W0;W1;}
+	MARCHDOWN {R1;W0;W1;W0;}
+	MARCHDOWN {R0;W1;W0;}
+
+	return 0;
+}
+
+
+static int sx_fw_ioctl (struct inode *inode, struct file *filp,
+		         unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	int *descr = (int *)arg, i;
+	static struct sx_board *board = NULL;
+	int nbytes, offset, data;
+	char *tmp;
+
+	func_enter();
+
+#if 0 
+	/* Removed superuser check: Sysops can use the permissions on the device
+	   file to restrict access. Recommendation: Root only. (root.root 600) */
+	if (!suser ()) {
+		return -EPERM;
+	}
+#endif
+
+	sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
+
+	if (!board) board = &boards[0];
+	if (board->flags & SX_BOARD_PRESENT) {
+		sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n", 
+		            board->flags);
+	} else {
+		sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:", 
+		            board->flags);
+		for (i=0;i< SX_NBOARDS;i++)
+			sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
+		sx_dprintk (SX_DEBUG_FIRMWARE, "\n");
+		return -EIO;
+	}
+
+	switch (cmd) {
+	case SXIO_SET_BOARD:
+		sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
+		if (arg > SX_NBOARDS) return -EIO;
+		sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n");
+		if (!(boards[arg].flags	& SX_BOARD_PRESENT)) return -EIO;
+		sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n");
+		board = &boards[arg];
+		break;
+	case SXIO_GET_TYPE:
+		rc = IS_SX_BOARD (board)? SX_TYPE_SX:SX_TYPE_SI;
+		sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
+		break;
+	case SXIO_DO_RAMTEST:
+		if (sx_initialized) /* Already initialized: better not ramtest the board.  */
+			return -EPERM;
+		if (IS_SX_BOARD (board)) {
+			rc          = do_memtest   (board, 0, 0x7000);
+			if (!rc) rc = do_memtest   (board, 0, 0x7000);
+			/*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/
+		} else {
+			rc             = do_memtest   (board, 0, 0x7ff8);
+			/* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
+		}
+		sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc);
+		break;
+	case SXIO_DOWNLOAD:
+		if (sx_initialized) /* Already initialized */
+			return -EEXIST;
+		if (!sx_reset (board)) 
+			return -EIO;
+		sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
+
+		tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER);
+		if (!tmp) return -ENOMEM;
+		Get_user (nbytes, descr++);
+		Get_user (offset, descr++); 
+		Get_user (data,	 descr++);
+		while (nbytes && data) {
+			for (i=0;i<nbytes;i += SX_CHUNK_SIZE) {
+				copy_from_user (tmp, (char *)data+i, 
+				                (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
+				memcpy_toio    ((char *) (board->base + offset + i), tmp, 
+				                (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
+			}
+
+			Get_user (nbytes, descr++);
+			Get_user (offset, descr++); 
+			Get_user (data,   descr++);
+		}
+		kfree (tmp);
+		sx_nports += sx_init_board (board);
+		rc = sx_nports;
+		break;
+	case SXIO_INIT:
+		if (sx_initialized) /* Already initialized */
+			return -EEXIST;
+		/* This is not allowed until all boards are initialized... */
+		for (i=0;i<SX_NBOARDS;i++) {
+			if ( (boards[i].flags & SX_BOARD_PRESENT) &&
+			     !(boards[i].flags & SX_BOARD_INITIALIZED))
+				return -EIO;
+		}
+		for (i=0;i<SX_NBOARDS;i++)
+			if (!(boards[i].flags & SX_BOARD_PRESENT)) break;
+
+		sx_dprintk (SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
+		            "%d channels, first board: %d ports\n", 
+		            i, sx_nports, boards[0].nports);
+		rc = sx_init_portstructs (i, sx_nports);
+		sx_init_drivers ();
+		if (rc >= 0) 
+			sx_initialized++;
+		break;
+	case SXIO_SETDEBUG:
+		sx_debug = arg;
+		break;
+	case SXIO_GETDEBUG:
+		rc = sx_debug;
+		break;
+	case SXIO_SETGSDEBUG:
+		gs_debug = arg;
+		break;
+	case SXIO_GETGSDEBUG:
+		rc = gs_debug;
+		break;
+	default:
+		printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd);
+		break;
+	}
+	func_exit ();
+	return rc;
+}
+
+
+static int sx_ioctl (struct tty_struct * tty, struct file * filp, 
+                     unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	struct sx_port *port = tty->driver_data;
+	int ival;
+
+	/* func_enter2(); */
+
+	rc = 0;
+	switch (cmd) {
+	case TIOCGSOFTCAR:
+		rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+		              (unsigned int *) arg);
+		break;
+	case TIOCSSOFTCAR:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(int))) == 0) {
+			Get_user(ival, (unsigned int *) arg);
+			tty->termios->c_cflag =
+				(tty->termios->c_cflag & ~CLOCAL) |
+				(ival ? CLOCAL : 0);
+		}
+		break;
+	case TIOCGSERIAL:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+		                      sizeof(struct serial_struct))) == 0)
+			gs_getserial(&port->gs, (struct serial_struct *) arg);
+		break;
+	case TIOCSSERIAL:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(struct serial_struct))) == 0)
+			rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+		break;
+	case TIOCMGET:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			ival = sx_getsignals(port);
+			put_user(ival, (unsigned int *) arg);
+		}
+		break;
+	case TIOCMBIS:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			Get_user(ival, (unsigned int *) arg);
+			sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1),
+			                     ((ival & TIOCM_RTS) ? 1 : -1));
+		}
+		break;
+	case TIOCMBIC:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			Get_user(ival, (unsigned int *) arg);
+			sx_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1),
+			                     ((ival & TIOCM_RTS) ? 0 : -1));
+		}
+		break;
+	case TIOCMSET:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg,
+		                      sizeof(unsigned int))) == 0) {
+			Get_user(ival, (unsigned int *) arg);
+			sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0),
+			                     ((ival & TIOCM_RTS) ? 1 : 0));
+		}
+		break;
+
+	default:
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+
+	/* func_exit(); */
+	return rc;
+}
+
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation. 
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself.  This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here.  When we come to read characters from the
+ * rx buffers on the card (sx_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in sx_rx_throt[]). 
+ * If it can't we simply don't remove chars from the cards buffer. 
+ * When the tty layer can accept chars, we again note that here and when
+ * sx_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void sx_throttle (struct tty_struct * tty)
+{
+	struct sx_port *port = (struct sx_port *)tty->driver_data;
+
+	func_enter2();
+	/* If the port is using any type of input flow
+	 * control then throttle the port.
+	 */
+	if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) {
+		port->gs.flags |= SX_RX_THROTTLE;
+	}
+	func_exit();
+}
+
+
+static void sx_unthrottle (struct tty_struct * tty)
+{
+	struct sx_port *port = (struct sx_port *)tty->driver_data;
+
+	func_enter2();
+	/* Always unthrottle even if flow control is not enabled on
+	 * this port in case we disabled flow control while the port
+	 * was throttled
+	 */
+	port->gs.flags &= ~SX_RX_THROTTLE;
+	func_exit();
+	return;
+}
+
+
+/* ********************************************************************** *
+ *                    Here are the initialization routines.               *
+ * ********************************************************************** */
+
+
+
+
+static int sx_init_board (struct sx_board *board)
+{
+	int addr;
+	int chans;
+	int type;
+
+	func_enter();
+
+	/* This is preceded by downloading the download code. */
+
+	board->flags |= SX_BOARD_INITIALIZED;
+
+	/* This resets the processor again, to make sure it didn't do any
+	   foolish things while we were downloading the image */
+	if (!sx_reset (board))
+		return 0;
+
+	sx_start_board (board);
+
+	if (!sx_busy_wait_neq (board, 0, 0xff, 0)) {
+		printk (KERN_ERR "sx: Ooops. Board won't initialize.\n");
+		return 0;
+	}
+
+	/* Ok. So now the processor on the card is running. It gathered
+	   some info for us... */
+	sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n");
+	if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10);
+	sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n");
+	if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30);
+
+	sx_dprintk (SX_DEBUG_INIT, 
+	            "init_status: %x, %dk memory, firmware V%x.%02x,\n", 
+	            read_sx_byte (board, 0), read_sx_byte(board, 1), 
+	            read_sx_byte (board, 5), read_sx_byte(board, 4));
+
+	if (read_sx_byte (board, 0) == 0xff) {
+		printk (KERN_INFO "sx: No modules found. Sorry.\n");
+		board->nports = 0;
+		return 0;
+	}
+
+	chans = 0;
+
+	if (IS_SX_BOARD(board)) {
+		sx_write_board_word (board, cc_int_count, sx_maxints);
+	} else {
+		if (sx_maxints)
+			sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints);
+	}
+
+	/* grab the first module type... */
+	/*  board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
+	board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip));
+
+	/* XXX byteorder */
+	for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
+		type = sx_read_module_byte (board, addr, mc_chip);
+		sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n", 
+		            addr, read_sx_byte (board, addr + 2));
+
+		chans += sx_read_module_byte (board, addr, mc_type);
+
+		sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n", 
+		            mod_type_s (type),
+		            pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf),
+		            pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4));
+
+		sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n", 
+		            sx_read_module_byte (board, addr, mc_rev1),
+		            sx_read_module_byte (board, addr, mc_rev2),
+		            sx_read_module_byte (board, addr, mc_mtaasic_rev));
+
+		/* The following combinations are illegal: It should theoretically
+		   work, but timing problems make the bus HANG. */
+
+		if (mod_compat_type (type) != board->ta_type) {
+			printk (KERN_ERR "sx: This is an invalid configuration.\n"
+			        "Don't mix TA/MTA/SXDC on the same hostadapter.\n");
+			chans=0;
+			break;
+		}
+		if (IS_SI_BOARD(board) && (mod_compat_type(type) == 4)) {
+			printk (KERN_ERR "sx: This is an invalid configuration.\n"
+			        "Don't use SXDCs on an SI/XIO adapter.\n");
+			chans=0;
+			break;
+		}
+#if 0 /* Problem fixed: firmware 3.05 */
+		if (IS_SX_BOARD(board) && (type == TA8)) {
+			/* There are some issues with the firmware and the DCD/RTS
+			   lines. It might work if you tie them together or something.
+			   It might also work if you get a newer sx_firmware.	Therefore
+			   this is just a warning. */
+			printk (KERN_WARNING "sx: The SX host doesn't work too well "
+			        "with the TA8 adapters.\nSpecialix is working on it.\n");
+		}
+#endif
+	}
+
+	if (chans) {
+		/* board->flags |= SX_BOARD_PRESENT; */
+		if(board->irq > 0) {
+			/* fixed irq, probably PCI */
+			if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
+				if(request_irq(board->irq, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) {
+					printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq);
+					board->irq = 0;
+				}
+			} else
+				board->irq = 0;
+		} else if(board->irq < 0 && sx_irqmask) {
+			/* auto-allocate irq */
+			int irqnr;
+			int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
+			for(irqnr = 15; irqnr > 0; irqnr--)
+				if(irqmask & (1 << irqnr))
+					if(! request_irq(irqnr, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board))
+						break;
+			if(! irqnr)
+				printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
+			board->irq = irqnr;
+		} else
+			board->irq = 0;
+
+		if (board->irq) {
+			/* Found a valid interrupt, start up interrupts! */
+			sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq);
+			sx_start_interrupts (board);
+			board->poll = sx_slowpoll;
+			board->flags |= SX_IRQ_ALLOCATED;
+		} else {
+			/* no irq: setup board for polled operation */
+			board->poll = sx_poll;
+			sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll);
+		}
+
+		/* The timer should be initialized anyway: That way we can safely
+			 del_timer it when the module is unloaded. */
+		init_timer (&board->timer);
+
+		if (board->poll) {
+			board->timer.data = (unsigned long) board;
+			board->timer.function = sx_pollfunc;
+			board->timer.expires = jiffies + board->poll;
+			add_timer (&board->timer);
+		}
+	} else {
+		board->irq = 0;
+	}
+
+	board->nports = chans;
+	sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports);
+
+	func_exit();
+	return chans;
+}
+
+
+void printheader(void)
+{
+	static int header_printed = 0;
+
+	if (!header_printed) {
+		printk (KERN_INFO "Specialix SX driver "
+		        "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n");
+		printk (KERN_INFO "sx: version %s\n", RCS_ID);
+		header_printed = 1;
+	}
+}
+
+
+int probe_sx (struct sx_board *board)
+{
+	struct vpd_prom vpdp;
+	char *p;
+	int i;
+
+	func_enter();
+	sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n", 
+	            board->base + SX_VPD_ROM);
+
+	if (sx_debug & SX_DEBUG_PROBE)
+		my_hd ((char *)(board->base + SX_VPD_ROM), 0x40);
+
+	p = (char *) &vpdp;
+	for (i=0;i< sizeof (struct vpd_prom);i++)
+		*p++ = read_sx_byte (board, SX_VPD_ROM + i*2);
+
+	if (sx_debug & SX_DEBUG_PROBE)
+		my_hd ((char *)&vpdp, 0x20);
+
+	sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n");
+
+	if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
+		sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n", 
+		            vpdp.identifier); 
+		return 0;
+	}
+
+	printheader ();
+
+	printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base);
+	printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ", 
+	        vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
+	printk (           "Manufactured: %d/%d\n", 
+	        1970 + vpdp.myear, vpdp.mweek);
+
+
+	if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) &&
+	    (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
+		/* This might be a bit harsh. This was the primary reason the
+		   SX/ISA card didn't work at first... */
+		printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n");
+		return (0);
+	}
+
+	if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
+		if (board->base & 0x8000) {
+			printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base);
+			printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
+		}
+	}
+
+
+	board->nports = -1;
+
+	/* This resets the processor, and keeps it off the bus. */
+	if (!sx_reset (board)) 
+		return 0;
+	sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
+
+	board->flags |= SX_BOARD_PRESENT;
+
+	func_exit();
+	return 1;
+}
+
+
+
+/* Specialix probes for this card at 32k increments from 640k to 16M.
+   I consider machines with less than 16M unlikely nowadays, so I'm
+   not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA
+   card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves 
+   0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
+
+int probe_si (struct sx_board *board)
+{
+	int i;
+
+	func_enter();
+	sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n", 
+	            board->base + SI2_ISA_ID_BASE);
+
+	if (sx_debug & SX_DEBUG_PROBE)
+		my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8);
+
+	for (i=0;i<8;i++) {
+		if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) {
+			return 0;
+		}
+	}
+
+	printheader ();
+
+	printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base);
+	/* Compared to the SX boards, it is a complete guess as to what
+		 this card is up to... */
+
+	board->nports = -1;
+
+	/* This resets the processor, and keeps it off the bus. */
+	if (!sx_reset (board)) 
+		return 0;
+	sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
+
+	board->flags |= SX_BOARD_PRESENT;
+
+	func_exit();
+	return 1;
+}
+
+
+static int sx_init_drivers(void)
+{
+	int error;
+
+	func_enter();
+
+	memset(&sx_driver, 0, sizeof(sx_driver));
+	sx_driver.magic = TTY_DRIVER_MAGIC;
+	sx_driver.driver_name = "specialix_sx";
+	sx_driver.name = "ttyX";
+	sx_driver.major = SX_NORMAL_MAJOR;
+	sx_driver.num = sx_nports;
+	sx_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	sx_driver.subtype = SX_TYPE_NORMAL;
+	sx_driver.init_termios = tty_std_termios;
+	sx_driver.init_termios.c_cflag =
+	  B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	sx_driver.flags = TTY_DRIVER_REAL_RAW;
+	sx_driver.refcount = &sx_refcount;
+	sx_driver.table = sx_table;
+	sx_driver.termios = sx_termios;
+	sx_driver.termios_locked = sx_termios_locked;
+
+	sx_driver.open	= sx_open;
+	sx_driver.close = gs_close;
+	sx_driver.write = gs_write;
+	sx_driver.put_char = gs_put_char;
+	sx_driver.flush_chars = gs_flush_chars;
+	sx_driver.write_room = gs_write_room;
+	sx_driver.chars_in_buffer = gs_chars_in_buffer;
+	sx_driver.flush_buffer = gs_flush_buffer;
+	sx_driver.ioctl = sx_ioctl;
+	sx_driver.throttle = sx_throttle;
+	sx_driver.unthrottle = sx_unthrottle;
+	sx_driver.set_termios = gs_set_termios;
+	sx_driver.stop = gs_stop;
+	sx_driver.start = gs_start;
+	sx_driver.hangup = gs_hangup;
+
+	sx_callout_driver = sx_driver;
+	sx_callout_driver.name = "cux";
+	sx_callout_driver.major = SX_CALLOUT_MAJOR;
+	sx_callout_driver.subtype = SX_TYPE_CALLOUT;
+
+	if ((error = tty_register_driver(&sx_driver))) {
+		printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	if ((error = tty_register_driver(&sx_callout_driver))) {
+		tty_unregister_driver(&sx_driver);
+		printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n",
+		       error);
+		return 1;
+	}
+
+	func_exit();
+	return 0;
+}
+
+
+void * ckmalloc (int size)
+{
+	void *p;
+
+	p = kmalloc(size, GFP_KERNEL);
+	if (p) 
+		memset(p, 0, size);
+	return p;
+}
+
+
+static int sx_init_portstructs (int nboards, int nports)
+{
+	struct sx_board *board;
+	struct sx_port *port;
+	int i, j;
+	int addr, chans;
+	int portno;
+
+	func_enter();
+
+	/* Many drivers statically allocate the maximum number of ports
+	   There is no reason not to allocate them dynamically. Is there? -- REW */
+	sx_ports          = ckmalloc(nports * sizeof (struct sx_port));
+	if (!sx_ports)
+		return -ENOMEM;
+
+	sx_termios        = ckmalloc(nports * sizeof (struct termios *));
+	if (!sx_termios) {
+		kfree (sx_ports);
+		return -ENOMEM;
+	}
+
+	sx_termios_locked = ckmalloc(nports * sizeof (struct termios *));
+	if (!sx_termios_locked) {
+		kfree (sx_ports);
+		kfree (sx_termios);
+		return -ENOMEM;
+	}
+
+	/* Adjust the values in the "driver" */
+	sx_driver.termios = sx_termios;
+	sx_driver.termios_locked = sx_termios_locked;
+
+	port = sx_ports;
+	for (i = 0; i < nboards; i++) {
+		board = &boards[i];
+		board->ports = port;
+		for (j=0; j < boards[i].nports;j++) {
+			sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j);
+			port->gs.callout_termios = tty_std_termios;
+			port->gs.normal_termios	= tty_std_termios;
+			port->gs.magic = SX_MAGIC;
+			port->gs.close_delay = HZ/2;
+			port->gs.closing_wait = 30 * HZ;
+			port->board = board;
+			port->gs.rd = &sx_real_driver;
+#ifdef NEW_WRITE_LOCKING
+			port->gs.port_write_sem = MUTEX;
+#endif
+			port++;
+		}
+	}
+
+	port = sx_ports;
+	portno = 0;
+	for (i = 0; i < nboards; i++) {
+		board = &boards[i];
+		board->port_base = portno;
+		/* Possibly the configuration was rejected. */
+		sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports);
+		if (board->nports <= 0) continue;
+		/* XXX byteorder ?? */
+		for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
+			chans = sx_read_module_byte (board, addr, mc_type); 
+			sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans);
+			sx_dprintk (SX_DEBUG_PROBE, "Port at");
+			for (j=0;j<chans;j++) {
+				/* The "sx-way" is the way it SHOULD be done. That way in the 
+				   future, the firmware may for example pack the structures a bit
+				   more efficient. Neil tells me it isn't going to happen anytime
+				   soon though. */
+				if (IS_SX_BOARD(board))
+					port->ch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer);
+				else
+					port->ch_base = addr + 0x100 + 0x300*j;
+
+				sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base);
+				port->line = portno++;
+				port++;
+			}
+			sx_dprintk (SX_DEBUG_PROBE, "\n");
+		}
+		/* This has to be done earlier. */
+		/* board->flags |= SX_BOARD_INITIALIZED; */
+	}
+
+	func_exit();
+	return 0;
+}
+
+
+static void sx_release_drivers(void)
+{
+	func_enter();
+	tty_unregister_driver(&sx_driver);
+	tty_unregister_driver(&sx_callout_driver);
+	func_exit();
+}
+
+#ifdef TWO_ZERO
+#define PDEV unsigned char pci_bus, unsigned pci_fun
+#define pdev pci_bus, pci_fun
+#else
+#define PDEV   struct pci_dev *pdev
+#endif
+
+
+#ifdef CONFIG_PCI
+ /******************************************************** 
+ * Setting bit 17 in the CNTRL register of the PLX 9050  * 
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon  *
+ * multiprocessor systems with the NX chipset.    -- NV  *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+   EEprom.  As the bit is read/write for the CPU, we can fix it here,
+   if we detect that it isn't set correctly. -- REW */
+
+void fix_sx_pci (PDEV, struct sx_board *board)
+{
+	unsigned int hwbase;
+	unsigned long rebase;
+	int t;
+
+#define CNTRL_REG_OFFSET        0x14
+
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
+	hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
+	rebase = (ulong) ioremap(hwbase, 0x80);
+	t = readb (rebase + CNTRL_REG_OFFSET*4 + 2);
+	if (t != 0x06) {
+		printk (KERN_DEBUG "sx: performing cntrl reg fix: %02x -> 06\n", t); 
+		writeb (0x06, rebase + CNTRL_REG_OFFSET*4+2);
+	}
+	my_iounmap (hwbase, rebase);
+
+}
+#endif
+
+
+#ifdef MODULE
+#define sx_init init_module
+#endif
+
+int sx_init(void) 
+{
+	int i;
+	int found = 0;
+	struct sx_board *board;
+
+#ifdef CONFIG_PCI
+#ifndef TWO_ZERO
+	struct pci_dev *pdev = NULL;
+#else
+	unsigned char pci_bus, pci_fun;
+	/* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */
+#endif
+	unsigned int tint;
+	unsigned short tshort;
+#endif
+
+	func_enter();
+	sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug);
+	if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) {
+		printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. "
+		        "Assuming -1.\n");
+		printk ("(%p)\n", &sx_debug);
+		sx_debug=-1;
+	}
+
+#ifdef CONFIG_PCI
+	if (pci_present ()) {
+#ifndef TWO_ZERO
+		while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 
+		                                PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, 
+			                              pdev))) {
+#else
+			for (i=0;i< SX_NBOARDS;i++) {
+				if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, 
+				                         PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i,
+					                       &pci_bus, &pci_fun)) break;
+#endif
+			/* Specialix has a whole bunch of cards with
+			   0x2000 as the device ID. They say its because
+			   the standard requires it. Stupid standard. */
+			/* It seems that reading a word doesn't work reliably on 2.0.
+			   Also, reading a non-aligned dword doesn't work. So we read the
+			   whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+			   ourselves */
+			/* I don't know why the define doesn't work, constant 0x2c does --REW */ 
+			pci_read_config_dword (pdev, 0x2c, &tint);
+			tshort = (tint >> 16) & 0xffff;
+			sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+			/* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d	(%x)\n", pdev, tint); */ 
+			if (tshort != 0x0200) {
+				sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n", 
+				            tshort);
+				continue;
+			}
+			board = &boards[found];
+
+			pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+			board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK;
+			board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN);
+			board->irq = get_irq (pdev);
+			board->flags &= ~SX_BOARD_TYPE;
+			board->flags |=  SX_PCI_BOARD;
+
+			sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d).\n", 
+			            tint, boards[found].base, board->irq);
+
+			if (probe_sx (board)) {
+				found++;
+				fix_sx_pci (pdev, board);
+			} else 
+				my_iounmap (board->hw_base, board->base);
+		}
+	}
+#endif
+
+	for (i=0;i<NR_SX_ADDRS;i++) {
+		board = &boards[found];
+		board->hw_base = sx_probe_addrs[i];
+		board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN);
+		board->flags &= ~SX_BOARD_TYPE;
+		board->flags |=	SX_ISA_BOARD;
+		board->irq = sx_irqmask?-1:0;
+
+		if (probe_sx (board)) {
+			found++;
+		} else {
+			my_iounmap (board->hw_base, board->base);
+		}
+	}
+
+	for (i=0;i<NR_SI_ADDRS;i++) {
+		board = &boards[found];
+		board->hw_base = si_probe_addrs[i];
+		board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
+		board->flags &= ~SX_BOARD_TYPE;
+		board->flags |=  SI_ISA_BOARD;
+		board->irq = sx_irqmask ?-1:0;
+
+		if (probe_si (board)) {
+			found++;
+		} else {
+			my_iounmap (board->hw_base, board->base);
+		}
+	}
+
+	if (found) {
+		printk (KERN_INFO "sx: total of %d boards detected.\n", found);
+
+		if (misc_register(&sx_fw_device) < 0) {
+			printk(KERN_ERR "SX: Unable to register firmware loader driver.\n");
+			return -EIO;
+		}
+	}
+
+	func_exit();
+	return found?0:-EIO;
+}
+
+
+
+void cleanup_module(void)
+{
+	int i; 
+	struct sx_board *board;
+
+	func_enter();
+	for (i = 0; i < SX_NBOARDS; i++) {
+		board = &boards[i];
+		if (board->flags & SX_BOARD_INITIALIZED) {
+			sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base);
+			/* The board should stop messing with us.
+			   (actually I mean the interrupt) */
+			sx_reset (board);
+			if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
+				free_irq (board->irq, board);
+
+			/* It is safe/allowed to del_timer a non-active timer */
+			del_timer (& board->timer);
+			my_iounmap (board->hw_base, board->base);
+		}
+	}
+	if (misc_deregister(&sx_fw_device) < 0) {
+		printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+	}
+	sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
+	if (sx_initialized)
+		sx_release_drivers ();
+
+	kfree (sx_ports);
+	kfree (sx_termios);
+	kfree (sx_termios_locked);
+	func_exit();
+}
+
+
+#ifdef DEBUG
+void my_hd (unsigned char *addr, int len)
+{
+	int i, j, ch;
+
+	for (i=0;i<len;i+=16) {
+		printk ("%08x ", (int) addr+i);
+		for (j=0;j<16;j++) {
+			printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+		}
+		for (j=0;j<16;j++) {
+			ch = addr[j+i];
+			printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+		}
+		printk ("\n");
+	}
+}
+#endif
+
+#ifdef MODULE
+#undef func_enter
+#undef func_exit
+
+#include "generic_serial.c"
+#endif
+
+
+/*
+ * Anybody who knows why this doesn't work for me, please tell me -- REW.
+ * Snatched from scsi.c (fixed one spelling error):
+ * Overrides for Emacs so that we follow Linus' tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/sx.h linux/drivers/char/sx.h
--- v2.3.12/linux/drivers/char/sx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sx.h	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,180 @@
+
+/*
+ *  sx.h
+ *
+ *  Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ *  SX serial driver.
+ *  -- Supports SI, XIO and SX host cards. 
+ *  -- Supports TAs, MTAs and SXDCs.
+ *
+ *  Version 1.3 -- March, 1999. 
+ * 
+ */
+
+#define SX_NBOARDS        4
+#define SX_PORTSPERBOARD 32
+#define SX_NPORTS        (SX_NBOARDS * SX_PORTSPERBOARD)
+
+#ifdef __KERNEL__
+
+#define SX_MAGIC 0x12345678
+
+struct sx_port {
+  struct gs_port          gs;
+  /*
+  struct tq_struct        tqueue;
+  struct tq_struct        tqueue_hangup;
+  */
+  struct wait_queue       *shutdown_wait;
+  int                     ch_base;
+  int                     c_dcd;
+  struct sx_board         *board;
+  int                     line;
+  int                     locks;
+};
+
+struct sx_board {
+  int magic;
+  unsigned int base;
+  unsigned int hw_base;
+  int port_base; /* Number of the first port */
+  struct sx_port *ports;
+  int nports;
+  int flags;
+  int irq;
+  int poll;
+  int ta_type;
+  struct timer_list       timer;
+  int                     locks;
+};
+
+struct vpd_prom {
+  unsigned short id;
+  char hwrev;
+  char hwass;
+  int uniqid;
+  char myear;
+  char mweek;
+  char hw_feature[5];
+  char oem_id;
+  char identifier[16];
+};
+
+#ifndef MOD_RS232DB25MALE
+#define MOD_RS232DB25MALE 0x0a
+#endif
+
+
+#define SX_BOARD_PRESENT     0x00000001
+#define SX_ISA_BOARD         0x00000002
+#define SX_PCI_BOARD         0x00000004
+#define SI_ISA_BOARD         0x00000008
+#define SX_BOARD_INITIALIZED 0x00000010
+#define SX_IRQ_ALLOCATED     0x00000020
+
+#define SX_BOARD_TYPE (SX_ISA_BOARD|SX_PCI_BOARD|SI_ISA_BOARD)
+
+#define IS_SX_BOARD(board) (board->flags & (SX_PCI_BOARD | SX_ISA_BOARD))
+#define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD)
+
+
+#define SERIAL_TYPE_NORMAL 1
+
+/* The SI processor clock is required to calculate the cc_int_count register
+   value for the SI cards. */
+#define SI_PROCESSOR_CLOCK 25000000
+
+
+/* port flags */
+/* Make sure these don't clash with gs flags or async flags */
+#define SX_RX_THROTTLE        0x0000001
+
+
+
+#define SX_PORT_TRANSMIT_LOCK  0
+#define SX_BOARD_INTR_LOCK     0
+
+
+
+/* Debug flags. Add these together to get more debug info. */
+
+#define SX_DEBUG_OPEN          0x00000001
+#define SX_DEBUG_SETTING       0x00000002
+#define SX_DEBUG_FLOW          0x00000004
+#define SX_DEBUG_MODEMSIGNALS  0x00000008
+#define SX_DEBUG_TERMIOS       0x00000010
+#define SX_DEBUG_TRANSMIT      0x00000020
+#define SX_DEBUG_RECEIVE       0x00000040
+#define SX_DEBUG_INTERRUPTS    0x00000080
+#define SX_DEBUG_PROBE         0x00000100
+#define SX_DEBUG_INIT          0x00000200
+#define SX_DEBUG_CLEANUP       0x00000400
+#define SX_DEBUG_CLOSE         0x00000800
+#define SX_DEBUG_FIRMWARE      0x00001000
+#define SX_DEBUG_MEMTEST       0x00002000
+
+#define SX_DEBUG_ALL           0xffffffff
+
+
+#define O_OTHER(tty)    \
+      ((O_OLCUC(tty))  ||\
+      (O_ONLCR(tty))   ||\
+      (O_OCRNL(tty))   ||\
+      (O_ONOCR(tty))   ||\
+      (O_ONLRET(tty))  ||\
+      (O_OFILL(tty))   ||\
+      (O_OFDEL(tty))   ||\
+      (O_NLDLY(tty))   ||\
+      (O_CRDLY(tty))   ||\
+      (O_TABDLY(tty))  ||\
+      (O_BSDLY(tty))   ||\
+      (O_VTDLY(tty))   ||\
+      (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty)    \
+      ((I_INLCR(tty))  ||\
+      (I_IGNCR(tty))   ||\
+      (I_ICRNL(tty))   ||\
+      (I_IUCLC(tty))   ||\
+      (L_ISIG(tty)))
+
+#define MOD_TA   (        TA>>4)
+#define MOD_MTA  (MTA_CD1400>>4)
+#define MOD_SXDC (      SXDC>>4)
+
+
+/* We copy the download code over to the card in chunks of ... bytes */
+#define SX_CHUNK_SIZE 128
+
+#endif /* __KERNEL__ */
+
+
+
+/* Specialix document 6210046-11 page 3 */
+#define SPX(X) (('S'<<24) | ('P' << 16) | (X))
+
+/* Specialix-Linux specific IOCTLS. */
+#define SPXL(X) (SPX(('L' << 8) | (X)))
+
+
+#define SXIO_SET_BOARD      SPXL(0x01)
+#define SXIO_GET_TYPE       SPXL(0x02)
+#define SXIO_DOWNLOAD       SPXL(0x03)
+#define SXIO_INIT           SPXL(0x04)
+#define SXIO_SETDEBUG       SPXL(0x05)
+#define SXIO_GETDEBUG       SPXL(0x06)
+#define SXIO_DO_RAMTEST     SPXL(0x07)
+#define SXIO_SETGSDEBUG     SPXL(0x08)
+#define SXIO_GETGSDEBUG     SPXL(0x09)
+
+
+#ifndef SXCTL_MISC_MINOR 
+/* Allow others to gather this into "major.h" or something like that */
+#define SXCTL_MISC_MINOR    167
+#endif
+
+#define SX_TYPE_SX          0x01
+#define SX_TYPE_SI          0x02
+
diff -u --recursive --new-file v2.3.12/linux/drivers/char/sxboards.h linux/drivers/char/sxboards.h
--- v2.3.12/linux/drivers/char/sxboards.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sxboards.h	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,181 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	SX/SI/XIO Board Hardware Definitions	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	16th March 1998				*/
+/*									*/
+/*	Version		:	3.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1998	*/
+/*									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the SX/SI/XIO board hardware	*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+3.0.0	16/03/98 NPV	Creation.
+
+*/
+
+#ifndef	_sxboards_h				/* If SXBOARDS.H not already defined */
+#define	_sxboards_h    1
+
+/*****************************************************************************
+*******************************                 ******************************
+*******************************   Board Types   ******************************
+*******************************                 ******************************
+*****************************************************************************/
+
+/* BUS types... */
+#define		BUS_ISA		0
+#define		BUS_MCA		1
+#define		BUS_EISA	2
+#define		BUS_PCI		3
+
+/* Board phases... */
+#define		SI1_Z280	1
+#define		SI2_Z280	2
+#define		SI3_T225	3
+
+/* Board types... */
+#define		CARD_TYPE(bus,phase)	(bus<<4|phase)
+#define		CARD_BUS(type)		((type>>4)&0xF)
+#define		CARD_PHASE(type)	(type&0xF)
+
+#define		TYPE_SI2_ISA		CARD_TYPE(BUS_ISA,SI2_Z280)
+#define		TYPE_SI2_EISA		CARD_TYPE(BUS_EISA,SI2_Z280)
+#define		TYPE_SI2_PCI		CARD_TYPE(BUS_PCI,SI2_Z280)
+
+#define		TYPE_SX_ISA		CARD_TYPE(BUS_ISA,SI3_T225)
+#define		TYPE_SX_PCI		CARD_TYPE(BUS_PCI,SI3_T225)
+
+/*****************************************************************************
+******************************                  ******************************
+******************************   Phase 2 Z280   ******************************
+******************************                  ******************************
+*****************************************************************************/
+
+/* ISA board details... */
+#define		SI2_ISA_WINDOW_LEN	0x8000		/* 32 Kbyte shared memory window */
+#define 	SI2_ISA_MEMORY_LEN	0x7FF8		/* Usable memory */
+#define		SI2_ISA_ADDR_LOW	0x0A0000	/* Lowest address = 640 Kbyte */
+#define		SI2_ISA_ADDR_HIGH	0xFF8000	/* Highest address = 16Mbyte - 32Kbyte */
+#define		SI2_ISA_ADDR_STEP	SI2_ISA_WINDOW_LEN/* ISA board address step */
+#define		SI2_ISA_IRQ_MASK	0x9800		/* IRQs 15,12,11 */
+
+/* ISA board, register definitions... */
+#define		SI2_ISA_ID_BASE		0x7FF8			/* READ:  Board ID string */
+#define		SI2_ISA_RESET		SI2_ISA_ID_BASE		/* WRITE: Host Reset */
+#define		SI2_ISA_IRQ11		(SI2_ISA_ID_BASE+1)	/* WRITE: Set IRQ11 */
+#define		SI2_ISA_IRQ12		(SI2_ISA_ID_BASE+2)	/* WRITE: Set IRQ12 */
+#define		SI2_ISA_IRQ15		(SI2_ISA_ID_BASE+3)	/* WRITE: Set IRQ15 */
+#define		SI2_ISA_IRQSET		(SI2_ISA_ID_BASE+4)	/* WRITE: Set Host Interrupt */
+#define		SI2_ISA_INTCLEAR	(SI2_ISA_ID_BASE+5)	/* WRITE: Enable Host Interrupt */
+
+#define		SI2_ISA_IRQ11_SET	0x10
+#define		SI2_ISA_IRQ11_CLEAR	0x00
+#define		SI2_ISA_IRQ12_SET	0x10
+#define		SI2_ISA_IRQ12_CLEAR	0x00
+#define		SI2_ISA_IRQ15_SET	0x10
+#define		SI2_ISA_IRQ15_CLEAR	0x00
+#define		SI2_ISA_INTCLEAR_SET	0x10
+#define		SI2_ISA_INTCLEAR_CLEAR	0x00
+#define		SI2_ISA_IRQSET_CLEAR	0x10
+#define		SI2_ISA_IRQSET_SET	0x00
+#define		SI2_ISA_RESET_SET	0x00
+#define		SI2_ISA_RESET_CLEAR	0x10
+
+/* PCI board details... */
+#define		SI2_PCI_WINDOW_LEN	0x100000	/* 1 Mbyte memory window */
+
+/* PCI board register definitions... */
+#define		SI2_PCI_SET_IRQ		0x40001		/* Set Host Interrupt  */
+#define		SI2_PCI_RESET		0xC0001		/* Host Reset */
+
+/*****************************************************************************
+******************************                  ******************************
+******************************   Phase 3 T225   ******************************
+******************************                  ******************************
+*****************************************************************************/
+
+/* General board details... */
+#define		SX_WINDOW_LEN		64*1024		/* 64 Kbyte memory window */
+
+/* ISA board details... */
+#define		SX_ISA_ADDR_LOW		0x0A0000	/* Lowest address = 640 Kbyte */
+#define		SX_ISA_ADDR_HIGH	0xFF8000	/* Highest address = 16Mbyte - 32Kbyte */
+#define		SX_ISA_ADDR_STEP	SX_WINDOW_LEN	/* ISA board address step */
+#define		SX_ISA_IRQ_MASK		0x9E00		/* IRQs 15,12,11,10,9 */
+
+/* Hardware register definitions... */
+#define		SX_EVENT_STATUS		0x7800		/* READ:  T225 Event Status */
+#define		SX_EVENT_STROBE		0x7800		/* WRITE: T225 Event Strobe */
+#define		SX_EVENT_ENABLE		0x7880		/* WRITE: T225 Event Enable */
+#define		SX_VPD_ROM		0x7C00		/* READ:  Vital Product Data ROM */
+#define		SX_CONFIG		0x7C00		/* WRITE: Host Configuration Register */
+#define		SX_IRQ_STATUS		0x7C80		/* READ:  Host Interrupt Status */
+#define		SX_SET_IRQ		0x7C80		/* WRITE: Set Host Interrupt */
+#define		SX_RESET_STATUS		0x7D00		/* READ:  Host Reset Status */
+#define		SX_RESET		0x7D00		/* WRITE: Host Reset */
+#define		SX_RESET_IRQ		0x7D80		/* WRITE: Reset Host Interrupt */
+
+/* SX_VPD_ROM definitions... */
+#define		SX_VPD_SLX_ID1		0x00
+#define		SX_VPD_SLX_ID2		0x01
+#define		SX_VPD_HW_REV		0x02
+#define		SX_VPD_HW_ASSEM		0x03
+#define		SX_VPD_UNIQUEID4	0x04
+#define		SX_VPD_UNIQUEID3	0x05
+#define		SX_VPD_UNIQUEID2	0x06
+#define		SX_VPD_UNIQUEID1	0x07
+#define		SX_VPD_MANU_YEAR	0x08
+#define		SX_VPD_MANU_WEEK	0x09
+#define		SX_VPD_IDENT		0x10
+#define		SX_VPD_IDENT_STRING	"JET HOST BY KEV#"
+
+/* SX unique identifiers... */
+#define		SX_UNIQUEID_MASK	0xF0
+#define		SX_ISA_UNIQUEID1	0x20
+#define		SX_PCI_UNIQUEID1	0x50
+
+/* SX_CONFIG definitions... */
+#define		SX_CONF_BUSEN		0x02		/* Enable T225 memory and I/O */
+#define		SX_CONF_HOSTIRQ		0x04		/* Enable board to host interrupt */
+
+/* SX bootstrap... */
+#define		SX_BOOTSTRAP		"\x28\x20\x21\x02\x60\x0a"
+#define		SX_BOOTSTRAP_SIZE	6
+#define		SX_BOOTSTRAP_ADDR	(0x8000-SX_BOOTSTRAP_SIZE)
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   EISA   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+#define		SI2_EISA_OFF	 	0x42
+#define		SI2_EISA_VAL	 	0x01
+
+/*****************************************************************************
+***********************************         **********************************
+***********************************   PCI   **********************************
+***********************************         **********************************
+*****************************************************************************/
+
+/* General definitions... */
+
+#define		SPX_VENDOR_ID		0x11CB		/* Assigned by the PCI SIG */
+#define		SPX_DEVICE_ID		0x4000		/* SI/XIO boards */
+#define		SPX_PLXDEVICE_ID	0x2000		/* SX boards */
+
+#define		SPX_SUB_VENDOR_ID	SPX_VENDOR_ID	/* Same as vendor id */
+#define		SI2_SUB_SYS_ID		0x400		/* Phase 2 (Z280) board */
+#define		SX_SUB_SYS_ID		0x200		/* Phase 3 (t225) board */
+
+#endif						/*_sxboards_h */
+
+/* End of SXBOARDS.H */
diff -u --recursive --new-file v2.3.12/linux/drivers/char/sxwindow.h linux/drivers/char/sxwindow.h
--- v2.3.12/linux/drivers/char/sxwindow.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sxwindow.h	Thu Aug  5 14:47:44 1999
@@ -0,0 +1,393 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	SX Shared Memory Window Structure	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	16th March 1998				*/
+/*									*/
+/*	Version		:	3.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1998	*/
+/*									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the SX/SI/XIO cards shared	*/
+/*				memory window structure:		*/
+/*					SXCARD				*/
+/*					SXMODULE			*/
+/*					SXCHANNEL			*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+3.0.0	16/03/98 NPV	Creation. (based on STRUCT.H)
+
+*/
+
+#ifndef	_sxwindow_h				/* If SXWINDOW.H not already defined */
+#define	_sxwindow_h    1
+
+/*****************************************************************************
+***************************                        ***************************
+***************************   Common Definitions   ***************************
+***************************                        ***************************
+*****************************************************************************/
+
+typedef	struct	_SXCARD		*PSXCARD;	/* SXCARD structure pointer */
+typedef	struct	_SXMODULE	*PMOD;		/* SXMODULE structure pointer */
+typedef	struct	_SXCHANNEL	*PCHAN;		/* SXCHANNEL structure pointer */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   SXCARD   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+typedef	struct	_SXCARD
+{
+	BYTE	cc_init_status;			/* 0x00 Initialisation status */
+	BYTE	cc_mem_size;			/* 0x01 Size of memory on card */
+	WORD	cc_int_count;			/* 0x02 Interrupt count */
+	WORD	cc_revision;			/* 0x04 Download code revision */
+	BYTE	cc_isr_count;			/* 0x06 Count when ISR is run */
+	BYTE	cc_main_count;			/* 0x07 Count when main loop is run */
+	WORD	cc_int_pending;			/* 0x08 Interrupt pending */
+	WORD	cc_poll_count;			/* 0x0A Count when poll is run */
+	BYTE	cc_int_set_count;		/* 0x0C Count when host interrupt is set */
+	BYTE	cc_rfu[0x80 - 0x0D];		/* 0x0D Pad structure to 128 bytes (0x80) */
+
+} SXCARD;
+
+/* SXCARD.cc_init_status definitions... */
+#define 	ADAPTERS_FOUND		(BYTE)0x01
+#define 	NO_ADAPTERS_FOUND	(BYTE)0xFF
+
+/* SXCARD.cc_mem_size definitions... */
+#define 	SX_MEMORY_SIZE		(BYTE)0x40
+
+/* SXCARD.cc_int_count definitions... */
+#define 	INT_COUNT_DEFAULT	100	/* Hz */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   SXMODULE   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+#define	TOP_POINTER(a)		((a)|0x8000)	/* Sets top bit of word */
+#define UNTOP_POINTER(a)	((a)&~0x8000)	/* Clears top bit of word */
+
+typedef	struct	_SXMODULE
+{
+	WORD	mc_next;			/* 0x00 Next module "pointer" (ORed with 0x8000) */
+	BYTE	mc_type;			/* 0x02 Type of TA in terms of number of channels */
+	BYTE	mc_mod_no;			/* 0x03 Module number on SI bus cable (0 closest to card) */
+	BYTE	mc_dtr;				/* 0x04 Private DTR copy (TA only) */
+	BYTE	mc_rfu1;			/* 0x05 Reserved */
+	WORD	mc_uart;			/* 0x06 UART base address for this module */
+	BYTE	mc_chip;			/* 0x08 Chip type / number of ports */
+	BYTE	mc_current_uart;		/* 0x09 Current uart selected for this module */
+#ifdef	DOWNLOAD
+	PCHAN	mc_chan_pointer[8];		/* 0x0A Pointer to each channel structure */
+#else
+	WORD	mc_chan_pointer[8];		/* 0x0A Define as WORD if not compiling into download */
+#endif
+	WORD	mc_rfu2;			/* 0x1A Reserved */
+	BYTE	mc_opens1;			/* 0x1C Number of open ports on first four ports on MTA/SXDC */
+	BYTE	mc_opens2;			/* 0x1D Number of open ports on second four ports on MTA/SXDC */
+	BYTE	mc_mods;			/* 0x1E Types of connector module attached to MTA/SXDC */
+	BYTE	mc_rev1;			/* 0x1F Revision of first CD1400 on MTA/SXDC */
+	BYTE	mc_rev2;			/* 0x20 Revision of second CD1400 on MTA/SXDC */
+	BYTE	mc_mtaasic_rev;			/* 0x21 Revision of MTA ASIC 1..4 -> A, B, C, D */
+	BYTE	mc_rfu3[0x100 - 0x22];		/* 0x22 Pad structure to 256 bytes (0x100) */
+
+} SXMODULE;
+
+/* SXMODULE.mc_type definitions... */
+#define		FOUR_PORTS	(BYTE)4
+#define 	EIGHT_PORTS	(BYTE)8
+
+/* SXMODULE.mc_chip definitions... */
+#define 	CHIP_MASK	0xF0
+#define		TA		(BYTE)0
+#define 	TA4		(TA | FOUR_PORTS)
+#define 	TA8		(TA | EIGHT_PORTS)
+#define		TA4_ASIC	(BYTE)0x0A
+#define		TA8_ASIC	(BYTE)0x0B
+#define 	MTA_CD1400	(BYTE)0x28
+#define 	SXDC		(BYTE)0x48
+
+/* SXMODULE.mc_mods definitions... */
+#define		MOD_RS232DB25	0x00		/* RS232 DB25 (socket/plug) */
+#define		MOD_RS232RJ45	0x01		/* RS232 RJ45 (shielded/opto-isolated) */
+#define		MOD_RESERVED_2	0x02		/* Reserved (RS485) */
+#define		MOD_RS422DB25	0x03		/* RS422 DB25 Socket */
+#define		MOD_RESERVED_4	0x04		/* Reserved */
+#define		MOD_PARALLEL	0x05		/* Parallel */
+#define		MOD_RESERVED_6	0x06		/* Reserved (RS423) */
+#define		MOD_RESERVED_7	0x07		/* Reserved */
+#define		MOD_2_RS232DB25	0x08		/* Rev 2.0 RS232 DB25 (socket/plug) */
+#define		MOD_2_RS232RJ45	0x09		/* Rev 2.0 RS232 RJ45 */
+#define		MOD_RESERVED_A	0x0A		/* Rev 2.0 Reserved */
+#define		MOD_2_RS422DB25	0x0B		/* Rev 2.0 RS422 DB25 */
+#define		MOD_RESERVED_C	0x0C		/* Rev 2.0 Reserved */
+#define		MOD_2_PARALLEL	0x0D		/* Rev 2.0 Parallel */
+#define		MOD_RESERVED_E	0x0E		/* Rev 2.0 Reserved */
+#define		MOD_BLANK	0x0F		/* Blank Panel */
+
+/*****************************************************************************
+********************************               *******************************
+********************************   SXCHANNEL   *******************************
+********************************               *******************************
+*****************************************************************************/
+
+#define		TX_BUFF_OFFSET		0x60	/* Transmit buffer offset in channel structure */
+#define		BUFF_POINTER(a)		(((a)+TX_BUFF_OFFSET)|0x8000)
+#define		UNBUFF_POINTER(a)	(jet_channel*)(((a)&~0x8000)-TX_BUFF_OFFSET) 
+#define 	BUFFER_SIZE		256
+#define 	HIGH_WATER		((BUFFER_SIZE / 4) * 3)
+#define 	LOW_WATER		(BUFFER_SIZE / 4)
+
+typedef	struct	_SXCHANNEL
+{
+	WORD	next_item;			/* 0x00 Offset from window base of next channels hi_txbuf (ORred with 0x8000) */
+	WORD 	addr_uart;			/* 0x02 INTERNAL pointer to uart address. Includes FASTPATH bit */
+	WORD	module;				/* 0x04 Offset from window base of parent SXMODULE structure */
+	BYTE 	type;				/* 0x06 Chip type / number of ports (copy of mc_chip) */
+	BYTE	chan_number;			/* 0x07 Channel number on the TA/MTA/SXDC */
+	WORD	xc_status;			/* 0x08 Flow control and I/O status */
+	BYTE	hi_rxipos;			/* 0x0A Receive buffer input index */
+	BYTE	hi_rxopos;			/* 0x0B Receive buffer output index */
+	BYTE	hi_txopos;			/* 0x0C Transmit buffer output index */
+	BYTE	hi_txipos;			/* 0x0D Transmit buffer input index */
+	BYTE	hi_hstat;			/* 0x0E Command register */
+	BYTE	dtr_bit;			/* 0x0F INTERNAL DTR control byte (TA only) */
+	BYTE	txon;				/* 0x10 INTERNAL copy of hi_txon */
+	BYTE	txoff;				/* 0x11 INTERNAL copy of hi_txoff */
+	BYTE	rxon;				/* 0x12 INTERNAL copy of hi_rxon */
+	BYTE	rxoff;				/* 0x13 INTERNAL copy of hi_rxoff */
+	BYTE	hi_mr1;				/* 0x14 Mode Register 1 (databits,parity,RTS rx flow)*/
+	BYTE	hi_mr2;				/* 0x15 Mode Register 2 (stopbits,local,CTS tx flow)*/
+	BYTE	hi_csr;				/* 0x16 Clock Select Register (baud rate) */
+	BYTE	hi_op;				/* 0x17 Modem Output Signal */
+	BYTE	hi_ip;				/* 0x18 Modem Input Signal */
+	BYTE	hi_state;			/* 0x19 Channel status */
+	BYTE	hi_prtcl;			/* 0x1A Channel protocol (flow control) */
+	BYTE	hi_txon;			/* 0x1B Transmit XON character */
+	BYTE	hi_txoff;			/* 0x1C Transmit XOFF character */
+	BYTE	hi_rxon;			/* 0x1D Receive XON character */
+	BYTE	hi_rxoff;			/* 0x1E Receive XOFF character */
+	BYTE	close_prev;			/* 0x1F INTERNAL channel previously closed flag */
+	BYTE	hi_break;			/* 0x20 Break and error control */
+	BYTE	break_state;			/* 0x21 INTERNAL copy of hi_break */
+	BYTE	hi_mask;			/* 0x22 Mask for received data */
+	BYTE	mask;				/* 0x23 INTERNAL copy of hi_mask */
+	BYTE	mod_type;			/* 0x24 MTA/SXDC hardware module type */
+	BYTE	ccr_state;			/* 0x25 INTERNAL MTA/SXDC state of CCR register */
+	BYTE	ip_mask;			/* 0x26 Input handshake mask */
+	BYTE	hi_parallel;			/* 0x27 Parallel port flag */
+	BYTE	par_error;			/* 0x28 Error code for parallel loopback test */
+	BYTE	any_sent;			/* 0x29 INTERNAL data sent flag */
+	BYTE	asic_txfifo_size;		/* 0x2A INTERNAL SXDC transmit FIFO size */
+	BYTE	rfu1[2];			/* 0x2B Reserved */
+	BYTE	csr;				/* 0x2D INTERNAL copy of hi_csr */
+#ifdef	DOWNLOAD
+	PCHAN	nextp;				/* 0x2E Offset from window base of next channel structure */
+#else
+	WORD	nextp;				/* 0x2E Define as WORD if not compiling into download */
+#endif
+	BYTE	prtcl;				/* 0x30 INTERNAL copy of hi_prtcl */
+	BYTE	mr1;				/* 0x31 INTERNAL copy of hi_mr1 */
+	BYTE	mr2;				/* 0x32 INTERNAL copy of hi_mr2 */
+	BYTE	hi_txbaud;			/* 0x33 Extended transmit baud rate (SXDC only if((hi_csr&0x0F)==0x0F) */
+	BYTE	hi_rxbaud;			/* 0x34 Extended receive baud rate  (SXDC only if((hi_csr&0xF0)==0xF0) */
+	BYTE	txbreak_state;			/* 0x35 INTERNAL MTA/SXDC transmit break state */
+	BYTE	txbaud;				/* 0x36 INTERNAL copy of hi_txbaud */
+	BYTE	rxbaud;				/* 0x37 INTERNAL copy of hi_rxbaud */
+	WORD	err_framing;			/* 0x38 Count of receive framing errors */
+	WORD	err_parity;			/* 0x3A Count of receive parity errors */
+	WORD	err_overrun;			/* 0x3C Count of receive overrun errors */
+	WORD	err_overflow;			/* 0x3E Count of receive buffer overflow errors */
+	BYTE	rfu2[TX_BUFF_OFFSET - 0x40];	/* 0x40 Reserved until hi_txbuf */
+	BYTE	hi_txbuf[BUFFER_SIZE];		/* 0x060 Transmit buffer */
+	BYTE	hi_rxbuf[BUFFER_SIZE];		/* 0x160 Receive buffer */
+	BYTE	rfu3[0x300 - 0x260];		/* 0x260 Reserved until 768 bytes (0x300) */
+
+} SXCHANNEL;
+
+/* SXCHANNEL.addr_uart definitions... */
+#define		FASTPATH	0x1000		/* Set to indicate fast rx/tx processing (TA only) */
+
+/* SXCHANNEL.xc_status definitions... */
+#define		X_TANY		0x0001		/* XON is any character (TA only) */
+#define		X_TION		0x0001		/* Tx interrupts on (MTA only) */
+#define		X_TXEN		0x0002		/* Tx XON/XOFF enabled (TA only) */
+#define		X_RTSEN		0x0002		/* RTS FLOW enabled (MTA only) */
+#define		X_TXRC		0x0004		/* XOFF received (TA only) */
+#define		X_RTSLOW	0x0004		/* RTS dropped (MTA only) */
+#define		X_RXEN		0x0008		/* Rx XON/XOFF enabled */
+#define		X_ANYXO		0x0010		/* XOFF pending/sent or RTS dropped */
+#define		X_RXSE		0x0020		/* Rx XOFF sent */
+#define		X_NPEND		0x0040		/* Rx XON pending or XOFF pending */
+#define		X_FPEND		0x0080		/* Rx XOFF pending */
+#define		C_CRSE		0x0100		/* Carriage return sent (TA only) */
+#define		C_TEMR		0x0100		/* Tx empty requested (MTA only) */
+#define		C_TEMA		0x0200		/* Tx empty acked (MTA only) */
+#define		C_ANYP		0x0200		/* Any protocol bar tx XON/XOFF (TA only) */
+#define		C_EN		0x0400		/* Cooking enabled (on MTA means port is also || */
+#define		C_HIGH		0x0800		/* Buffer previously hit high water */
+#define		C_CTSEN		0x1000		/* CTS automatic flow-control enabled */
+#define		C_DCDEN		0x2000		/* DCD/DTR checking enabled */
+#define		C_BREAK		0x4000		/* Break detected */
+#define		C_RTSEN		0x8000		/* RTS automatic flow control enabled (MTA only) */
+#define		C_PARITY	0x8000		/* Parity checking enabled (TA only) */
+
+/* SXCHANNEL.hi_hstat definitions... */
+#define		HS_IDLE_OPEN	0x00		/* Channel open state */
+#define		HS_LOPEN	0x02		/* Local open command (no modem monitoring) */
+#define		HS_MOPEN	0x04		/* Modem open command (wait for DCD signal) */
+#define		HS_IDLE_MPEND	0x06		/* Waiting for DCD signal state */
+#define		HS_CONFIG	0x08		/* Configuration command */
+#define		HS_CLOSE	0x0A		/* Close command */
+#define		HS_START	0x0C		/* Start transmit break command */
+#define		HS_STOP		0x0E		/* Stop transmit break command */
+#define		HS_IDLE_CLOSED	0x10		/* Closed channel state */
+#define		HS_IDLE_BREAK	0x12		/* Transmit break state */
+#define		HS_FORCE_CLOSED	0x14		/* Force close command */
+#define		HS_RESUME	0x16		/* Clear pending XOFF command */
+#define		HS_WFLUSH	0x18		/* Flush transmit buffer command */
+#define		HS_RFLUSH	0x1A		/* Flush receive buffer command */
+#define		HS_SUSPEND	0x1C		/* Suspend output command (like XOFF received) */
+#define		PARALLEL	0x1E		/* Parallel port loopback test command (Diagnostics Only) */
+#define		ENABLE_RX_INTS	0x20		/* Enable receive interrupts command (Diagnostics Only) */
+#define		ENABLE_TX_INTS	0x22		/* Enable transmit interrupts command (Diagnostics Only) */
+#define		ENABLE_MDM_INTS	0x24		/* Enable modem interrupts command (Diagnostics Only) */
+#define		DISABLE_INTS	0x26		/* Disable interrupts command (Diagnostics Only) */
+
+/* SXCHANNEL.hi_mr1 definitions... */
+#define		MR1_BITS	0x03		/* Data bits mask */
+#define		MR1_5_BITS	0x00		/* 5 data bits */
+#define		MR1_6_BITS	0x01		/* 6 data bits */
+#define		MR1_7_BITS	0x02		/* 7 data bits */
+#define		MR1_8_BITS	0x03		/* 8 data bits */
+#define		MR1_PARITY	0x1C		/* Parity mask */
+#define		MR1_ODD		0x04		/* Odd parity */
+#define		MR1_EVEN	0x00		/* Even parity */
+#define		MR1_WITH	0x00		/* Parity enabled */
+#define		MR1_FORCE	0x08		/* Force parity */
+#define		MR1_NONE	0x10		/* No parity */
+#define		MR1_NOPARITY	MR1_NONE		/* No parity */
+#define		MR1_ODDPARITY	(MR1_WITH|MR1_ODD)	/* Odd parity */
+#define		MR1_EVENPARITY	(MR1_WITH|MR1_EVEN)	/* Even parity */
+#define		MR1_MARKPARITY	(MR1_FORCE|MR1_ODD)	/* Mark parity */
+#define		MR1_SPACEPARITY	(MR1_FORCE|MR1_EVEN)	/* Space parity */
+#define		MR1_RTS_RXFLOW	0x80		/* RTS receive flow control */
+
+/* SXCHANNEL.hi_mr2 definitions... */
+#define		MR2_STOP	0x0F		/* Stop bits mask */
+#define		MR2_1_STOP	0x07		/* 1 stop bit */
+#define		MR2_2_STOP	0x0F		/* 2 stop bits */
+#define		MR2_CTS_TXFLOW	0x10		/* CTS transmit flow control */
+#define		MR2_RTS_TOGGLE	0x20		/* RTS toggle on transmit */
+#define		MR2_NORMAL	0x00		/* Normal mode */
+#define		MR2_AUTO	0x40		/* Auto-echo mode (TA only) */
+#define		MR2_LOCAL	0x80		/* Local echo mode */
+#define		MR2_REMOTE	0xC0		/* Remote echo mode (TA only) */
+
+/* SXCHANNEL.hi_csr definitions... */
+#define		CSR_75		0x0		/*    75 baud */
+#define		CSR_110		0x1		/*   110 baud (TA), 115200 (MTA/SXDC) */
+#define		CSR_38400	0x2		/* 38400 baud */
+#define		CSR_150		0x3		/*   150 baud */
+#define		CSR_300		0x4		/*   300 baud */
+#define		CSR_600		0x5		/*   600 baud */
+#define		CSR_1200	0x6		/*  1200 baud */
+#define		CSR_2000	0x7		/*  2000 baud */
+#define		CSR_2400	0x8		/*  2400 baud */
+#define		CSR_4800	0x9		/*  4800 baud */
+#define		CSR_1800	0xA		/*  1800 baud */
+#define		CSR_9600	0xB		/*  9600 baud */
+#define		CSR_19200	0xC		/* 19200 baud */
+#define		CSR_57600	0xD		/* 57600 baud */
+#define		CSR_EXTBAUD	0xF		/* Extended baud rate (hi_txbaud/hi_rxbaud) */
+
+/* SXCHANNEL.hi_op definitions... */
+#define		OP_RTS		0x01		/* RTS modem output signal */
+#define		OP_DTR		0x02		/* DTR modem output signal */
+
+/* SXCHANNEL.hi_ip definitions... */
+#define		IP_CTS		0x02		/* CTS modem input signal */
+#define		IP_DCD		0x04		/* DCD modem input signal */
+#define		IP_DSR		0x20		/* DTR modem input signal */
+#define		IP_RI		0x40		/* RI modem input signal */
+
+/* SXCHANNEL.hi_state definitions... */
+#define		ST_BREAK	0x01		/* Break received (clear with config) */
+#define		ST_DCD		0x02		/* DCD signal changed state */
+
+/* SXCHANNEL.hi_prtcl definitions... */
+#define		SP_TANY		0x01		/* Transmit XON/XANY (if SP_TXEN enabled) */
+#define		SP_TXEN		0x02		/* Transmit XON/XOFF flow control */
+#define		SP_CEN		0x04		/* Cooking enabled */
+#define		SP_RXEN		0x08		/* Rx XON/XOFF enabled */
+#define		SP_DCEN		0x20		/* DCD / DTR check */
+#define		SP_DTR_RXFLOW	0x40		/* DTR receive flow control */
+#define		SP_PAEN		0x80		/* Parity checking enabled */
+
+/* SXCHANNEL.hi_break definitions... */
+#define		BR_IGN		0x01		/* Ignore any received breaks */
+#define		BR_INT		0x02		/* Interrupt on received break */
+#define		BR_PARMRK	0x04		/* Enable parmrk parity error processing */
+#define		BR_PARIGN	0x08		/* Ignore chars with parity errors */
+#define 	BR_ERRINT	0x80		/* Treat parity/framing/overrun errors as exceptions */
+
+/* SXCHANNEL.par_error definitions.. */
+#define		DIAG_IRQ_RX	0x01		/* Indicate serial receive interrupt (diags only) */
+#define		DIAG_IRQ_TX	0x02		/* Indicate serial transmit interrupt (diags only) */
+#define		DIAG_IRQ_MD	0x04		/* Indicate serial modem interrupt (diags only) */
+
+/* SXCHANNEL.hi_txbaud/hi_rxbaud definitions... (SXDC only) */
+#define		BAUD_75		0x00		/*     75 baud */
+#define		BAUD_115200	0x01		/* 115200 baud */
+#define		BAUD_38400	0x02		/*  38400 baud */
+#define		BAUD_150	0x03		/*    150 baud */
+#define		BAUD_300	0x04		/*    300 baud */
+#define		BAUD_600	0x05		/*    600 baud */
+#define		BAUD_1200	0x06		/*   1200 baud */
+#define		BAUD_2000	0x07		/*   2000 baud */
+#define		BAUD_2400	0x08		/*   2400 baud */
+#define		BAUD_4800	0x09		/*   4800 baud */
+#define		BAUD_1800	0x0A		/*   1800 baud */
+#define		BAUD_9600	0x0B		/*   9600 baud */
+#define		BAUD_19200	0x0C		/*  19200 baud */
+#define		BAUD_57600	0x0D		/*  57600 baud */
+#define		BAUD_230400	0x0E		/* 230400 baud */
+#define		BAUD_460800	0x0F		/* 460800 baud */
+#define		BAUD_921600	0x10		/* 921600 baud */
+#define		BAUD_50		0x11    	/*     50 baud */
+#define		BAUD_110	0x12		/*    110 baud */
+#define		BAUD_134_5	0x13		/*  134.5 baud */
+#define		BAUD_200	0x14		/*    200 baud */
+#define		BAUD_7200	0x15		/*   7200 baud */
+#define		BAUD_56000	0x16		/*  56000 baud */
+#define		BAUD_64000	0x17		/*  64000 baud */
+#define		BAUD_76800	0x18		/*  76800 baud */
+#define		BAUD_128000	0x19		/* 128000 baud */
+#define		BAUD_150000	0x1A		/* 150000 baud */
+#define		BAUD_14400	0x1B		/*  14400 baud */
+#define		BAUD_256000	0x1C		/* 256000 baud */
+#define		BAUD_28800	0x1D		/*  28800 baud */
+
+/* SXCHANNEL.txbreak_state definiions... */
+#define		TXBREAK_OFF	0		/* Not sending break */
+#define		TXBREAK_START	1		/* Begin sending break */
+#define		TXBREAK_START1	2		/* Begin sending break, part 1 */
+#define		TXBREAK_ON	3		/* Sending break */
+#define		TXBREAK_STOP	4		/* Stop sending break */
+#define		TXBREAK_STOP1	5		/* Stop sending break, part 1 */
+
+#endif						/* _sxwindow_h */
+
+/* End of SXWINDOW.H */
+
diff -u --recursive --new-file v2.3.12/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.12/linux/drivers/char/tty_io.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/tty_io.c	Thu Aug  5 14:47:44 1999
@@ -125,11 +125,15 @@
 int tty_ioctl(struct inode * inode, struct file * file,
 	      unsigned int cmd, unsigned long arg);
 static int tty_fasync(int fd, struct file * filp, int on);
+#ifdef CONFIG_SX
+extern int sx_init (void);
+#endif
 #ifdef CONFIG_8xx
 extern long console_8xx_init(long, long);
 extern int rs_8xx_init(void);
 #endif /* CONFIG_8xx */
 
+
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
@@ -2080,7 +2084,7 @@
  * Ok, now we can initialize the rest of the tty devices and can count
  * on memory allocations, interrupts etc..
  */
-__initfunc(int tty_init(void))
+int __init tty_init(void)
 {
 	if (sizeof(struct tty_struct) > PAGE_SIZE)
 		panic("size of tty structure > PAGE_SIZE!");
@@ -2177,6 +2181,9 @@
 #endif
 #ifdef CONFIG_SPECIALIX
 	specialix_init();
+#endif
+#ifdef CONFIG_SX
+	sx_init();
 #endif
 #ifdef CONFIG_8xx
         rs_8xx_init();
diff -u --recursive --new-file v2.3.12/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.3.12/linux/drivers/char/vc_screen.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/char/vc_screen.c	Thu Aug  5 14:34:02 1999
@@ -310,7 +310,7 @@
 	NULL		/* fsync */
 };
 
-__initfunc(int vcs_init(void))
+int __init vcs_init(void)
 {
 	int error;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/dio/dio.c linux/drivers/dio/dio.c
--- v2.3.12/linux/drivers/dio/dio.c	Sat Jun 13 13:14:31 1998
+++ linux/drivers/dio/dio.c	Thu Aug  5 14:34:02 1999
@@ -112,7 +112,7 @@
 
 static struct dioboard *blist = NULL;
 
-__initfunc(static int dio_find_slow(int deviceid))
+static int __init dio_find_slow(int deviceid)
 {
 	/* Called to find a DIO device before the full bus scan has run.  Basically
 	   only used by the console driver.  */
@@ -151,7 +151,7 @@
 /* This is the function that scans the DIO space and works out what
  * hardware is actually present.
  */
-__initfunc(void dio_init(void))
+void __init dio_init(void)
 {
         int scode;
         struct dioboard *b, *bprev = NULL;
diff -u --recursive --new-file v2.3.12/linux/drivers/fc4/soc.c linux/drivers/fc4/soc.c
--- v2.3.12/linux/drivers/fc4/soc.c	Fri Mar 26 13:57:41 1999
+++ linux/drivers/fc4/soc.c	Thu Aug  5 14:34:02 1999
@@ -672,7 +672,7 @@
 }
 
 #ifndef MODULE
-__initfunc(int soc_probe(void))
+int __init soc_probe(void)
 #else
 int init_module(void)
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/fc4/socal.c linux/drivers/fc4/socal.c
--- v2.3.12/linux/drivers/fc4/socal.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/fc4/socal.c	Thu Aug  5 14:34:02 1999
@@ -798,7 +798,7 @@
 }
 
 #ifndef MODULE
-__initfunc(int socal_probe(void))
+int __init socal_probe(void)
 #else
 int init_module(void)
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/Makefile linux/drivers/i2o/Makefile
--- v2.3.12/linux/drivers/i2o/Makefile	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/Makefile	Thu Aug  5 15:04:52 1999
@@ -27,7 +27,7 @@
 L_OBJS += i2o_pci.o
 else
   ifeq ($(CONFIG_I2O_PCI),m)
-  M_OBJS += i2o_pci.o
+  MX_OBJS += i2o_pci.o
   endif
 endif
 
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.12/linux/drivers/i2o/i2o_block.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_block.c	Thu Aug  5 15:04:52 1999
@@ -323,7 +323,8 @@
 {
 	i2o_block_reply,
 	"I2O Block OSM",
-	0
+	0,
+	I2O_CLASS_RANDOM_BLOCK_STORAGE
 };
 
 
@@ -576,15 +577,6 @@
 }
 
 /*
- *	Issue UTIL_CLAIM messages
- */
- 
-static int i2ob_claim_device(struct i2ob_device *dev, int onoff)
-{
-	return i2o_issue_claim(dev->controller, dev->tid, i2ob_context, onoff, &dev->done_flag);
-}
-
-/*
  *	Close the block device down
  */
  
@@ -625,10 +617,10 @@
 		i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2);
 	
 		/*
-                 * Now unclaim the device.
-                 */
-                if (i2ob_claim_device(dev, 0)<0)
-                        printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
+ 		 * Now unclaim the device.
+		 */
+		if (i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0)
+			printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
 
 	}
 	MOD_DEC_USE_COUNT;
@@ -657,7 +649,7 @@
 		int *query_done;
 		
 		
-		if(i2ob_claim_device(dev, 1)<0)
+		if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY)<0)
 		{
 			dev->refcnt--;
 			return -EBUSY;
@@ -809,36 +801,35 @@
 			if(unit<MAX_I2OB<<4)
 			{
  				/*
-                                 * Get the device and fill in the
-                                 * Tid and controller.
-                                 */
-                                struct i2ob_device *dev=&i2ob_dev[unit];
-       				dev->i2odev = d; 
+				 * Get the device and fill in the
+				 * Tid and controller.
+				 */
+				struct i2ob_device *dev=&i2ob_dev[unit];
+				dev->i2odev = d; 
 				dev->controller = c;
-                                dev->tid = d->id;
+				dev->tid = d->id;
  
-                                /*
-                                 * Insure the device can be claimed
-                                 * before installing it.
-                                 */
-                                if(i2ob_claim_device(dev, 1)==0)
-                                {
-                                        printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit);
-                                        i2ob_install_device(c,d,unit);
+				/*
+				 * Insure the device can be claimed
+				 * before installing it.
+				 */
+				if(i2o_claim_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY )==0)
+				{
+					printk(KERN_INFO "Claimed Dev %p Tid %d Unit %d\n",dev,dev->tid,unit);
+					i2ob_install_device(c,d,unit);
                                         unit+=16;
  
-                                        /*
-                                         * Now that the device has been
-                                         * installed, unclaim it so that
-                                         * it can be claimed by either
-                                         * the block or scsi driver.
-                                         */
-                                        if (i2ob_claim_device(dev, 0)<0)
-                                                printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid);
- 
-                                }
-                                else
-                                        printk(KERN_INFO "TID %d not claimed\n",dev->tid);
+					/*
+					 * Now that the device has been
+					 * installed, unclaim it so that
+					 * it can be claimed by either
+					 * the block or scsi driver.
+					 */
+					if(i2o_release_device(dev->i2odev, &i2o_block_handler, I2O_CLAIM_PRIMARY))
+						printk(KERN_INFO "Could not unclaim Dev %p Tid %d\n",dev,dev->tid);
+				}
+				else
+					printk(KERN_INFO "TID %d not claimed\n",dev->tid);
 			}
 			else
 			{
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.12/linux/drivers/i2o/i2o_config.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_config.c	Thu Aug  5 15:04:52 1999
@@ -75,7 +75,8 @@
 {
 	i2o_cfg_reply,
 	"Configuration",
-	0
+	0,
+	0xffffffff	// All classes
 };
 
 static long long cfg_llseek(struct file *file, long long offset, int origin)
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.12/linux/drivers/i2o/i2o_core.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_core.c	Thu Aug  5 15:04:52 1999
@@ -14,15 +14,20 @@
  *	Red Creek RCPCI45 adapter driver by Red Creek Communications
  *
  *	Fixes by Philipp Rumpf
- *		 Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *		      Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
  *	         Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *				Deepak Saxena <deepak@plexity.net>
  */
- 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+
+#if defined(CONFIG_I2O_PCI) || defined (CONFIG_I2O_PCI_MODULE)
 #include <linux/i2o.h>
+#endif
+
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
@@ -32,6 +37,7 @@
 
 #include "i2o_lan.h"
 
+#define DRIVERDEBUG
 
 /*
  *	Size of the I2O module table
@@ -46,6 +52,32 @@
 extern int i2o_online_controller(struct i2o_controller *c);
 static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
 			   struct i2o_message *);
+static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
+static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
+static void i2o_dump_message(u32 *);
+
+#ifdef MODULE
+/* 
+ * Function table to send to bus specific layers
+ * See <include/linux/i2o.h> for explanation of this
+ */
+static struct i2o_core_func_table i2o_core_functions =
+{
+	i2o_install_controller,
+	i2o_activate_controller,
+	i2o_find_controller,
+	i2o_unlock_controller,
+	i2o_run_queue,
+	i2o_delete_controller
+};
+
+#ifdef CONFIG_I2O_PCI_MODULE
+extern int i2o_pci_core_attach(struct i2o_core_func_table *);
+extern void i2o_pci_core_detach(void);
+#endif /* CONFIG_I2O_PCI_MODULE */
+
+#endif /* MODULE */
+
 
 /* Message handler */ 
 static struct i2o_handler i2o_core_handler =
@@ -133,12 +165,19 @@
  
 int i2o_install_device(struct i2o_controller *c, struct i2o_device *d)
 {
+	int i;
+
 	spin_lock(&i2o_configuration_lock);
 	d->controller=c;
 	d->owner=NULL;
 	d->next=c->devices;
 	c->devices=d;
 	*d->dev_name = 0;
+	d->owner = NULL;
+
+	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+		d->managers[i] = NULL;
+
 	spin_unlock(&i2o_configuration_lock);
 	return 0;
 }
@@ -247,9 +286,12 @@
 	while(*p)
 	{
 		if(*p!=c)
+		{
+			printk("Quiescing controller %p != %p\n", c, *p);
 			if(i2o_quiesce_controller(*p)<0)
 				printk(KERN_INFO "Unable to quiesce iop%d\n",
 				       (*p)->unit);
+		}
 		p=&((*p)->next);
 	}
 
@@ -308,11 +350,23 @@
 	
 
 /*
- *	Track if a device is being used by a driver
+ * Claim a device for use as either the primary user or just
+ * as a management/secondary user
  */
- 
-int i2o_claim_device(struct i2o_device *d, struct i2o_driver *r)
+int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
 {
+	/* Device already has a primary user or too many managers */
+	if((type == I2O_CLAIM_PRIMARY && d->owner) ||
+		(d->num_managers == I2O_MAX_MANAGERS))
+	{
+			return -EBUSY;
+	}
+
+	if(i2o_issue_claim(d->controller,d->id, h->context, 1, &reply_flag, type) < 0)
+	{
+		return -EBUSY;
+	}
+
 	spin_lock(&i2o_configuration_lock);
 	if(d->owner)
 	{
@@ -320,25 +374,92 @@
 		return -EBUSY;
 	}
 	atomic_inc(&d->controller->users);
-	d->owner=r;
+
+	if(type == I2O_CLAIM_PRIMARY)
+		d->owner=h;
+	else
+		i2o_add_management_user(d, h);
+
 	spin_unlock(&i2o_configuration_lock);
 	return 0;
 }
 
-int i2o_release_device(struct i2o_device *d)
+int i2o_release_device(struct i2o_device *d, struct i2o_handler *h, u32 type)
 {
+	int err = 0;
+
 	spin_lock(&i2o_configuration_lock);
-	if(d->owner==NULL)
+
+	/* Primary user */
+	if(type == I2O_CLAIM_PRIMARY)
 	{
+		if(d->owner != h)
+			err = -ENOENT;
+		else
+		{
+			if(i2o_issue_claim(d->controller,d->id, h->context, 0, &reply_flag, type) < 0)
+			{
+				err = -ENXIO;
+			}
+			else
+			{
+				d->owner = NULL;
+				atomic_dec(&d->controller->users);
+			}
+		}
+
 		spin_unlock(&i2o_configuration_lock);
-		return -EINVAL;
+		return err;
 	}
-	atomic_dec(&d->controller->users);
-	d->owner=NULL;
+
+	/* Management or other user */
+	if(i2o_remove_management_user(d, h))
+		err = -ENOENT;
+	else
+	{
+		atomic_dec(&d->controller->users);
+
+		if(i2o_issue_claim(d->controller,d->id, h->context, 0, 
+									&reply_flag, type) < 0)
+			err = -ENXIO;
+	}
+
 	spin_unlock(&i2o_configuration_lock);
+	return err;
+}
+
+int i2o_add_management_user(struct i2o_device *d, struct i2o_handler *h)
+{
+	int i;
+
+	if(d->num_managers == I2O_MAX_MANAGERS)
+		return 1;
+
+	for(i = 0; i < I2O_MAX_MANAGERS; i++)
+		if(!d->managers[i])
+			d->managers[i] = h;
+	
+	d->num_managers++;
+	
 	return 0;
 }
 
+int i2o_remove_management_user(struct i2o_device *d, struct i2o_handler *h)
+{
+	int i;
+
+	for(i=0; i < I2O_MAX_MANAGERS; i++)
+	{
+		if(d->managers[i] == h)
+		{
+			d->managers[i] = NULL;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
 /*
  *	This is called by the bus specific driver layer when an interrupt
  *	or poll of this card interface is desired.
@@ -363,7 +484,11 @@
 		if(i)
 			i->reply(i,c,m);
 		else
-			printk("Spurious reply\n");
+		{
+			printk("Spurious reply to handler %d\n", 
+				m->initiator_context&(MAX_I2O_MODULES-1));
+			i2o_dump_message((u32*)m);
+		}	
 	 	i2o_flush_reply(c,mv);
 		mb();
 	}
@@ -803,7 +928,8 @@
 	msg[2]=core_context;
 	msg[3]=(u32)&reply_flag;
 
-	return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 10);
+	/* Long timeout needed for quiesce if lots of devices */
+	return i2o_post_wait(c, ADAPTER_TID, msg, sizeof(msg), &reply_flag, 120);
 }
 
 
@@ -839,11 +965,15 @@
 	/* First stop external operations */
 	for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
 	{
-		if(i2o_quiesce_controller(iop)<0)
-			printk(KERN_INFO "Unable to quiesce iop%d\n",
-			       iop->unit);
-		else
-			printk(KERN_DEBUG "%s quiesced\n", iop->name);
+		/* Quiesce is rejected on hold state */
+		if(iop->status != ADAPTER_STATE_HOLD)
+		{
+			if(i2o_quiesce_controller(iop)<0)
+				printk(KERN_INFO "Unable to quiesce iop%d\n",
+				       iop->unit);
+			else
+				printk(KERN_DEBUG "%s quiesced\n", iop->name);
+		}
 	}
 
 	/* Then reset the IOP */
@@ -1398,7 +1528,7 @@
  *	Issue UTIL_CLAIM messages
  */
  
-int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag)
+int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag, u32 type)
 {
 	u32 msg[6];
 
@@ -1412,7 +1542,7 @@
 	
 	msg[2] = 0x80000000|context;
 	msg[3] = (u32)flag;
-	msg[4] = 0x01<<24;	/* Primary user */
+	msg[4] = type;
 	
 	return i2o_post_wait(c, tid, msg, 20, flag,2);
 }
@@ -1999,8 +2129,19 @@
 	return;
 }
 
+/* Used to dump a message to syslog during debugging */
+static void i2o_dump_message(u32 *msg)
+{
+#ifdef DRIVERDEBUG
+	int i;
+
+	printk(KERN_INFO "Dumping I2O message @ %p\n", msg);
+	for(i = 0; i < ((msg[0]>>16)&0xffff); i++)
+		printk(KERN_INFO "\tmsg[%d] = %#10x\n", i, msg[i]);
+#endif
+}
 
-#ifdef CONFIG_MODULE
+#ifdef MODULE
 
 EXPORT_SYMBOL(i2o_install_handler);
 EXPORT_SYMBOL(i2o_remove_handler);
@@ -2040,19 +2181,31 @@
 
 int init_module(void)
 {
-        if (i2o_install_handler(&i2o_core_handler) < 0)
-        {
-                printk(KERN_ERR "i2o_core: Unable to install core handler.\n");
-                return 0;
-        }
+	if (i2o_install_handler(&i2o_core_handler) < 0)
+	{
+		printk(KERN_ERR "i2o_core: Unable to install core handler.\n");
+		return 0;
+	}
 
-        core_context = i2o_core_handler.context;
+	core_context = i2o_core_handler.context;
 
-        return 0;
+	/*
+	 * Attach core to I2O PCI subsystem
+	 */
+#ifdef CONFIG_I2O_PCI_MODULE
+	if(i2o_pci_core_attach(&i2o_core_functions) < 0)
+		printk(KERN_INFO "No PCI I2O controllers found\n");
+#endif
+
+	return 0;
 }
 
 void cleanup_module(void)
 {
+#ifdef CONFIG_I2O_PCI_MODULE
+	i2o_pci_core_detach();
+#endif
+
 	i2o_remove_handler(&i2o_core_handler);
 }
 
@@ -2093,4 +2246,4 @@
 	return 0;
 }
 
-#endif
\ No newline at end of file
+#endif
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.12/linux/drivers/i2o/i2o_lan.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_lan.c	Thu Aug  5 15:04:52 1999
@@ -1,7 +1,7 @@
 /*
  * 	linux/drivers/i2o/i2o_lan.c
  *
- *    	I2O LAN CLASS OSM 	Prototyping, June 4th 1999
+ *    	I2O LAN CLASS OSM 	Prototyping, July 16th 1999
  *
  *	(C) Copyright 1999 	University of Helsinki,
  *				Department of Computer Science
@@ -15,17 +15,16 @@
  *
  * 	Authors: 	Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
  *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *			Deepak Saxena <deepak@plexity.net>
  *
  *	Tested:		in FDDI environment (using SysKonnect's DDM)
  *			in Ethernet environment (using Intel 82558 DDM proto)
  *
  *	TODO:		batch mode networking
- *			- this one assumes that we always get one packet 
- *			  in a bucket
  *			- we've not been able to test batch replies and 
  *			  batch receives
- *			- error checking / timeouts
- *			- code / test for other LAN classes
+ *			error checking / timeouts
+ *			code / test for other LAN classes
  */
 
 #include <linux/config.h>
@@ -39,6 +38,7 @@
 #include <linux/malloc.h>
 #include <linux/trdevice.h>
 #include <linux/init.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 
 #include <linux/errno.h>
@@ -48,7 +48,7 @@
 
 //#define DRIVERDEBUG
 #ifdef DRIVERDEBUG
-#define dprintk(s, args...) printk(s, ## args) 
+#define dprintk(s, args...) printk(s, ## args)
 #else
 #define dprintk(s, args...)
 #endif
@@ -64,17 +64,25 @@
 	u32 packet_tresh;		/* treshold for incoming skb's */	
 	struct fddi_statistics stats;   /* see also struct net_device_stats */ 
 	unsigned short (*type_trans)(struct sk_buff *, struct device *);
+	/* 
+	 * Due to way that interrupts can pile up, we need to keep track
+ 	 * of buckets ourselves.  Otherwise we'll end up flooding
+	 * the DDM with buckets.
+	 */
+	u32	bucket_count;
 };
 
 /* function prototypes */
 static int i2o_lan_receive_post(struct device *dev);
 static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m);
+static void i2o_lan_release_buckets(u32 *msg, struct i2o_lan_local *priv);
 
 /*
  * Module params
  */
-static u32 bucketpost = 64;
-static u32 bucketthresh = 8;
+static u32 bucketpost = I2O_BUCKET_COUNT;
+static u32 bucketthresh = I2O_BUCKET_THRESH;
+static u32 rx_copybreak = 200;
 
 static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, 
 			  struct i2o_message *m)
@@ -82,6 +90,15 @@
 	u32 *msg = (u32 *)m;
 	u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
 	struct device *dev = i2o_landevs[unit];
+	struct i2o_lan_local *priv; 
+
+	if(dev)
+		priv = (struct i2o_lan_local *)dev->priv;
+	else
+		priv = NULL;
+	
+	dprintk("Unit: %d Function: %#x\n",
+				unit, msg[1]>>24);
 
     	if (msg[0] & (1<<13)) // Fail bit is set
  	{
@@ -97,36 +114,41 @@
 		return;
 	}	
 
-#ifdef DRIVERDEBUG
-//	if (msg[4] >> 24) 	/* ReqStatus != SUCCESS */
-		i2o_report_status(KERN_INFO, "i2o_lan", msg);
+#ifndef DRIVERDEBUG
+	if (msg[4] >> 24) 	/* ReqStatus != SUCCESS */
 #endif
+		i2o_report_status(KERN_INFO, dev->name, msg);
 
 	switch (msg[1] >> 24) {
 	case LAN_RECEIVE_POST: 
-		if (dev->start) 
-			i2o_lan_receive_post_reply(dev,m);
-		else { 
-			// we are getting unused buckets back
-			u8 trl_count  = msg[3] & 0x000000FF; 	
-			struct i2o_bucket_descriptor *bucket =
-				(struct i2o_bucket_descriptor *)&msg[6];
-			do {	
-				dprintk("%s: Releasing unused bucket\n",dev->name);
-				dev_kfree_skb((struct sk_buff *)bucket->context);
-				bucket++;
-			} while (--trl_count);
-		}			
-	break;
+	{
+		if (dev->start)
+		{
+			if(!(msg[4]>>24))
+			{
+				i2o_lan_receive_post_reply(dev,m);
+				break;
+			}
+			else
+			{
+				// Something VERY wrong if this is happening
+				 printk( KERN_WARNING "i2olan: Device %s rejected bucket post\n", dev->name);
+				i2o_lan_release_buckets(msg,priv);
+			}
+		}
+		else
+		{
+			i2o_lan_release_buckets(msg,priv);	
+		}
+	
+		break;
+	}
 
 	case LAN_PACKET_SEND:
 	case LAN_SDU_SEND: 
 	{
 		u8 trl_count  = msg[3] & 0x000000FF; 	
 		
-		if (msg[4] >> 24) 	// ReqStatus != SUCCESS
-			i2o_report_status(KERN_WARNING, dev->name, msg);
-
 		do { 	// The HDM has handled the outgoing packet
 			dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]);
 			dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
@@ -135,29 +157,47 @@
 		
 		dev->tbusy = 0;
 		mark_bh(NET_BH); /* inform upper layers */
+	
+		break;	
 	}
-	break;	
 
 	default: 
 		if (msg[2] & 0x80000000)  // reply to a UtilParamsGet/Set
 		{	
-	       		int *flag = (int *)msg[3]; // flag for i2o_post_wait
+	   	int *flag = (int *)msg[3]; // flag for i2o_post_wait
 			if (msg[4] >> 24) // ReqStatus != SUCCESS
 			{
-				i2o_report_status(KERN_WARNING, dev->name, msg);
-	      		 	*flag = -(msg[4] & 0xFFFF); // DetailedStatus
-	      		}
-	      		else
-	      			*flag = I2O_POST_WAIT_OK;
+	     	 	*flag = -(msg[4] & 0xFFFF); // DetailedStatus
+	     	}
+	     	else
+	     		*flag = I2O_POST_WAIT_OK;
 		}
 	}
 }
 
+void i2o_lan_release_buckets(u32 *msg, struct i2o_lan_local *priv)
+{
+	u8 trl_count  = (u8)(msg[3] & 0x000000FF); 	
+   u32 *pskb = &msg[6];
+	
+	while (trl_count) 
+	{	
+		dprintk("%s: Releasing unused sk_buff %p\n",dev->name, 
+			(struct sk_buff*)(*pskb));
+		dev_kfree_skb((struct sk_buff*)(*pskb)); 
+		pskb++;
+		if(priv)
+			priv->bucket_count--;
+		trl_count--;
+	}
+}
+
 static struct i2o_handler i2o_lan_handler =
 {
 	i2o_lan_reply,
 	"I2O Lan OSM",
-	0		// context
+	0,		// context
+	I2O_CLASS_LAN
 };
 static int lan_context;
 
@@ -177,22 +217,25 @@
 		"msgsize = %d, buckets_remaining = %d\n", 
 		msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]);	
 #endif
-	dprintk(KERN_INFO "Buckets_remaining = %d\n",msg[5]);
+
+	dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d\n",
+		msg[5], priv->bucket_count);
 
 	do {
 		skb = (struct sk_buff *)(bucket->context);		
 		packet = (struct i2o_packet_info *)bucket->packet_info;	
+		priv->bucket_count--;
 #if 0
-		dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
+		dprintk(KERN)INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
 			packet->flags, packet->offset, packet->status, packet->len);
 #endif
-		if (packet->len < priv->packet_tresh) {
+		if (packet->len < rx_copybreak) {
 			newskb = (struct sk_buff *)
 					dev_alloc_skb(packet->len+2);	
 			if (newskb) {
 				skb_reserve(newskb,2);
 				memcpy(skb_put(newskb,packet->len), 
-				       skb->data, packet->len);
+			       skb->data, packet->len);
 				newskb->dev = dev;
 				newskb->protocol = priv->type_trans(newskb, dev);
 
@@ -200,10 +243,11 @@
 				dev_kfree_skb(skb); // FIXME: reuse this skb? 
 			}
 			else {
-				printk("Can't allocate skb.\n");
+				printk("I2OLAN-%s: Can't allocate skb.\n", dev->name);
 				return -ENOMEM;
 			}
 		} else {
+
 			skb_put(skb,packet->len);		
 			skb->dev  = dev;		
 			skb->protocol = priv->type_trans(skb, dev);
@@ -216,9 +260,18 @@
 		bucket++; // to next Packet Descriptor Block
 	} while (--trl_count);
 
-
-	if (msg[5] <= bucketthresh)  	// BucketsRemaining
+	if (priv->bucket_count <= bucketthresh) // BucketsRemaining
+	{
+		dprintk("Bucket_count = %d, ",priv->bucket_count);
 		i2o_lan_receive_post(dev);
+	}
+
+
+	if((msg[4]& 0x0000ffff) == 0x05) // I2O_LAN_RECEIVE_OVERRUN
+	{
+		printk("Bucket overrun! priv->bucketcount = %d\n",
+					priv->bucket_count);
+	}
 
 	return 0;
 }
@@ -267,6 +320,9 @@
 			if (skb == NULL)
 				return -ENOMEM;
 			skb_reserve(skb, 2);
+
+			priv->bucket_count++;
+
 			msg[4 + 3*i] = 0x51000000 | bucket_len;
 			msg[5 + 3*i] = (u32)skb;
 			msg[6 + 3*i] = virt_to_bus(skb->data);
@@ -279,6 +335,7 @@
 
 		total += bucket_count;
 	}
+
 	return 0;	
 }	
 
@@ -317,6 +374,7 @@
 	struct i2o_controller *iop = i2o_dev->controller;	
 	u32 msg[5];
 
+	dprintk( "%s: LAN SUSPEND MESSAGE\n", dev->name );
 	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
 	msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->id;
 	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
@@ -350,7 +408,7 @@
 	// enable batch mode, toggle automatically
 	val = 0x00000000;
 //	val = 0x00000001; // turn off batch mode
-	if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0003, 0,
+	if (i2o_set_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0003, 0,
 			&val, 4, &priv->reply_flag) <0)
 		printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n");
 	else
@@ -364,7 +422,7 @@
 	/* set LAN_OPERATION attributes */
 
 	val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit
-	if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0004, 2,
+	if (i2o_set_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0004, 2,
 		&val, 4, &priv->reply_flag) < 0)
 		printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n");
 	else
@@ -384,8 +442,10 @@
 	struct i2o_device *i2o_dev = priv->i2o_dev;	
 	struct i2o_controller *iop = i2o_dev->controller;
 
-	if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 1, 
+/*	if (i2o_issue_claim(iop, i2o_dev->id, priv->unit << 16 | lan_context, 1, 
 			    &priv->reply_flag) < 0)
+*/
+	if(i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY))
 	{
 		printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
 		return -EAGAIN;
@@ -424,8 +484,12 @@
 
 	i2o_lan_suspend(dev);
 
-	if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, 
+/*
+	if (i2o_issue_claim(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0, 
 			    &priv->reply_flag) < 0)
+*/
+
+	if(i2o_release_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY))
 		printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
 		       "(tid=%d)\n", dev->name, i2o_dev->id);
 
@@ -513,7 +577,6 @@
 	msg[6] = virt_to_bus(skb->data);
 
         i2o_post_message(iop,m);
-        
 	dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
 		dev->name, skb->len);
 
@@ -528,7 +591,7 @@
 	u64 val64[16];
 	u64 supported_group[4] = { 0, 0, 0, 0 };
 
-        if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, 
+        if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0100, -1, 
         		 val64, sizeof(val64), &priv->reply_flag) < 0)
         	dprintk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
 	else {
@@ -542,11 +605,11 @@
 		priv->stats.rx_dropped = val64[6];
 	}
 
-        i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0180, -1, 
+        i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0180, -1, 
         		&supported_group, sizeof(supported_group), &priv->reply_flag);
 
 	if (supported_group[2]) {
-        	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0183, -1, 
+        	if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0183, -1, 
         	 	val64, sizeof(val64), &priv->reply_flag) < 0)
         		dprintk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name);
 		else {
@@ -561,23 +624,24 @@
 	{
 		u64 supported_stats = 0;		
 
-        	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0200, -1, 
+        	if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0200, -1, 
         			 val64, sizeof(val64), &priv->reply_flag) < 0)
         		dprintk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name);
 		else {
-        		dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name);
+//        		dprintk("%s: LAN_802_3_HISTORICAL_STATS queried.\n",dev->name);
 	 		priv->stats.transmit_collision = val64[1] + val64[2];
 			priv->stats.rx_frame_errors    = val64[0];		
 			priv->stats.tx_carrier_errors  = val64[6];
 		}
-	
-        	i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0280, -1, 
-        			 &supported_stats, 8, &priv->reply_flag);
-        			
+
+        	if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0280, -1, 
+        			 &supported_stats, 8, &priv->reply_flag) < 0)
+        		dprintk("%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS\n", dev->name);
+        
         	if (supported_stats != 0) {
-        		if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0281, -1, 
+        		if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0281, -1, 
         				 val64, sizeof(val64), &priv->reply_flag) < 0)
-        			dprintk("%s: Unable to query LAN_OPTIONLA_802_3_HISTORICAL_STATS.\n",dev->name);
+        			dprintk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
 			else {
         			dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
 				if (supported_stats & 0x1)
@@ -586,18 +650,19 @@
 					priv->stats.tx_heartbeat_errors = val64[2];
 			}
 		}
+
 	}
 
 #ifdef CONFIG_TR
 	if (i2o_dev->subclass == I2O_LAN_TR)
 	{
-        	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0300, -1, 
+        	if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0300, -1, 
         			 val64, sizeof(val64), &priv->reply_flag) < 0)
         		dprintk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name);
 		else {
 			struct tr_statistics *stats = 
 					(struct tr_statistics *)&priv->stats;
-        		dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
+//        		dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
 
 			stats->line_errors		= val64[0];
 			stats->internal_errors		= val64[7];
@@ -617,11 +682,11 @@
 #ifdef CONFIG_FDDI
 	if (i2o_dev->subclass == I2O_LAN_FDDI)
 	{
-        	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0400, -1, 
+        	if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0400, -1, 
         			 val64, sizeof(val64), &priv->reply_flag) < 0)
         		dprintk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name);
 		else {
-        		dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
+//        		dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
 			priv->stats.smt_cf_state = val64[0];
 			memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN);
 			memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);			
@@ -654,15 +719,29 @@
 
 	dprintk(KERN_INFO "%s: Entered i2o_lan_set_multicast_list().\n", dev->name);
 
+if (dev==NULL)
+        printk("dev is NULL\n");
+else if (dev->priv==NULL)
+        printk("dev->priv is NULL\n");
+else if (priv->i2o_dev==NULL)
+        printk("i2o_dev is NULL\n");
+else if (i2o_dev->controller==NULL)
+	printk("iop is NULL\n");
+else {
+	printk("Everything seems to be OK in i2o_lan_set_multicast_list().\n");
+        printk("id = %d, unit = %d, lan_context = %d\n",
+        i2o_dev->id, priv->unit, lan_context);
+}  
+
 return;
 
 /* FIXME: Why does the next call kill the interrupt handler?
- * The same works fine in function lan_open(), and in i2o_proc.c
+ * The same piece of code works fine in function lan_open(), and in i2o_proc.c
  *
- *  *because its trying to sleep in an irq - this must be async - Alan
+ * *because its trying to sleep in an irq - this must be async - Alan
  */
 
-	if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, -1,
+	if (i2o_query_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0001, -1,
 			     &work32, sizeof(work32), &priv->reply_flag) < 0 ) 
 	{
 		printk(KERN_WARNING "i2o_lan: Unable to query "
@@ -705,11 +784,11 @@
 			mclist = mclist->next;
 		} 
 
-		if (i2o_clear_table(iop, i2o_dev->id, lan_context, 0x0002,
+		if (i2o_clear_table(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0002,
 				&priv->reply_flag) < 0 ) 
 			dprintk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
 
-		if (i2o_row_add_table(iop, i2o_dev->id, lan_context, 0x0002, -1,
+		if (i2o_row_add_table(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0002, -1,
 			work32, dev->mc_count*8, &priv->reply_flag) < 0)	
 			dprintk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
 	} 
@@ -719,7 +798,7 @@
 		dprintk(KERN_INFO "i2o_lan: Enabling unicast mode...\n");
         }
 
-	if (i2o_set_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3,
+	if (i2o_set_scalar(iop, i2o_dev->id, priv->unit << 16 | lan_context, 0x0001, 3,
 			&filter_mask, 4, &priv->reply_flag) <0)
 		printk(KERN_WARNING "i2o_lan: Unable to set MAC FilterMask.\n");
 
@@ -744,12 +823,14 @@
 		unregister_dev = unregister_netdev;
 		break;
 
+
 #ifdef CONFIG_ANYLAN
 	case I2O_LAN_100VG:
 		printk(KERN_ERR "i2o_lan: 100base VG not yet supported\n");
 		break;
 #endif
 
+
 #ifdef CONFIG_TR
 	case I2O_LAN_TR:
 		dev = init_trdev(NULL, sizeof(struct i2o_lan_local));
@@ -802,11 +883,18 @@
 	priv = (struct i2o_lan_local *)dev->priv;
 	priv->i2o_dev = i2o_dev;
 	priv->type_trans = type_trans;
-	
-        if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, lan_context,
-			     0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0)
+	priv->bucket_count = 0;
+
+	unit++;
+	i2o_landevs[unit] = dev;
+	priv->unit = unit;
+
+	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, 
+			priv->unit << 16 | lan_context,
+			0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0)
 	{
         	printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
+		unit--;
 		unregister_dev(dev);
 		kfree(dev);
       		return NULL;  
@@ -835,29 +923,33 @@
 __init int i2o_lan_init(void)
 {
 	struct device *dev;
-	struct i2o_lan_local *priv;
-        int i;
+	int i;
 
-        if (i2o_install_handler(&i2o_lan_handler) < 0)
+	bucketpost = bucketpost - bucketthresh;
+
+	if (i2o_install_handler(&i2o_lan_handler) < 0)
 	{
  		printk(KERN_ERR "Unable to register I2O LAN OSM.\n");
 		return -EINVAL;
-        }   
+	}   
+
+	for(i=0; i <= MAX_LAN_CARDS; i++)
+		i2o_landevs[i] = NULL;
 
 	lan_context = i2o_lan_handler.context;
 
-        for (i=0; i < MAX_I2O_CONTROLLERS; i++)
+	for (i=0; i < MAX_I2O_CONTROLLERS; i++)
 	{
-                struct i2o_controller *iop = i2o_find_controller(i);
-                struct i2o_device *i2o_dev;
+		struct i2o_controller *iop = i2o_find_controller(i);
+		struct i2o_device *i2o_dev;
 
-                if (iop==NULL)
+		if (iop==NULL)
 			continue;
 
-                for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next)
+		for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next)
 		{
-                        if (i2o_dev->class != I2O_CLASS_LAN) 
-                                continue;
+			if (i2o_dev->class != I2O_CLASS_LAN) 
+				continue;
 
 			if (unit == MAX_LAN_CARDS)
 			{
@@ -872,19 +964,15 @@
 				printk(KERN_ERR "Unable to register I2O LAN device\n");
 				continue; // try next one
 			}
-			priv = (struct i2o_lan_local *)dev->priv;	
-
-			unit++;
-			i2o_landevs[unit] = dev;
-			priv->unit = unit;
 
 			printk(KERN_INFO "%s: I2O LAN device registered, tid = %d,"
 				" subclass = 0x%08X, unit = %d.\n",
-				dev->name, i2o_dev->id, i2o_dev->subclass, 
-				priv->unit);
-                }
+				dev->name, i2o_dev->id, i2o_dev->subclass,
+				((struct i2o_lan_local *)dev->priv)->unit);
+		}
+
 		i2o_unlock_controller(iop);
-        }
+	}
 
 	dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1);
 
@@ -940,5 +1028,6 @@
 
 MODULE_PARM(bucketpost, "i");           // Number of buckets to post
 MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
+MODULE_PARM(rx_copybreak, "i");
 
 #endif    
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h
--- v2.3.12/linux/drivers/i2o/i2o_lan.h	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_lan.h	Thu Aug  5 15:04:52 1999
@@ -17,8 +17,8 @@
 
 /* Tunable parameters first */
 
-#define I2O_BUCKET_COUNT 	16
-#define I2O_BUCKET_THRESH	0
+#define I2O_BUCKET_COUNT 	64
+#define I2O_BUCKET_THRESH	16
 
 /* LAN types */
 #define I2O_LAN_ETHERNET	0x0030
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.12/linux/drivers/i2o/i2o_pci.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_pci.c	Fri Aug  6 11:16:54 1999
@@ -5,16 +5,17 @@
  *	(C) Copyright 1999   Red Hat Software
  *	
  *	Written by Alan Cox, Building Number Three Ltd
+ * Modified by Deepak Saxena <deepak@plexity.net>
  *
  *	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
+ * as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
  *	TODO:
  *		Support polled I2O PCI controllers. 
  */
- 
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -24,10 +25,21 @@
 #include <linux/malloc.h>
 #include <asm/io.h>
 
+#ifdef MODULE
+/*
+ * Core function table
+ * See <include/linux/i2o.h> for an explanation
+ */
+static struct i2o_core_func_table *core;
+
+/* Core attach function */
+extern int i2o_pci_core_attach(struct i2o_core_func_table *);
+extern void i2o_pci_core_detach(void);
+#endif /* MODULE */
+
 /*
  *	Free bus specific resources
  */
- 
 static void i2o_pci_dispose(struct i2o_controller *c)
 {
 	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
@@ -60,7 +72,11 @@
 static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
 {
 	struct i2o_controller *c = dev_id;
+#ifdef MODULE
+	core->run_queue(c);
+#else
 	i2o_run_queue(c);
+#endif /* MODULE */
 }	
 
 /*
@@ -76,20 +92,20 @@
 	u32 size;
 	
 	int i;
-	
+
 	if(c==NULL)
 	{
 		printk(KERN_ERR "i2o_pci: insufficient memory to add controller.\n");
 		return -ENOMEM;
 	}
 	memset(c, 0, sizeof(*c));
-	
+
 	for(i=0; i<6; i++)
 	{
 		/* Skip I/O spaces */
-		if(!(dev->base_address[i]&PCI_BASE_ADDRESS_SPACE))
+		if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE))
 		{
-			memptr=PCI_BASE_ADDRESS_MEM_MASK&dev->base_address[i];
+			memptr=dev->resource[i].flags;
 			break;
 		}
 	}
@@ -100,10 +116,7 @@
 		return -ENOMEM;
 	}
 	
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, 0xFFFFFFFF);
-	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, &size);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, dev->base_address[i]);
-	
+	size = dev->resource[i].end-dev->resource[i].start+1;	
 	/* Map the I2O controller */
 	
 	printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size);
@@ -125,8 +138,12 @@
 	c->type = I2O_TYPE_PCI;
 
 	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
-	
+
+#ifdef MODULE
+	i = core->install(c);
+#else
 	i = i2o_install_controller(c);
+#endif /* MODULE */
 	
 	if(i<0)
 	{
@@ -144,7 +161,11 @@
 			printk(KERN_ERR "%s: unable to allocate interrupt %d.\n",
 				c->name, dev->irq);
 			c->bus.pci.irq = -1;
+#ifdef MODULE
+			core->delete(c);
+#else
 			i2o_delete_controller(c);
+#endif /* MODULE */
 			return -EBUSY;
 		}
 	}
@@ -187,12 +208,27 @@
 	
 	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
 	{
+#ifdef MODULE
+		c=core->find(i);
+#else
 		c=i2o_find_controller(i);
+#endif /* MODULE */
+
 		if(c==NULL)
 			continue;		
+
+#ifdef MODULE
+		core->unlock(c);
+#else
 		i2o_unlock_controller(c);
+#endif /* MODULE */
+
 		if(c->type == I2O_TYPE_PCI)
+#ifdef MODULE
+			core->delete(c);
+#else
 			i2o_delete_controller(c);
+#endif /* MODULE */
 	}
 }
 
@@ -203,50 +239,102 @@
 	
 	for(i = 0; i < MAX_I2O_CONTROLLERS; i++)
 	{
+#ifdef MODULE
+		c=core->find(i);
+#else
 		c=i2o_find_controller(i);
+#endif /* MODULE */
+
 		if(c==NULL)
 			continue;		
 		if(c->type == I2O_TYPE_PCI)
 		{
+#ifdef MODULE
+			if(core->activate(c))
+#else
 			if(i2o_activate_controller(c))
+#endif /* MODULE */
 			{
 				printk("I2O: Failed to initialize iop%d\n", c->unit);
+#ifdef MODULE
+				core->unlock(c);
+				core->delete(c);
+#else
 				i2o_unlock_controller(c);
 				i2o_delete_controller(c);
+#endif
 				continue;
 			}
 		
 			I2O_IRQ_WRITE32(c,0);
 		}
+#ifdef MODULE
+		core->unlock(c);
+#else
 		i2o_unlock_controller(c);
+#endif
 	}
 }
 
+
 #ifdef MODULE
 
-EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Red Hat Software");
-MODULE_DESCRIPTION("I2O PCI Interface");
+int i2o_pci_core_attach(struct i2o_core_func_table *table)
+{
+	int i;
+
+	MOD_INC_USE_COUNT;
+
+	core = table;
+ 
+	if((i = i2o_pci_scan())<0)
+ 		return -ENODEV;
+ 	i2o_pci_activate();
+
+	return i;
+}
+
+void i2o_pci_core_detach(void)
+{
+	i2o_pci_unload();
+
+	MOD_DEC_USE_COUNT;
+}
 
 int init_module(void)
 {
-	if(i2o_pci_scan()<0)
-		return -ENODEV;
-	i2o_pci_activate();
-	return 0;
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
+
+/*
+ * Let the core call the scan function for module dependency
+ * reasons.  See include/linux/i2o.h for the reason why this
+ * is done.
+ *
+ *	if(i2o_pci_scan()<0)
+ *		return -ENODEV;
+ *	i2o_pci_activate();
+ */
+
+ 	return 0;
+ 
 }
 
 void cleanup_module(void)
 {
-	i2o_pci_unload();
 }
 
+EXPORT_SYMBOL(i2o_pci_core_attach);
+EXPORT_SYMBOL(i2o_pci_core_detach);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O PCI Interface");
+
 #else
 __init void i2o_pci_init(void)
 {
+	printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
 	if(i2o_pci_scan()>=0)
 	{
-		printk(KERN_INFO "Linux I2O PCI support (c) 1999 Red Hat Software.\n");
 		i2o_pci_activate();
 	}
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.3.12/linux/drivers/i2o/i2o_proc.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_proc.c	Fri Aug  6 11:16:54 1999
@@ -3,7 +3,7 @@
  *
  *   Copyright (c) 1999 Intel Corporation
  *   
- *   Originally written by Deepak Saxena(deepak.saxena@intel.com)
+ *   Originally written by Deepak Saxena(deepak@plexity.net)
  *
  *   This program is free software. You can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
@@ -143,7 +143,8 @@
 {
 	(void *)i2o_proc_reply,
 	"I2O procfs Layer",
-	0
+	0,
+	0xffffffff	// All classes
 };
 
 /*
@@ -3089,7 +3090,7 @@
 #ifdef MODULE
 
 
-MODULE_AUTHOR("Intel Corporation");
+MODULE_AUTHOR("Deepak Saxena");
 MODULE_DESCRIPTION("I2O procfs Handler");
 
 void cleanup_module(void)
diff -u --recursive --new-file v2.3.12/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- v2.3.12/linux/drivers/i2o/i2o_scsi.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/i2o/i2o_scsi.c	Thu Aug  5 15:04:52 1999
@@ -293,7 +293,8 @@
 {
 	i2o_scsi_reply,
 	"I2O SCSI OSM",
-	0
+	0,
+	I2O_CLASS_SCSI_PERIPHERAL
 };
 
 static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun)
diff -u --recursive --new-file v2.3.12/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- v2.3.12/linux/drivers/isdn/hisax/diva.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/isdn/hisax/diva.c	Fri Aug  6 11:43:09 1999
@@ -510,7 +510,7 @@
 			/* get IRQ */
 			cs->irq = dev_diva->irq;
 			/* get IO address */
-			cs->hw.diva.cfg_reg = dev_diva->base_address[2]
+			cs->hw.diva.cfg_reg = dev_diva->resource[2].start
 				& PCI_BASE_ADDRESS_IO_MASK;
 		} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL,
 			PCI_DIVA20_U_ID, dev_diva_u))) {
@@ -518,7 +518,7 @@
 			/* get IRQ */
 			cs->irq = dev_diva_u->irq;
 			/* get IO address */
-			cs->hw.diva.cfg_reg = dev_diva_u->base_address[2]
+			cs->hw.diva.cfg_reg = dev_diva_u->resource[2].start
 				& PCI_BASE_ADDRESS_IO_MASK;
 		} else {
 			printk(KERN_WARNING "Diva: No PCI card found\n");
diff -u --recursive --new-file v2.3.12/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- v2.3.12/linux/drivers/isdn/hisax/elsa.c	Sun May 23 10:03:41 1999
+++ linux/drivers/isdn/hisax/elsa.c	Fri Aug  6 11:43:09 1999
@@ -1027,17 +1027,17 @@
 			 dev_qs1000))) {
 				cs->subtyp = ELSA_QS1000PCI;
 			cs->irq = dev_qs1000->irq;
-			cs->hw.elsa.cfg = dev_qs1000->base_address[1] & 
+			cs->hw.elsa.cfg = dev_qs1000->resource[1].start & 
 				PCI_BASE_ADDRESS_IO_MASK;
-			cs->hw.elsa.base = dev_qs1000->base_address[3] & 
+			cs->hw.elsa.base = dev_qs1000->resource[3].start & 
 				PCI_BASE_ADDRESS_IO_MASK;
 		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA,
 			PCI_QS3000_ID, dev_qs3000))) {
 			cs->subtyp = ELSA_QS3000PCI;
 			cs->irq = dev_qs3000->irq;
-			cs->hw.elsa.cfg = dev_qs3000->base_address[1] & 
+			cs->hw.elsa.cfg = dev_qs3000->resource[1].start & 
 				PCI_BASE_ADDRESS_IO_MASK;
-			cs->hw.elsa.base = dev_qs3000->base_address[3] & 
+			cs->hw.elsa.base = dev_qs3000->resource[3].start & 
 				PCI_BASE_ADDRESS_IO_MASK;
 		} else {
 			printk(KERN_WARNING "Elsa: No PCI card found\n");
diff -u --recursive --new-file v2.3.12/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- v2.3.12/linux/drivers/isdn/hisax/netjet.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/isdn/hisax/netjet.c	Fri Aug  6 11:43:09 1999
@@ -1074,7 +1074,7 @@
 		printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
 		return(0);
 	}
-		cs->hw.njet.base = dev_netjet->base_address[0] &
+		cs->hw.njet.base = dev_netjet->resource[0].start &
 			PCI_BASE_ADDRESS_IO_MASK; 
 		if (!cs->hw.njet.base) {
 		printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
diff -u --recursive --new-file v2.3.12/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- v2.3.12/linux/drivers/isdn/hisax/niccy.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/isdn/hisax/niccy.c	Fri Aug  6 11:43:09 1999
@@ -319,16 +319,16 @@
 			return(0);
 		}
 			cs->irq = niccy_dev->irq;
-			if (!niccy_dev->base_address[0]) {
+			if (!niccy_dev->resource[0].start) {
 				printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
 			return(0);
 		}
-			cs->hw.niccy.cfg_reg = niccy_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-			if (!niccy_dev->base_address[1]) {
+			cs->hw.niccy.cfg_reg = niccy_dev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK;
+			if (!niccy_dev->resource[1].start) {
 			printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
 			return(0);
 		}
-			pci_ioaddr = niccy_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+			pci_ioaddr = niccy_dev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
 		cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
 		cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
 		cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.3.12/linux/drivers/macintosh/adb.c	Mon Jun  7 12:12:32 1999
+++ linux/drivers/macintosh/adb.c	Wed Aug  4 16:36:41 1999
@@ -31,7 +31,7 @@
 #include <asm/pmu.h>
 #include <asm/uaccess.h>
 #include <asm/hydra.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 EXPORT_SYMBOL(adb_controller);
 EXPORT_SYMBOL(adb_client_list);
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.3.12/linux/drivers/macintosh/mac_keyb.c	Mon Jun  7 12:12:32 1999
+++ linux/drivers/macintosh/mac_keyb.c	Mon Aug  9 10:23:09 1999
@@ -44,7 +44,7 @@
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 #include <linux/kbd_kern.h>
 #include <linux/kbd_ll.h>
@@ -673,7 +673,7 @@
 
 }
 
-__initfunc(void mackbd_init_hw(void))
+void __init mackbd_init_hw(void)
 {
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 	    return;
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c
--- v2.3.12/linux/drivers/macintosh/macio-adb.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/macio-adb.c	Wed Aug  4 16:36:41 1999
@@ -14,7 +14,7 @@
 #include <asm/hydra.h>
 #include <asm/irq.h>
 #include <asm/system.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 struct preg {
 	unsigned char r;
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.12/linux/drivers/macintosh/macserial.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/macintosh/macserial.c	Mon Aug  9 10:23:09 1999
@@ -39,7 +39,7 @@
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
-#include <asm/init.h>
+#include <linux/init.h>
 
 #include "macserial.h"
 
@@ -2121,7 +2121,7 @@
  *	- initialize the serial port
  *	Return non-zero if we didn't find a serial port.
  */
-__initfunc(static int serial_console_setup(struct console *co, char *options))
+static int __init serial_console_setup(struct console *co, char *options)
 {
 	struct mac_serial *info = zs_soft + co->index;
 	int	baud = 38400;
@@ -2306,7 +2306,7 @@
 /*
  *	Register console.
  */
-__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+long __init serial_console_init(long kmem_start, long kmem_end)
 {
 	register_console(&sercons);
 	return kmem_start;
@@ -2376,7 +2376,7 @@
  * boot command line flags.
  * XXX at the moment probably only channel A will work
  */
-__initfunc(void zs_kgdb_hook(int tty_num))
+void __init zs_kgdb_hook(int tty_num)
 {
 	/* Find out how many Z8530 SCCs we have */
 	if (zs_chain == 0)
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- v2.3.12/linux/drivers/macintosh/mediabay.c	Mon Dec 21 08:37:28 1998
+++ linux/drivers/macintosh/mediabay.c	Wed Aug  4 16:36:41 1999
@@ -25,7 +25,7 @@
 #include <asm/io.h>
 #include <asm/feature.h>
 #include <asm/mediabay.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 
 #undef MB_USE_INTERRUPTS
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c
--- v2.3.12/linux/drivers/macintosh/nvram.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/nvram.c	Mon Aug  9 10:23:09 1999
@@ -108,7 +108,7 @@
 	&nvram_fops
 };
 
-__initfunc(int nvram_init(void))
+int nvram_init(void)
 {
 	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
 		NVRAM_VERSION);
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.3.12/linux/drivers/macintosh/via-cuda.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/via-cuda.c	Wed Aug  4 16:36:41 1999
@@ -20,7 +20,7 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 static volatile unsigned char *via;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.3.12/linux/drivers/macintosh/via-pmu.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/via-pmu.c	Wed Aug  4 16:36:41 1999
@@ -28,7 +28,7 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/init.h>
+#include <linux/init.h>
 #include <asm/irq.h>
 #include <asm/feature.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.12/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.3.12/linux/drivers/net/3c59x.c	Tue Jan 19 14:47:15 1999
+++ linux/drivers/net/3c59x.c	Thu Aug  5 15:04:52 1999
@@ -655,20 +655,9 @@
 				continue;
 
 			{
-#if LINUX_VERSION_CODE >= 0x20155
 				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-				ioaddr = pdev->base_address[0] & ~3;
+				ioaddr = pdev->resource[0].start;
 				irq = pdev->irq;
-#else
-				u32 pci_ioaddr;
-				u8 pci_irq_line;
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, &pci_irq_line);
-				pcibios_read_config_dword(pci_bus, pci_device_fn,
-										  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-				ioaddr = pci_ioaddr & ~3;;
-				irq = pci_irq_line;
-#endif
 			}
 
 			/* Power-up the card. */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.12/linux/drivers/net/Config.in	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/Config.in	Fri Aug  6 10:44:11 1999
@@ -194,9 +194,11 @@
   dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 fi
 
-tristate 'PPP (point-to-point) support' CONFIG_PPP
+tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
-  comment 'CCP compressors for PPP are only built as modules.'
+  dep_tristate 'PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
+  dep_tristate 'PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+  dep_tristate 'PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
 fi
 
 tristate 'SLIP (serial line) support' CONFIG_SLIP
diff -u --recursive --new-file v2.3.12/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.12/linux/drivers/net/Makefile	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/Makefile	Mon Aug  9 12:32:28 1999
@@ -302,16 +302,38 @@
 # bsd_comp.o is *always* a module, for some documented reason
 # (licensing).
 ifeq ($(CONFIG_PPP),y)
-LX_OBJS += ppp.o
-M_OBJS += bsd_comp.o
+LX_OBJS += ppp_generic.o
 CONFIG_SLHC_BUILTIN = y
-CONFIG_PPPDEF_BUILTIN = y
+  ifeq ($(CONFIG_PPP_ASYNC),y)
+  LX_OBJS += ppp_async.o
+  else
+    ifeq ($(CONFIG_PPP_ASYNC),m)
+    MX_OBJS += ppp_async.o
+    endif
+  endif
+  ifeq ($(CONFIG_PPP_DEFLATE),y)
+  CONFIG_PPPDEF_BUILTIN = y
+  else
+    ifeq ($(CONFIG_PPP_DEFLATE),m)
+    CONFIG_PPPDEF_MODULE = y
+    endif
+  endif
+  ifeq ($(CONFIG_PPP_BSDCOMP),m)
+  M_OBJS += bsd_comp.o
+  endif
 else
   ifeq ($(CONFIG_PPP),m)
+  MX_OBJS += ppp_generic.o
   CONFIG_SLHC_MODULE = y
-  CONFIG_PPPDEF_MODULE = y
-  MX_OBJS += ppp.o
-  M_OBJS += bsd_comp.o
+    ifeq ($(CONFIG_PPP_ASYNC),m)
+    MX_OBJS += ppp_async.o
+    endif
+    ifeq ($(CONFIG_PPP_DEFLATE),m)
+    CONFIG_PPPDEF_MODULE = y
+    endif
+    ifeq ($(CONFIG_PPP_BSDCOMP),m)
+    M_OBJS += bsd_comp.o
+    endif
   endif
 endif
 
@@ -845,13 +867,11 @@
 
 # if anything built-in uses ppp_deflate, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
-# ... NO!!!  ppp_deflate.o does not work as resident;
-# it works only as a module!
 ifdef CONFIG_PPPDEF_BUILTIN
-MX_OBJS += ppp_deflate.o
+L_OBJS += ppp_deflate.o
 else
   ifdef CONFIG_PPPDEF_MODULE
-  MX_OBJS += ppp_deflate.o
+  M_OBJS += ppp_deflate.o
   endif
 endif
 
@@ -884,6 +904,17 @@
   M_OBJS += hplance.o
   endif
 endif
+
+ifeq ($(CONFIG_MVME147_NET),y)
+L_OBJS += mvme147.o
+CONFIG_7990_BUILTIN = y
+else
+  ifeq ($(CONFIG_MVME147_NET),m)
+  CONFIG_7990_MODULE = y
+  M_OBJS += mvme147.o
+  endif
+endif
+
 # If we need generic LANCE support, either in the kernel or as a module,
 # build it in the appropriate way.
 ifdef CONFIG_7990_BUILTIN
@@ -1054,6 +1085,10 @@
   ifeq ($(CONFIG_MACE),m)
   M_OBJS += mace.o
   endif
+endif
+
+ifeq ($(CONFIG_MACSONIC),y)
+L_OBJS += macsonic.o
 endif
 
 ifeq ($(CONFIG_BMAC),y)
diff -u --recursive --new-file v2.3.12/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.12/linux/drivers/net/Space.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/Space.c	Mon Aug  9 12:32:28 1999
@@ -114,10 +114,12 @@
 extern int hplance_probe(struct device *dev);
 extern int bagetlance_probe(struct device *);
 extern int dec_lance_probe(struct device *);
+extern int mvme147lance_probe(struct device *dev);
 extern int via_rhine_probe(struct device *dev);
 extern int tc515_probe(struct device *dev);
 extern int lance_probe(struct device *dev);
 extern int rcpci_probe(struct device *);
+extern int mac_onboard_sonic_probe(struct device *dev);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -425,6 +427,12 @@
 #ifdef CONFIG_HPLANCE		/* HP300 internal Ethernet */
 	{hplance_probe, 0},
 #endif
+#ifdef CONFIG_MVME147_NET	/* MVME147 internal Ethernet */
+	{mvme147lance_probe, 0},
+#endif
+#ifdef CONFIG_MACSONIC		/* Mac 68k Quadra builtin Ethernet */ 
+	{mac_onboard_sonic_probe, 0},
+#endif
 	{NULL, 0},
 };
 
@@ -679,6 +687,14 @@
 #undef NEXT_DEV
 #define NEXT_DEV (&mkiss_bootstrap)
 #endif	/* MKISS */
+  
+#if defined(CONFIG_YAM)
+extern int yam_init(struct device *);
+static struct device yam_bootstrap = {
+  "yam", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, yam_init, };
+#undef NEXT_DEV
+#define NEXT_DEV (&yam_bootstrap)
+#endif	/* CONFIG_YAM */
   
 #if defined(CONFIG_STRIP)
 extern int strip_init_ctrl_dev(struct device *);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.3.12/linux/drivers/net/acenic.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/acenic.c	Thu Aug  5 15:04:52 1999
@@ -288,13 +288,13 @@
 			break;
 		}
 		printk("Gigabit Ethernet at 0x%08lx, irq %i, PCI latency %i "
-		       "clks\n", pdev->base_address[0], dev->irq, pci_latency);
+		       "clks\n", pdev->resource[0].start, dev->irq, pci_latency);
 
 		/*
 		 * Remap the regs into kernel space.
 		 */
 
-		ap->regs = (struct ace_regs *)ioremap(pdev->base_address[0],
+		ap->regs = (struct ace_regs *)ioremap(pdev->resource[0].start,
 						      0x4000);
 		if (!ap->regs){
 			printk(KERN_ERR "%s:  Unable to map I/O register, "
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c
--- v2.3.12/linux/drivers/net/ariadne2.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/ariadne2.c	Mon Aug  9 12:32:28 1999
@@ -177,6 +177,7 @@
     name = "NE2000";
 
     dev->base_addr = ioaddr;
+    dev->irq = IRQ_AMIGA_PORTS;
 
     /* Install the Interrupt handler */
     if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, 0, "AriadNE2 Ethernet",
@@ -191,7 +192,9 @@
     ((struct ei_device *)dev->priv)->priv = key;
 
     for(i = 0; i < ETHER_ADDR_LEN; i++) {
+#ifdef DEBUG
 	printk(" %2.2x", SA_prom[i]);
+#endif
 	dev->dev_addr[i] = SA_prom[i];
     }
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c
--- v2.3.12/linux/drivers/net/atari_bionet.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/atari_bionet.c	Mon Aug  9 12:32:28 1999
@@ -446,7 +446,7 @@
 	}
 	else {
 		int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned long buf = VTOP(skb->data);
+		unsigned long buf = virt_to_phys(skb->data);
 		int stat;
 
 		stdma_lock(bionet_intr, NULL);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c
--- v2.3.12/linux/drivers/net/atari_pamsnet.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/atari_pamsnet.c	Mon Aug  9 12:32:28 1999
@@ -439,7 +439,7 @@
 	unsigned char *buffer;
 {
 	int ret = -1;
-	unsigned char *vbuffer = (unsigned char *)PTOV(buffer);
+	unsigned char *vbuffer = phys_to_virt((unsigned long)buffer);
 	unsigned char cmd_buffer[5];
 
 	if (send_first(target, INQUIRY))
@@ -487,7 +487,7 @@
 	    !acsi_wait_for_IRQ(TIMEOUTDMA) ||
 	    get_status())
 		goto bad;
-	ret = (HADDR *)PTOV(&(((DMAHWADDR *)buffer)->hwaddr));
+	ret = phys_to_virt(&(((DMAHWADDR *)buffer)->hwaddr));
 	dma_cache_maintenance((unsigned long)buffer, 512, 0);
 bad:
 	return (ret);
@@ -707,7 +707,7 @@
 	}
 	else {
 		int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned long buf = VTOP(skb->data);
+		unsigned long buf = virt_to_phys(skb->data);
 		int stat;
 
 		stdma_lock(pamsnet_intr, NULL);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.12/linux/drivers/net/de4x5.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/de4x5.c	Thu Aug  5 15:04:52 1999
@@ -2192,7 +2192,7 @@
 	lp->chipset = device;
 
 	/* Get the board I/O address (64 bits on sparc64) */
-	iobase = pdev->base_address[0] & CBIO_MASK;
+	iobase = pdev->resource[0].start;
 
 	/* Fetch the IRQ to be used */
 	irq = pdev->irq;
@@ -2278,7 +2278,7 @@
 	lp->chipset = device;
 
 	/* Get the board I/O address (64 bits on sparc64) */
-	iobase = dev->base_address[0] & CBIO_MASK;
+	iobase = dev->resource[0].start;
 
 	/* Fetch the IRQ to be used */
 	irq = dev->irq;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.3.12/linux/drivers/net/dgrs.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/dgrs.c	Thu Aug  5 15:04:52 1999
@@ -1395,28 +1395,14 @@
 							&pci_device_fn))
 					break;
 
-#if LINUX_VERSION_CODE < 0x20100
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-					PCI_INTERRUPT_LINE, &pci_irq);
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-					PCI_BASE_ADDRESS_0, &plxreg);
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-					PCI_BASE_ADDRESS_1, &io);
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-					PCI_BASE_ADDRESS_2, &mem);
-#else
 			pdev = pci_find_slot(pci_bus, pci_device_fn);
 			pci_irq = pdev->irq;
-			plxreg = pdev->base_address[0];
-			io = pdev->base_address[1];
-			mem = pdev->base_address[2];
-#endif
+			plxreg = pdev->resource[0].start;
+			io = pdev->resource[1].start;
+			mem = pdev->resource[2].start;
 			pcibios_read_config_dword(pci_bus, pci_device_fn,
 					0x30, &plxdma);
 			irq = pci_irq;
-			plxreg &= ~15;
-			io &= ~3;
-			mem &= ~15;
 			plxdma &= ~15;
 
 			/*
diff -u --recursive --new-file v2.3.12/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.12/linux/drivers/net/eepro100.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/eepro100.c	Mon Aug  9 10:26:12 1999
@@ -1,14 +1,14 @@
-/* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */
+/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
 /*
    NOTICE: this version tested with kernels 1.3.72 and later only!
-	Written 1996-1998 by Donald Becker.
+	Written 1996-1999 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
-	This driver is for the Intel EtherExpress Pro 100B boards.
-	It should work with other i82557 and i82558 boards.
-	To use a built-in driver, install as drivers/net/eepro100.c.
+	This driver is for the Intel EtherExpress Pro100 (Speedo3) design.
+	It should work with all i82557/558/559 boards.
+
 	To use as a module, use the compile-command at the end of the file.
 
 	The author may be reached as becker@CESDIS.usra.edu, or C/O
@@ -16,15 +16,17 @@
 	   Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
 	For updates see
 		http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
-	There is also a mailing list based at
+	For installation instructions
+		http://cesdis.gsfc.nasa.gov/linux/misc/modules.html
+	There is a Majordomo mailing list based at
 		linux-eepro100@cesdis.gsfc.nasa.gov
 */
 
 static const char *version =
-"eepro100.c:v1.06 10/16/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
+"eepro100.c:v1.09j 7/27/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
 
 /* A few user-configurable values that apply to all boards.
-   First set are undocumented and spelled per Intel recommendations. */
+   First set is undocumented and spelled per Intel recommendations. */
 
 static int congenb = 0;		/* Enable congestion control in the DP83840. */
 static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
@@ -38,14 +40,48 @@
 static int rx_copybreak = 200;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 200;
+static int max_interrupt_work = 20;
 
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 3;
+static int multicast_filter_limit = 64;
 
-#include <linux/module.h>
+/* 'options' is used to pass a transceiver override or full-duplex flag
+   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
+static int debug = -1;			/* The debug level */
+#endif
+
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE	32		/* Effectively 2 entries fewer. */
+#define RX_RING_SIZE	32
+/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
+#define TX_QUEUE_LIMIT  12
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ		1536
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
 
 #include <linux/version.h>
+#include <linux/module.h>
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+
+#if LINUX_VERSION_CODE < 0x20200  &&  defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -53,19 +89,24 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
+#ifdef HAS_PCI_NETIF
+#include "pci-netif.h"
+#else
 #include <linux/pci.h>
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h>		/* Ignore the bogus warning in 2.1.100+ */
+#endif
+#endif
+#include <asm/spinlock.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 
-#include <asm/spinlock.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-/*
- * Module documentation
- */
+#if LINUX_VERSION_CODE > 0x20118  &&  defined(MODULE)
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
 MODULE_PARM(debug, "i");
@@ -79,16 +120,39 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(multicast_filter_limit, "i");
+#endif
 
 #define RUN_AT(x) (jiffies + (x))
-
+/* Condensed bus+endian portability operations. */
+#define virt_to_le32bus(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32bus_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#define le16_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le32(val) (val)
+#define spin_lock_irqsave(&sp->lock, flags)	save_flags(flags); cli();
+#define spin_unlock_irqrestore(&sp->lock, flags); restore_flags(flags);
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
 #define dev_free_skb(skb) dev_kfree_skb(skb);
+#endif
+#if ! defined(CAP_NET_ADMIN)
+#define capable(CAP_XXX) (suser())
+#endif
+#if ! defined(HAS_NETIF_QUEUE)
+#define netif_wake_queue(dev)  mark_bh(NET_BH);
+#endif
 
 /* The total I/O port extent of the board.
    The registers beyond 0x18 only exist on the i82558. */
 #define SPEEDO3_TOTAL_SIZE 0x20
 
-int speedo_debug = 0;
+int speedo_debug = 1;
 
 /*
 				Theory of Operation
@@ -222,15 +286,52 @@
 
 */
 
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE	16		/* Effectively 2 entries fewer. */
-#define RX_RING_SIZE	16
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ		1536
+/* This table drives the PCI probe routines. */
+static struct device *
+speedo_found1(int pci_bus, int pci_devfn, struct device *dev,
+			  long ioaddr, int irq, int chip_idx, int fnd_cnt);
+
+#ifdef USE_IO
+#define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
+#define SPEEDO_SIZE		32
+#else
+#define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
+#define SPEEDO_SIZE		0x1000
+#endif
 
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((800*HZ)/1000)
+#if defined(HAS_PCI_NETIF)
+struct pci_id_info static pci_tbl[] = {
+	{ "Intel PCI EtherExpress Pro100",
+	  { 0x12298086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE,
+	  0, speedo_found1 },
+	{0,},						/* 0 terminated list. */
+};
+#else
+enum pci_flags_bit {
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+struct pci_id_info {
+	const char *name;
+	u16	vendor_id, device_id, device_id_mask, flags;
+	int io_size;
+	struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
+							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
+} static pci_tbl[] = {
+	{ "Intel PCI EtherExpress Pro100",
+	  0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 },
+	{0,},						/* 0 terminated list. */
+};
+#endif
+
+#ifndef USE_IO
+#define inb readb
+#define inw readw
+#define inl readl
+#define outb writeb
+#define outw writew
+#define outl writel
+#endif
 
 /* How to wait for the command unit to accept a command.
    Typically this takes 0 ticks. */
@@ -241,10 +342,6 @@
 	while(inb(cmd_ioaddr) && --wait >= 0);
 }
 
-/* Operational parameter that usually are not changed. */
-
-/* The rest of these values should never change. */
-
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
 enum speedo_offsets {
@@ -257,33 +354,41 @@
 };
 /* Commands that can be put in a command list entry. */
 enum commands {
-	CmdNOp = 0, CmdIASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-	CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7,
-	CmdSuspend = 0x4000,		/* Suspend after completion. */
-	CmdIntr = 0x2000,			/* Interrupt after completion. */
-	CmdTxFlex = 0x0008,			/* Use "Flexible mode" for CmdTx command. */
+	CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000,
+	CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000,
+	CmdDump = 0x60000, CmdDiagnose = 0x70000,
+	CmdSuspend = 0x40000000,	/* Suspend after completion. */
+	CmdIntr = 0x20000000,		/* Interrupt after completion. */
+	CmdTxFlex = 0x00080000,		/* Use "Flexible mode" for CmdTx command. */
 };
+/* Do atomically if possible. */
+#if defined(__i386__) || defined(__alpha__)
+#define clear_suspend(cmd)   clear_bit(30, &(cmd)->cmd_status)
+#elif defined(__powerpc__)
+#define clear_suspend(cmd)	clear_bit(6, &(cmd)->cmd_status)
+#else
+#define clear_suspend(cmd)	(cmd)->cmd_status &= cpu_to_le32(~CmdSuspend)
+#endif
 
-/* The SCB accepts the following controls for the Tx and Rx units: */
-#define	 CU_START		0x0010
-#define	 CU_RESUME		0x0020
-#define	 CU_STATSADDR	0x0040
-#define	 CU_SHOWSTATS	0x0050	/* Dump statistics counters. */
-#define	 CU_CMD_BASE	0x0060	/* Base address to add to add CU commands. */
-#define	 CU_DUMPSTATS	0x0070	/* Dump then reset stats counters. */
-
-#define	 RX_START	0x0001
-#define	 RX_RESUME	0x0002
-#define	 RX_ABORT	0x0004
-#define	 RX_ADDR_LOAD	0x0006
-#define	 RX_RESUMENR	0x0007
-#define INT_MASK	0x0100
-#define DRVR_INT	0x0200		/* Driver generated interrupt. */
+enum SCBCmdBits {
+     SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
+     SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
+     SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
+     /* The rest are Rx and Tx commands. */
+     CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
+     CUCmdBase=0x0060,  /* CU Base address (set to zero) . */
+     CUDumpStats=0x0070, /* Dump then reset stats counters. */
+     RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
+     RxResumeNoResources=0x0007,
+};
+
+enum SCBPort_cmds {
+	PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
+};
 
 /* The Speedo3 Rx and Tx frame/buffer descriptors. */
 struct descriptor {			/* A generic descriptor. */
-	s16 status;		/* Offset 0. */
-	s16 command;		/* Offset 2. */
+	s32 cmd_status;			/* All command and status fields. */
 	u32 link;					/* struct descriptor *  */
 	unsigned char params[0];
 };
@@ -293,8 +398,7 @@
 	s32 status;
 	u32 link;					/* struct RxFD * */
 	u32 rx_buf_addr;			/* void * */
-	u16 count;
-	u16 size;
+	u32 count;
 };
 
 /* Selected elements of the Tx/RxFD.status word. */
@@ -302,7 +406,7 @@
 	RxComplete=0x8000, RxOK=0x2000,
 	RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
 	RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
-	StatusComplete=0x8000,
+	TxUnderrun=0x1000,  StatusComplete=0x8000,
 };
 
 struct TxFD {					/* Transmit frame descriptor set. */
@@ -338,49 +442,57 @@
 	u32 done_marker;
 };
 
+/* Do not change the position (alignment) of the first few elements!
+   The later elements are grouped for cache locality. */
 struct speedo_private {
-	char devname[8];			/* Used only for kernel debugging. */
-	const char *product_name;
-	struct device *next_module;
-	spinlock_t lock;
-	struct TxFD	tx_ring[TX_RING_SIZE] 	/* Commands (usually CmdTxPacket). */
-				__attribute__ ((aligned (L1_CACHE_BYTES)));;
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct TxFD	tx_ring[TX_RING_SIZE];	/* Commands (usually CmdTxPacket). */
+	struct RxFD *rx_ringp[RX_RING_SIZE];	/* Rx descriptor, used as ring. */
+	/* The addresses of a Tx/Rx-in-place packets/buffers. */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	struct descriptor  *last_cmd;	/* Last command sent. */
-	/* Rx descriptor ring & addresses of receive-in-place skbuffs. */
-	struct RxFD *rx_ringp[RX_RING_SIZE];
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct descriptor  *last_cmd;	/* Last command sent. */
+	unsigned int cur_tx, dirty_tx;	/* The ring entries to be free()ed. */
+	spinlock_t lock;				/* Group with Tx control cache line. */
+	u32 tx_threshold;					/* The value for txdesc.count. */
 	struct RxFD *last_rxf;	/* Last command sent. */
+	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
+	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
+	const char *product_name;
+	struct device *next_module;
+	void *priv_addr;					/* Unaligned address for kfree */
 	struct enet_statistics stats;
 	struct speedo_stats lstats;
+	int chip_id;
+	unsigned char pci_bus, pci_devfn, acpi_pwr;
 	struct timer_list timer;	/* Media selection timer. */
-	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
-	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	int mc_setup_frm_len;			 	/* The length of an allocated.. */
 	struct descriptor *mc_setup_frm; 	/* ..multicast setup frame. */
 	int mc_setup_busy;					/* Avoid double-use of setup frame. */
+	int in_interrupt;					/* Word-aligned dev->interrupt */
 	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int default_port:1;		/* Last dev->if_port value. */
+	unsigned int flow_ctrl:1;			/* Use 802.3x flow control. */
 	unsigned int rx_bug:1;				/* Work around receiver hang errata. */
 	unsigned int rx_bug10:1;			/* Receiver might hang at 10mbps. */
 	unsigned int rx_bug100:1;			/* Receiver might hang at 100mbps. */
+	unsigned char default_port:8;		/* Last dev->if_port value. */
 	unsigned short phy[2];				/* PHY media interfaces available. */
+	unsigned short advertising;			/* Current PHY advertised caps. */
+	unsigned short partner;				/* Link partner caps. */
+	long last_reset;
 };
 
 /* The parameters for a CmdConfigure operation.
    There are so many options that it would be difficult to document each bit.
    We mostly use the default or recommended settings. */
 const char i82557_config_cmd[22] = {
-	22, 0x08, 0, 0,  0, 0x80, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
+	22, 0x08, 0, 0,  0, 0, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0,
 	0xf2, 0x48,   0, 0x40, 0xf2, 0x80, 		/* 0x40=Force full-duplex */
 	0x3f, 0x05, };
 const char i82558_config_cmd[22] = {
-	22, 0x08, 0, 1,  0, 0x80, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
+	22, 0x08, 0, 1,  0, 0, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0x08, 0x88,
 	0x68, 0, 0x40, 0xf2, 0xBD, 		/* 0xBD->0xFD=Force full-duplex */
 	0x31, 0x05, };
@@ -394,16 +506,16 @@
 enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
 					 S80C24, I82555, DP83840A=10, };
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
+#define EE_READ_CMD		(6)
 
-static void speedo_found1(struct device *dev, long ioaddr, int irq,
-						  int card_idx);
-
-static int read_eeprom(long ioaddr, int location, int addr_len);
+static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static int mdio_write(long ioaddr, int phy_id, int location, int value);
 static int speedo_open(struct device *dev);
+static void speedo_resume(struct device *dev);
 static void speedo_timer(unsigned long data);
 static void speedo_init_rx_ring(struct device *dev);
+static void speedo_tx_timeout(struct device *dev);
 static int speedo_start_xmit(struct sk_buff *skb, struct device *dev);
 static int speedo_rx(struct device *dev);
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -414,15 +526,6 @@
 
 
 
-/* The parameters that may be passed in... */
-/* 'options' is used to pass a transceiver override or full-duplex flag
-   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#ifdef MODULE
-static int debug = -1;			/* The debug level */
-#endif
-
 #ifdef honor_default_port
 /* Optional driver feature to allow forcing the transceiver setting.
    Not recommended. */
@@ -433,6 +536,7 @@
 /* A list of all installed Speedo devices, for removing the driver module. */
 static struct device *root_speedo_dev = NULL;
 
+#if ! defined(HAS_PCI_NETIF)
 int eepro100_init(struct device *dev)
 {
 	int cards_found = 0;
@@ -443,6 +547,7 @@
 
 	for (; pci_index < 8; pci_index++) {
 		unsigned char pci_bus, pci_device_fn, pci_latency;
+		u32 pciaddr;
 		long ioaddr;
 		int irq;
 
@@ -453,13 +558,42 @@
 								pci_index, &pci_bus,
 								&pci_device_fn))
 			break;
+#if LINUX_VERSION_CODE >= 0x20155  ||  PCI_SUPPORT_1
 		{
 			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-			ioaddr = pdev->base_address[1];		/* Use [0] to mem-map */
+#ifdef USE_IO
+			pciaddr = pdev->resource[1].start;
+#else
+			pciaddr = pdev->resource[0].start;
+#endif
 			irq = pdev->irq;
 		}
+#else
+		{
+			u8 pci_irq_line;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			/* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
+#ifdef USE_IO
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_1, &pciaddr);
+#else
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pciaddr);
+#endif
+			irq = pci_irq_line;
+		}
+#endif
 		/* Remove I/O space marker in bit 0. */
-		ioaddr &= ~3;
+		if (pciaddr & 1) {
+			ioaddr = pciaddr & ~3;
+			if (check_region(ioaddr, 32))
+				continue;
+		} else if ((ioaddr = (long)ioremap(pciaddr & ~0xf, 0x1000)) == 0) {
+			printk(KERN_INFO "Failed to map PCI address %#x.\n",
+				   pciaddr);
+			continue;
+		}
 		if (speedo_debug > 2)
 			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
 				   ioaddr, irq);
@@ -485,25 +619,29 @@
 		} else if (speedo_debug > 1)
 			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 
-		speedo_found1(dev, ioaddr, irq, cards_found);
+		speedo_found1(pci_bus, pci_device_fn, dev, ioaddr, irq, 0,cards_found);
 		dev = NULL;
 		cards_found++;
 	}
 
 	return cards_found;
 }
+#endif
 
-static void speedo_found1(struct device *dev, long ioaddr, int irq,
-						  int card_idx)
+static struct device *
+speedo_found1(int pci_bus, int pci_devfn, struct device *dev,
+			  long ioaddr, int irq, int chip_idx, int card_idx)
 {
-	static int did_version = 0;			/* Already printed version info. */
 	struct speedo_private *sp;
-	char *product;
+	const char *product;
 	int i, option;
-	u16 eeprom[0x40];
-
+	u16 eeprom[0x100];
+	int acpi_idle_state = 0;
+#ifndef MODULE
+	static int did_version = 0;			/* Already printed version info. */
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
+#endif
 
 	dev = init_etherdev(dev, sizeof(struct speedo_private));
 
@@ -514,16 +652,31 @@
 	else
 		option = 0;
 
+#if defined(HAS_PCI_NETIF)
+	acpi_idle_state = acpi_set_pwr_state(pci_bus, pci_devfn, ACPI_D0);
+#endif
+
 	/* Read the station address EEPROM before doing the reset.
-	   Perhaps this should even be done before accepting the device,
-	   then we wouldn't have a device name with which to report the error. */
+	   Nominally his should even be done before accepting the device, but
+	   then we wouldn't have a device name with which to report the error.
+	   The size test is for 6 bit vs. 8 bit address serial EEPROMs.
+	*/
 	{
 		u16 sum = 0;
 		int j;
-		int addr_len = read_eeprom(ioaddr, 0, 6) == 0xffff ? 8 : 6;
+		int read_cmd, ee_size;
 
-		for (j = 0, i = 0; i < 0x40; i++) {
-			u16 value = read_eeprom(ioaddr, i, addr_len);
+		if ((do_eeprom_cmd(ioaddr, EE_READ_CMD << 24, 27) & 0xffe0000)
+			== 0xffe0000) {
+			ee_size = 0x100;
+			read_cmd = EE_READ_CMD << 24;
+		} else {
+			ee_size = 0x40;
+			read_cmd = EE_READ_CMD << 22;
+		}
+
+		for (j = 0, i = 0; i < ee_size; i++) {
+			u16 value = do_eeprom_cmd(ioaddr, read_cmd | (i << 16), 27);
 			eeprom[i] = value;
 			sum += value;
 			if (i < 3) {
@@ -542,12 +695,12 @@
 	/* Reset the chip: stop Tx and Rx processes and clear counters.
 	   This takes less than 10usec and will easily finish before the next
 	   action. */
-	outl(0, ioaddr + SCBPort);
+	outl(PortReset, ioaddr + SCBPort);
 
 	if (eeprom[3] & 0x0100)
 		product = "OEM i82557/i82558 10/100 Ethernet";
 	else
-		product = "Intel EtherExpress Pro 10/100";
+		product = pci_tbl[chip_idx].name;
 
 	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
 
@@ -600,7 +753,7 @@
 		self_test_results = (s32*) ((((long) str) + 15) & ~0xf);
 		self_test_results[0] = 0;
 		self_test_results[1] = -1;
-		outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
+		outl(virt_to_bus(self_test_results) | PortSelfTest, ioaddr + SCBPort);
 		do {
 			udelay(10);
 		} while (self_test_results[1] == -1  &&  --boguscnt >= 0);
@@ -624,19 +777,33 @@
 	}
 #endif  /* kernel_bloat */
 
+	outl(PortReset, ioaddr + SCBPort);
+#if defined(HAS_PCI_NETIF)
+	/* Return the chip to its original power state. */
+	acpi_set_pwr_state(pci_bus, pci_devfn, acpi_idle_state);
+#endif
+
 	/* We do a request_region() only to register /proc/ioports info. */
 	request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	if (dev->priv == NULL)
-		dev->priv = kmalloc(sizeof(*sp), GFP_KERNEL);
 	sp = dev->priv;
+	if (dev->priv == NULL) {
+		void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
+		dev->priv = sp = mem;		/* Cache align here if kmalloc does not. */
+		sp->priv_addr = mem;
+	}
 	memset(sp, 0, sizeof(*sp));
 	sp->next_module = root_speedo_dev;
 	root_speedo_dev = dev;
 
+	sp->pci_bus = pci_bus;
+	sp->pci_devfn = pci_devfn;
+	sp->chip_id = chip_idx;
+	sp->acpi_pwr = acpi_idle_state;
+
 	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
@@ -659,7 +826,7 @@
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &speedo_ioctl;
 
-	return;
+	return dev;
 }
 
 /* Serial EEPROM section.
@@ -668,47 +835,33 @@
 #define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */
 #define EE_CS			0x02	/* EEPROM chip select. */
 #define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */
-#define EE_WRITE_0		0x01
-#define EE_WRITE_1		0x05
 #define EE_DATA_READ	0x08	/* EEPROM chip data out. */
 #define EE_ENB			(0x4800 | EE_CS)
+#define EE_WRITE_0		0x4802
+#define EE_WRITE_1		0x4806
+#define EE_OFFSET		SCBeeprom
 
 /* Delay between EEPROM clock transitions.
-   This will actually work with no delay on 33Mhz PCI.  */
-#define eeprom_delay(nanosec)		udelay(1);
+   The code works with no delay on 33Mhz PCI.  */
+#define eeprom_delay()	inw(ee_addr)
 
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD	(5 << addr_len)
-#define EE_READ_CMD		(6 << addr_len)
-#define EE_ERASE_CMD	(7 << addr_len)
-
-static int read_eeprom(long ioaddr, int location, int addr_len)
-{
-	unsigned short retval = 0;
-	int ee_addr = ioaddr + SCBeeprom;
-	int read_cmd = location | EE_READ_CMD;
-	int i;
+static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
+{
+	unsigned retval = 0;
+	long ee_addr = ioaddr + SCBeeprom;
 
-	outw(EE_ENB & ~EE_CS, ee_addr);
-	outw(EE_ENB, ee_addr);
+	outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
 
-	/* Shift the read command bits out. */
-	for (i = 12; i >= 0; i--) {
-		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-		outw(EE_ENB | dataval, ee_addr);
-		eeprom_delay(100);
-		outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay(150);
-	}
-	outw(EE_ENB, ee_addr);
-
-	for (i = 15; i >= 0; i--) {
-		outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay(100);
+	/* Shift the command bits out. */
+	do {
+		short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+		outw(dataval, ee_addr);
+		eeprom_delay();
+		outw(dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
 		retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
-		outw(EE_ENB, ee_addr);
-		eeprom_delay(100);
-	}
+	} while (--cmd_len >= 0);
+	outw(EE_ENB, ee_addr);
 
 	/* Terminate the EEPROM access. */
 	outw(EE_ENB & ~EE_CS, ee_addr);
@@ -723,6 +876,7 @@
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
+			break;
 		}
 	} while (! (val & 0x10000000));
 	return val & 0xffff;
@@ -737,6 +891,7 @@
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
+			break;
 		}
 	} while (! (val & 0x10000000));
 	return val & 0xffff;
@@ -749,21 +904,31 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-#ifdef notdef
-	/* We could reset the chip, but should not need to. */
-	/* In fact we MUST NOT, unless we also re-do the init */
-	outl(0, ioaddr + SCBPort);
-	udelay(10);
+#if defined(HAS_PCI_NETIF)
+	acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
 #endif
 
-	/* This had better be initialized before we initialize the interrupt! */
-	sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
-#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
-	/* Retrigger negotiation to reset previous errors. */
+	/* Set up the Tx queue early.. */
+	sp->cur_tx = 0;
+	sp->dirty_tx = 0;
+	sp->last_cmd = 0;
+	sp->tx_full = 0;
+	sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+	sp->in_interrupt = 0;
+
+	/* .. we can safely take handler calls during init. */
+	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
+		return -EAGAIN;
+	}
+	MOD_INC_USE_COUNT;
+
+	dev->if_port = sp->default_port;
+#if 0
+	/* With some transceivers we must retrigger negotiation to reset
+	   power-up errors. */
 	if ((sp->phy[0] & 0x8000) == 0) {
 		int phy_addr = sp->phy[0] & 0x1f ;
 		/* Use 0x3300 for restarting NWay, other values to force xcvr:
@@ -780,85 +945,30 @@
 	}
 #endif
 
-	/* Load the statistics block address. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
-	outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd);
-	sp->lstats.done_marker = 0;
-
 	speedo_init_rx_ring(dev);
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(0, ioaddr + SCBPointer);
-	outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd);
-
-	/* Todo: verify that we must wait for previous command completion. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(virt_to_bus(sp->rx_ringp[0]), ioaddr + SCBPointer);
-	outw(INT_MASK | RX_START, ioaddr + SCBCmd);
-
-	/* Fill the first command with our physical address. */
-	{
-		u16 *eaddrs = (u16 *)dev->dev_addr;
-		u16 *setup_frm = (u16 *)&(sp->tx_ring[0].tx_desc_addr);
 
-		/* Avoid a bug(?!) here by marking the command already completed. */
-		sp->tx_ring[0].status = ((CmdSuspend | CmdIASetup) << 16) | 0xa000;
-		sp->tx_ring[0].link = virt_to_bus(&(sp->tx_ring[1]));
-		*setup_frm++ = eaddrs[0];
-		*setup_frm++ = eaddrs[1];
-		*setup_frm++ = eaddrs[2];
-	}
-	sp->last_cmd = (struct descriptor *)&sp->tx_ring[0];
-	sp->cur_tx = 1;
-	sp->dirty_tx = 0;
-	sp->tx_full = 0;
-
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(0, ioaddr + SCBPointer);
-	outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd);
-
-	dev->if_port = sp->default_port;
+	/* Fire up the hardware. */
+	speedo_resume(dev);
 
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
 
-	/* Start the chip's Tx process and unmask interrupts. */
-	/* Todo: verify that we must wait for previous command completion. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(virt_to_bus(&sp->tx_ring[0]), ioaddr + SCBPointer);
-	outw(CU_START, ioaddr + SCBCmd);
-
 	/* Setup the chip and configure the multicast list. */
 	sp->mc_setup_frm = NULL;
 	sp->mc_setup_frm_len = 0;
 	sp->mc_setup_busy = 0;
 	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
+	sp->flow_ctrl = sp->partner = 0;
 	set_rx_mode(dev);
+	if ((sp->phy[0] & 0x8000) == 0)
+		sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
 
 	if (speedo_debug > 2) {
 		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
 
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outw(CU_DUMPSTATS, ioaddr + SCBCmd);
-
-	/*
-	 * Request the IRQ last, after we have set up all data structures.
-	 * It would be bad to get an interrupt before we're ready.
-	 */
-	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
-					"Intel EtherExpress Pro 10/100 Ethernet", dev)) {
-		return -EAGAIN;
-	}
-
-	/* No need to wait for the command unit to accept here. */
-	if ((sp->phy[0] & 0x8000) == 0)
-		mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
-
-	MOD_INC_USE_COUNT;
-
 	/* Set the timer.  The timer serves a dual purpose:
 	   1) to monitor the media interface (e.g. link beat) and perhaps switch
 	   to an alternate media type
@@ -870,20 +980,104 @@
 	sp->timer.function = &speedo_timer;					/* timer handler */
 	add_timer(&sp->timer);
 
+	/* No need to wait for the command unit to accept here. */
+	if ((sp->phy[0] & 0x8000) == 0)
+		mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
 	return 0;
 }
 
+/* Start the chip hardware after a full reset. */
+static void speedo_resume(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	outw(SCBMaskAll, ioaddr + SCBCmd);
+
+	/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
+	sp->tx_threshold = 0x01208000;
+
+	/* Set the segment registers to '0'. */
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	outl(0, ioaddr + SCBPointer);
+	outb(RxAddrLoad, ioaddr + SCBCmd);
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	outb(CUCmdBase, ioaddr + SCBCmd);
+	wait_for_cmd_done(ioaddr + SCBCmd);
+
+	/* Load the statistics block and rx ring addresses. */
+	outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
+	outb(CUStatsAddr, ioaddr + SCBCmd);
+	sp->lstats.done_marker = 0;
+	wait_for_cmd_done(ioaddr + SCBCmd);
+
+	outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
+		 ioaddr + SCBPointer);
+	outb(RxStart, ioaddr + SCBCmd);
+	wait_for_cmd_done(ioaddr + SCBCmd);
+
+	outb(CUDumpStats, ioaddr + SCBCmd);
+
+	/* Fill the first command with our physical address. */
+	{
+		int entry = sp->cur_tx++ % TX_RING_SIZE;
+		struct descriptor *cur_cmd = (struct descriptor *)&sp->tx_ring[entry];
+
+		/* Avoid a bug(?!) here by marking the command already completed. */
+		cur_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000);
+		cur_cmd->link =
+			virt_to_le32bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+		memcpy(cur_cmd->params, dev->dev_addr, 6);
+		if (sp->last_cmd)
+			clear_suspend(sp->last_cmd);
+		sp->last_cmd = cur_cmd;
+	}
+
+	/* Start the chip's Tx process and unmask interrupts. */
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
+		 ioaddr + SCBPointer);
+	outw(CUStart, ioaddr + SCBCmd);
+}
+
 /* Media monitoring and control. */
 static void speedo_timer(unsigned long data)
 {
 	struct device *dev = (struct device *)data;
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int phy_num = sp->phy[0] & 0x1f;
+
+	/* We have MII and lost link beat. */
+	if ((sp->phy[0] & 0x8000) == 0) {
+		int partner = mdio_read(ioaddr, phy_num, 5);
+		if (partner != sp->partner) {
+			int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
+			sp->partner = partner;
+			if (flow_ctrl != sp->flow_ctrl) {
+				sp->flow_ctrl = flow_ctrl;
+				sp->rx_mode = -1;	/* Trigger a reload. */
+			}
+			/* Clear sticky bit. */
+			mdio_read(ioaddr, phy_num, 1);
+			/* If link beat has returned... */
+			if (mdio_read(ioaddr, phy_num, 1) & 0x0004)
+				dev->flags |= IFF_RUNNING; 
+			else
+				dev->flags &= ~IFF_RUNNING;
+		}
+	}
 
 	if (speedo_debug > 3) {
-		long ioaddr = dev->base_addr;
 		printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
+	/* This has a small false-trigger window. */
+	if (test_bit(0, (void*)&dev->tbusy) &&
+		(jiffies - dev->trans_start) > TX_TIMEOUT) {
+		speedo_tx_timeout(dev);
+		sp->last_reset = jiffies;
+	}
 	if (sp->rx_mode < 0  ||
 		(sp->rx_bug  && jiffies - sp->last_rx_time > 2*HZ)) {
 		/* We haven't received a packet in a Long Time.  We might have been
@@ -896,6 +1090,39 @@
 	add_timer(&sp->timer);
 }
 
+static void speedo_show_state(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int phy_num = sp->phy[0] & 0x1f;
+	int i;
+
+	/* Print a few items for debugging. */
+	if (speedo_debug > 0) {
+		int i;
+		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %d / %d:\n", dev->name,
+			   sp->cur_tx, sp->dirty_tx);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(KERN_DEBUG "%s: %c%c%d %8.8x.\n", dev->name,
+				   i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
+				   i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
+				   i, sp->tx_ring[i].status);
+	}
+	printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n",
+		   dev->name, sp->cur_rx);
+
+	for (i = 0; i < RX_RING_SIZE; i++)
+		printk(KERN_DEBUG "  Rx ring entry %d  %8.8x.\n",
+			   i, (int)sp->rx_ringp[i]->status);
+
+	for (i = 0; i < 16; i++) {
+		if (i == 6) i = 21;
+		printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
+			   phy_num, i, mdio_read(ioaddr, phy_num, i));
+	}
+
+}
+
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void
 speedo_init_rx_ring(struct device *dev)
@@ -917,9 +1144,9 @@
 		sp->rx_ringp[i] = rxf;
 		skb_reserve(skb, sizeof(struct RxFD));
 		if (last_rxf)
-			last_rxf->link = virt_to_bus(rxf);
+			last_rxf->link = virt_to_le32bus(rxf);
 		last_rxf = rxf;
-		rxf->status = 0x00000001; 			/* '1' is flag value only. */
+		rxf->status = cpu_to_le32(0x00000001);	/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
 		/* This field unused by i82557, we use it as a consistency check. */
 #ifdef final_version
@@ -927,12 +1154,11 @@
 #else
 		rxf->rx_buf_addr = virt_to_bus(skb->tail);
 #endif
-		rxf->count = 0;
-		rxf->size = PKT_BUF_SZ;
+		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
 	}
 	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as end-of-list. */
-	last_rxf->status = 0xC0000002; 			/* '2' is flag value only. */
+	last_rxf->status = cpu_to_le32(0xC0000002);	/* '2' is flag value only. */
 	sp->last_rxf = last_rxf;
 }
 
@@ -940,22 +1166,33 @@
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
+	int status = inw(ioaddr + SCBStatus);
+
+	/* Trigger a stats dump to give time before the reset. */
+	speedo_get_stats(dev);
 
 	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   " %4.4x at %d/%d command %8.8x.\n",
-		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd),
+		   dev->name, status, inw(ioaddr + SCBCmd),
 		   sp->dirty_tx, sp->cur_tx,
 		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
-	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
+	speedo_show_state(dev);
+	if ((status & 0x00C0) != 0x0080
+		&&  (status & 0x003C) == 0x0010) {
+		/* Only the command unit has stopped. */
 		printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
 			   dev->name);
 		outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
 			 ioaddr + SCBPointer);
-		outw(CU_START, ioaddr + SCBCmd);
+		outw(CUStart, ioaddr + SCBCmd);
 	} else {
-		outw(DRVR_INT, ioaddr + SCBCmd);
+		/* Reset the Tx and Rx units. */
+		outl(PortReset, ioaddr + SCBPort);
+		if (speedo_debug > 0)
+			speedo_show_state(dev);
+		udelay(10);
+		speedo_resume(dev);
 	}
-#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us
 	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
 	if ((sp->phy[0] & 0x8000) == 0) {
 		int phy_addr = sp->phy[0] & 0x1f;
@@ -967,7 +1204,6 @@
 		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
 #endif
 	}
-#endif
 	sp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	return;
@@ -989,7 +1225,7 @@
 			return 1;
 		if (tickssofar < TX_TIMEOUT) {
 			/* Reap sent packets from the full Tx queue. */
-			outw(DRVR_INT, ioaddr + SCBCmd);
+			outw(SCBTriggerIntr, ioaddr + SCBCmd);
 			return 1;
 		}
 		speedo_tx_timeout(dev);
@@ -1003,43 +1239,39 @@
 		unsigned long flags;
 
 		spin_lock_irqsave(&sp->lock, flags);
-
 		/* Calculate the Tx descriptor entry. */
 		entry = sp->cur_tx++ % TX_RING_SIZE;
 
 		sp->tx_skbuff[entry] = skb;
 		/* Todo: be a little more clever about setting the interrupt bit. */
 		sp->tx_ring[entry].status =
-			(CmdSuspend | CmdTx | CmdTxFlex) << 16;
+			cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex);
 		sp->tx_ring[entry].link =
-		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+			virt_to_le32bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
 		sp->tx_ring[entry].tx_desc_addr =
-		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);
-		/* The data region is always in one buffer descriptor, Tx FIFO
-		   threshold of 256. */
-		sp->tx_ring[entry].count = 0x01208000;
-		sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);
-		sp->tx_ring[entry].tx_buf_size0 = skb->len;
+			virt_to_le32bus(&sp->tx_ring[entry].tx_buf_addr0);
+		/* The data region is always in one buffer descriptor. */
+		sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold);
+		sp->tx_ring[entry].tx_buf_addr0 = virt_to_le32bus(skb->data);
+		sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
 		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
 		   than half full.  Argument against: we should be receiving packets
 		   and scavenging the queue.  Argument for: if so, it shouldn't
 		   matter. */
-		sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);
-		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
-
 		/* Trigger the command unit resume. */
-		wait_for_cmd_done(ioaddr + SCBCmd);
-		outw(CU_RESUME, ioaddr + SCBCmd);
-
+		{
+			struct descriptor *last_cmd = sp->last_cmd;
+			sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+			clear_suspend(last_cmd);
+		}
+		if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT)
+			sp->tx_full = 1;
+		else
+			clear_bit(0, (void*)&dev->tbusy);
 		spin_unlock_irqrestore(&sp->lock, flags);
 	}
-
-	/* Leave room for set_rx_mode() to fill two entries. */
-	if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
-		sp->tx_full = 1;
-	else
-		clear_bit(0, (void*)&dev->tbusy);
-
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	outw(CUResume, ioaddr + SCBCmd);
 	dev->trans_start = jiffies;
 
 	return 0;
@@ -1063,9 +1295,14 @@
 
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
-	spin_lock(&sp->lock);
-
 #ifndef final_version
+	/* A lock to prevent simultaneous entry on SMP machines. */
+	if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+			   dev->name);
+		sp->in_interrupt = 0;	/* Avoid halting machine. */
+		return;
+	}
 	dev->interrupt = 1;
 #endif
 
@@ -1085,37 +1322,44 @@
 			speedo_rx(dev);
 
 		if (status & 0x1000) {
-		  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
-			outw(RX_RESUMENR, ioaddr + SCBCmd);
-		  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
-			/* No idea of what went wrong.  Restart the receiver. */
-			outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
-				 ioaddr + SCBPointer);
-			outw(RX_START, ioaddr + SCBCmd);
-		  }
-		  sp->stats.rx_errors++;
+			if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
+				outw(RxResumeNoResources, ioaddr + SCBCmd);
+			else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
+				/* No idea of what went wrong.  Restart the receiver. */
+				outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
+					 ioaddr + SCBPointer);
+				outw(RxStart, ioaddr + SCBCmd);
+			}
+			sp->stats.rx_errors++;
 		}
 
 		/* User interrupt, Command/Tx unit interrupt or CU not active. */
 		if (status & 0xA400) {
-			unsigned int dirty_tx = sp->dirty_tx;
+			unsigned int dirty_tx;
+			spin_lock(&sp->lock);
 
+			dirty_tx = sp->dirty_tx;
 			while (sp->cur_tx - dirty_tx > 0) {
 				int entry = dirty_tx % TX_RING_SIZE;
-				int status = sp->tx_ring[entry].status;
+				int status = le32_to_cpu(sp->tx_ring[entry].status);
 
 				if (speedo_debug > 5)
 					printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
 						   entry, status);
 				if ((status & StatusComplete) == 0)
 					break;			/* It still hasn't been processed. */
+				if (status & TxUnderrun)
+					if (sp->tx_threshold < 0x01e08000)
+						sp->tx_threshold += 0x00040000;
 				/* Free the original skb. */
 				if (sp->tx_skbuff[entry]) {
 					sp->stats.tx_packets++;	/* Count only user packets. */
-					sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; /* Count transmitted bytes */
+#if LINUX_VERSION_CODE > 0x20127
+					sp->stats.tx_bytes += sp->tx_skbuff[entry]->len;
+#endif
 					dev_free_skb(sp->tx_skbuff[entry]);
 					sp->tx_skbuff[entry] = 0;
-				} else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16)
+				} else if ((status & 0x70000) == CmdNOp)
 					sp->mc_setup_busy = 0;
 				dirty_tx++;
 			}
@@ -1129,15 +1373,16 @@
 			}
 #endif
 
-			if (sp->tx_full && dev->tbusy
-				&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
+			sp->dirty_tx = dirty_tx;
+			if (sp->tx_full
+				&&  sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) {
 				/* The ring is no longer full, clear tbusy. */
 				sp->tx_full = 0;
 				clear_bit(0, (void*)&dev->tbusy);
-				mark_bh(NET_BH);
-			}
-
-			sp->dirty_tx = dirty_tx;
+				spin_unlock(&sp->lock);
+				netif_wake_queue(dev);
+			} else
+				spin_unlock(&sp->lock);
 		}
 
 		if (--boguscnt < 0) {
@@ -1154,7 +1399,7 @@
 			   dev->name, inw(ioaddr + SCBStatus));
 
 	dev->interrupt = 0;
-	spin_unlock(&sp->lock);
+	clear_bit(0, (void*)&sp->in_interrupt);
 	return;
 }
 
@@ -1170,26 +1415,25 @@
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while (sp->rx_ringp[entry] != NULL &&
-		   (status = sp->rx_ringp[entry]->status) & RxComplete) {
+		   (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) {
+		int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
 
 		if (--rx_work_limit < 0)
 			break;
 		if (speedo_debug > 4)
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
-				   sp->rx_ringp[entry]->count & 0x3fff);
-		if ((status & (RxErrTooBig|RxOK)) != RxOK) {
+				   pkt_len);
+		if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
 			if (status & RxErrTooBig)
 				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
 					   "status %8.8x!\n", dev->name, status);
-			else if ( ! (status & 0x2000)) {
+			else if ( ! (status & RxOK)) {
 				/* There was a fatal error.  This *should* be impossible. */
 				sp->stats.rx_errors++;
 				printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
-					   "status %8.8x.\n",
-					   dev->name, status);
+					   "status %8.8x.\n", dev->name, status);
 			}
 		} else {
-			int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
 			struct sk_buff *skb;
 
 			/* Check if the packet is long enough to just accept without
@@ -1201,13 +1445,11 @@
 				/* 'skb_put()' points to the start of sk_buff data area. */
 #if 1 || USE_IP_CSUM
 				/* Packet is in one chunk -- we can copy + cksum. */
-				eth_copy_and_sum(skb,
-								 bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-								 pkt_len, 0);
+				eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
+				memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
+					   pkt_len);
 #endif
 			} else {
 				void *temp;
@@ -1220,24 +1462,28 @@
 				}
 				sp->rx_skbuff[entry] = NULL;
 				temp = skb_put(skb, pkt_len);
+#if !defined(final_version) && !defined(__powerpc__)
 				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
 					printk(KERN_ERR "%s: Rx consistency error -- the skbuff "
 						   "addresses do not match in speedo_rx: %p vs. %p "
 						   "/ %p.\n", dev->name,
 						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
 						   skb->head, temp);
+#endif
 				sp->rx_ringp[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			sp->stats.rx_packets++;
-			sp->stats.rx_bytes += pkt_len; /* Count received bytes */
+#if LINUX_VERSION_CODE > 0x20127
+			sp->stats.rx_bytes += pkt_len;
+#endif
 		}
 		entry = (++sp->cur_rx) % RX_RING_SIZE;
 	}
 
 	/* Refill the Rx ring buffers. */
-	for (; sp->dirty_rx < sp->cur_rx; sp->dirty_rx++) {
+	for (; sp->cur_rx - sp->dirty_rx > 0; sp->dirty_rx++) {
 		struct RxFD *rxf;
 		entry = sp->dirty_rx % RX_RING_SIZE;
 		if (sp->rx_skbuff[entry] == NULL) {
@@ -1252,16 +1498,15 @@
 			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
 			skb->dev = dev;
 			skb_reserve(skb, sizeof(struct RxFD));
-			rxf->rx_buf_addr = virt_to_bus(skb->tail);
+			rxf->rx_buf_addr = virt_to_le32bus(skb->tail);
 		} else {
 			rxf = sp->rx_ringp[entry];
 		}
-		rxf->status = 0xC0000001; 	/* '1' for driver use only. */
+		rxf->status = cpu_to_le32(0xC0000001); 	/* '1' for driver use only. */
 		rxf->link = 0;			/* None yet. */
-		rxf->count = 0;
-		rxf->size = PKT_BUF_SZ;
-		sp->last_rxf->link = virt_to_bus(rxf);
-		sp->last_rxf->status &= ~0xC0000000;
+		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
+		sp->last_rxf->link = virt_to_le32bus(rxf);
+		sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
 		sp->last_rxf = rxf;
 	}
 
@@ -1287,8 +1532,8 @@
 	del_timer(&sp->timer);
 
 	/* Disable interrupts, and stop the chip's Rx process. */
-	outw(INT_MASK, ioaddr + SCBCmd);
-	outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd);
+	outw(SCBMaskAll, ioaddr + SCBCmd);
+	outw(SCBMaskAll | RxAbort, ioaddr + SCBCmd);
 
 	free_irq(dev->irq, dev);
 
@@ -1297,8 +1542,12 @@
 		struct sk_buff *skb = sp->rx_skbuff[i];
 		sp->rx_skbuff[i] = 0;
 		/* Clear the Rx descriptors. */
-		if (skb)
+		if (skb) {
+#if LINUX_VERSION_CODE < 0x20100
+			skb->free = 1;
+#endif
 			dev_free_skb(skb);
+		}
 	}
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1314,22 +1563,13 @@
 	}
 
 	/* Print a few items for debugging. */
-	if (speedo_debug > 3) {
-		int phy_num = sp->phy[0] & 0x1f;
-		printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n",
-			   dev->name, sp->cur_rx);
-
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(KERN_DEBUG "  Rx ring entry %d  %8.8x.\n",
-				   i, (int)sp->rx_ringp[i]->status);
-
-		for (i = 0; i < 5; i++)
-			printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
-				   phy_num, i, mdio_read(ioaddr, phy_num, i));
-		for (i = 21; i < 26; i++)
-			printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
-				   phy_num, i, mdio_read(ioaddr, phy_num, i));
-	}
+	if (speedo_debug > 3)
+		speedo_show_state(dev);
+
+#if defined(HAS_PCI_NETIF)
+	/* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */
+	acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D2);
+#endif
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1353,22 +1593,23 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (sp->lstats.done_marker == 0xA007) {	/* Previous dump finished */
-		sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
-		sp->stats.tx_window_errors += sp->lstats.tx_late_colls;
-		sp->stats.tx_fifo_errors += sp->lstats.tx_underruns;
-		sp->stats.tx_fifo_errors += sp->lstats.tx_lost_carrier;
-		/*sp->stats.tx_deferred += sp->lstats.tx_deferred;*/
-		sp->stats.collisions += sp->lstats.tx_total_colls;
-		sp->stats.rx_crc_errors += sp->lstats.rx_crc_errs;
-		sp->stats.rx_frame_errors += sp->lstats.rx_align_errs;
-		sp->stats.rx_over_errors += sp->lstats.rx_resource_errs;
-		sp->stats.rx_fifo_errors += sp->lstats.rx_overrun_errs;
-		sp->stats.rx_length_errors += sp->lstats.rx_runt_errs;
+	/* Update only if the previous dump finished. */
+	if (sp->lstats.done_marker == le32_to_cpu(0xA007)) {
+		sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats.tx_coll16_errs);
+		sp->stats.tx_window_errors += le32_to_cpu(sp->lstats.tx_late_colls);
+		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_underruns);
+		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_lost_carrier);
+		/*sp->stats.tx_deferred += le32_to_cpu(sp->lstats.tx_deferred);*/
+		sp->stats.collisions += le32_to_cpu(sp->lstats.tx_total_colls);
+		sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats.rx_crc_errs);
+		sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats.rx_align_errs);
+		sp->stats.rx_over_errors += le32_to_cpu(sp->lstats.rx_resource_errs);
+		sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats.rx_overrun_errs);
+		sp->stats.rx_length_errors += le32_to_cpu(sp->lstats.rx_runt_errs);
 		sp->lstats.done_marker = 0x0000;
 		if (dev->start) {
 			wait_for_cmd_done(ioaddr + SCBCmd);
-			outw(CU_DUMPSTATS, ioaddr + SCBCmd);
+			outw(CUDumpStats, ioaddr + SCBCmd);
 		}
 	}
 	return &sp->stats;
@@ -1380,17 +1621,32 @@
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
+#if defined(HAS_PCI_NETIF)
+	int saved_acpi;
+#endif
 
     switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+#if defined(HAS_PCI_NETIF)
+		saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
 		data[3] = mdio_read(ioaddr, data[0], data[1]);
+		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
+#else
+		data[3] = mdio_read(ioaddr, data[0], data[1]);
+#endif
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
+#if defined(HAS_PCI_NETIF)
+		saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
+		mdio_write(ioaddr, data[0], data[1], data[2]);
+		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
+#else
 		mdio_write(ioaddr, data[0], data[1], data[2]);
+#endif
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -1406,8 +1662,7 @@
    loaded the link -- we convert the current command block, normally a Tx
    command, into a no-op and link it to the new command.
 */
-static void
-set_rx_mode(struct device *dev)
+static void set_rx_mode(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
@@ -1440,9 +1695,9 @@
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 
 		sp->tx_skbuff[entry] = 0;			/* Redundant. */
-		sp->tx_ring[entry].status = (CmdSuspend | CmdConfigure) << 16;
+		sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure);
 		sp->tx_ring[entry].link =
-			virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
+			virt_to_le32bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
 		config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
 		/* Construct a full CmdConfig frame. */
 		memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
@@ -1450,6 +1705,7 @@
 		config_cmd_data[4] = rxdmacount;
 		config_cmd_data[5] = txdmacount + 0x80;
 		config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
+		config_cmd_data[19] = sp->flow_ctrl ? 0xBD : 0x80;
 		config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
 		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
@@ -1457,11 +1713,9 @@
 			config_cmd_data[8] = 0;
 		}
 		/* Trigger the command unit resume. */
-		last_cmd->command &= ~CmdSuspend;
-
 		wait_for_cmd_done(ioaddr + SCBCmd);
-		outw(CU_RESUME, ioaddr + SCBCmd);
-
+		clear_suspend(last_cmd);
+		outw(CUResume, ioaddr + SCBCmd);
 		spin_unlock_irqrestore(&sp->lock, flags);
 	}
 
@@ -1477,12 +1731,12 @@
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 
 		sp->tx_skbuff[entry] = 0;
-		sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16;
+		sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList);
 		sp->tx_ring[entry].link =
-			virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
+			virt_to_le32bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
 		sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
 		setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
-		*setup_params++ = dev->mc_count*6;
+		*setup_params++ = cpu_to_le16(dev->mc_count*6);
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
 			 i++, mclist = mclist->next) {
@@ -1492,12 +1746,10 @@
 			*setup_params++ = *eaddrs++;
 		}
 
-		last_cmd->command &= ~CmdSuspend;
-
-		/* Immediately trigger the command unit resume. */
 		wait_for_cmd_done(ioaddr + SCBCmd);
-		outw(CU_RESUME, ioaddr + SCBCmd);
-
+		clear_suspend(last_cmd);
+		/* Immediately trigger the command unit resume. */
+		outw(CUResume, ioaddr + SCBCmd);
 		spin_unlock_irqrestore(&sp->lock, flags);
 	} else if (new_rx_mode == 0) {
 		struct dev_mc_list *mclist;
@@ -1521,7 +1773,7 @@
 			}
 		}
 		/* If we are busy, someone might be quickly adding to the MC list.
-		   Try again later when the list changes stop. */
+		   Try again later when the list updates stop. */
 		if (sp->mc_setup_busy) {
 			sp->rx_mode = -1;
 			return;
@@ -1532,11 +1784,11 @@
 			printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
 				   "%d bytes.\n",
 				   dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
-		mc_setup_frm->status = 0;
-		mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
+		mc_setup_frm->cmd_status =
+			cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
 		/* Link set below. */
 		setup_params = (u16 *)&mc_setup_frm->params;
-		*setup_params++ = dev->mc_count*6;
+		*setup_params++ = cpu_to_le16(dev->mc_count*6);
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
 			 i++, mclist = mclist->next) {
@@ -1548,7 +1800,6 @@
 
 		/* Disable interrupts while playing with the Tx Cmd list. */
 		spin_lock_irqsave(&sp->lock, flags);
-
 		entry = sp->cur_tx++ % TX_RING_SIZE;
 		last_cmd = sp->last_cmd;
 		sp->last_cmd = mc_setup_frm;
@@ -1556,21 +1807,18 @@
 
 		/* Change the command to a NoOp, pointing to the CmdMulti command. */
 		sp->tx_skbuff[entry] = 0;
-		sp->tx_ring[entry].status = CmdNOp << 16;
-		sp->tx_ring[entry].link = virt_to_bus(mc_setup_frm);
+		sp->tx_ring[entry].status = cpu_to_le32(CmdNOp);
+		sp->tx_ring[entry].link = virt_to_le32bus(mc_setup_frm);
 
 		/* Set the link in the setup frame. */
 		mc_setup_frm->link =
-			virt_to_bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
-
-		last_cmd->command &= ~CmdSuspend;
+			virt_to_le32bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
 
-		/* Immediately trigger the command unit resume. */
 		wait_for_cmd_done(ioaddr + SCBCmd);
-		outw(CU_RESUME, ioaddr + SCBCmd);
-
+		clear_suspend(last_cmd);
+		/* Immediately trigger the command unit resume. */
+		outw(CUResume, ioaddr + SCBCmd);
 		spin_unlock_irqrestore(&sp->lock, flags);
-
 		if (speedo_debug > 5)
 			printk(" CmdMCSetup frame length %d in entry %d.\n",
 				   dev->mc_count, entry);
@@ -1581,42 +1829,64 @@
 
 #ifdef MODULE
 
-int
-init_module(void)
+int init_module(void)
 {
 	int cards_found;
 
 	if (debug >= 0)
 		speedo_debug = debug;
+	/* Always emit the version message. */
 	if (speedo_debug)
 		printk(KERN_INFO "%s", version);
 
-	root_speedo_dev = NULL;
+#if defined(HAS_PCI_NETIF)
+	cards_found = netif_pci_probe(pci_tbl, NULL);
+	if (cards_found < 0)
+		printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
+	return cards_found;
+#else
 	cards_found = eepro100_init(NULL);
-	return cards_found ? 0 : -ENODEV;
+	if (cards_found <= 0) {
+		printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
+		return -ENODEV;
+	}
+#endif
+	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	struct device *next_dev;
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_speedo_dev) {
-		next_dev = ((struct speedo_private *)root_speedo_dev->priv)->next_module;
+		struct speedo_private *sp = (void *)root_speedo_dev->priv;
 		unregister_netdev(root_speedo_dev);
+#ifdef USE_IO
 		release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
+#else
+		iounmap((char *)root_speedo_dev->base_addr);
+#endif
+#if defined(HAS_PCI_NETIF)
+		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, sp->acpi_pwr);
+#endif
+		next_dev = sp->next_module;
+		if (sp->priv_addr)
+			kfree(sp->priv_addr);
 		kfree(root_speedo_dev);
 		root_speedo_dev = next_dev;
 	}
 }
+
 #else   /* not MODULE */
+
 int eepro100_probe(struct device *dev)
 {
 	int cards_found = 0;
 
 	cards_found = eepro100_init(dev);
 
+	/* Only emit the version if the driver is being used. */
 	if (speedo_debug > 0  &&  cards_found)
 		printk(version);
 
@@ -1626,8 +1896,9 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` `[ -f ./pci-netif.h ] && echo -DHAS_PCI_NETIF`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c eepro100.c"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.3.12/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.3.12/linux/drivers/net/epic100.c	Thu Apr 29 11:53:41 1999
+++ linux/drivers/net/epic100.c	Thu Aug  5 15:04:52 1999
@@ -285,7 +285,7 @@
 	struct pci_dev *pcidev = NULL;
 	while ((pcidev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcidev))
 			!= NULL) {
-		long pci_ioaddr = pcidev->base_address[0] & ~3;
+		long pci_ioaddr = pcidev->resource[0].start;
 		int vendor = pcidev->vendor;
 		int device = pcidev->device;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in
--- v2.3.12/linux/drivers/net/hamradio/Config.in	Tue Dec 29 11:30:56 1998
+++ linux/drivers/net/hamradio/Config.in	Thu Aug  5 14:35:52 1999
@@ -16,7 +16,7 @@
 dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_PARPORT
 dep_tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP $CONFIG_PARPORT
 
-tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM
+dep_tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM $CONFIG_PARPORT
 if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
   bool '   soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
   bool '   soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
@@ -28,3 +28,5 @@
   bool '   soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
   bool '   soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
 fi
+
+tristate 'YAM driver for AX.25' CONFIG_YAM
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile
--- v2.3.12/linux/drivers/net/hamradio/Makefile	Sun Jun  7 11:13:45 1998
+++ linux/drivers/net/hamradio/Makefile	Thu Aug  5 14:35:52 1999
@@ -53,6 +53,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_YAM),y)
+L_OBJS += yam.o
+else
+  ifeq ($(CONFIG_YAM),m)
+  M_OBJS += yam.o
+  endif
+endif
+
 ifeq ($(CONFIG_PI),y)
 L_OBJS += pi2.o
 else
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.3.12/linux/drivers/net/hamradio/baycom_epp.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/net/hamradio/baycom_epp.c	Wed Aug  4 09:27:34 1999
@@ -31,6 +31,8 @@
  *                  Integrated FPGA EPP modem configuration routines
  *   0.3  11.05.98  Took FPGA config out and moved it into a separate program
  *   0.4  26.07.99  Adapted to new lowlevel parport driver interface
+ *   0.5  03.08.99  adapt to Linus' new __setup/__initcall
+ *                  removed some pre-2.2 kernel compatibility cruft
  *
  */
 
@@ -39,25 +41,13 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/socket.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
+#include <linux/init.h>
 #include <linux/string.h>
+#include <linux/tqueue.h>
+#include <linux/fs.h>
 #include <linux/parport.h>
-#include <linux/bitops.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
+#include <asm/uaccess.h>
 #include <linux/if_arp.h>
-//#include <net/ax25dev.h>
-#include <linux/kmod.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
 #include <linux/soundmodem.h>
@@ -71,56 +61,6 @@
 
 /* --------------------------------------------------------------------- */
 
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
 #define BAYCOM_DEBUG
 #define BAYCOM_MAGIC 19730510
 
@@ -148,8 +88,8 @@
 /* --------------------------------------------------------------------- */
 
 static const char bc_drvname[] = "baycom_epp";
-static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_epp: version 0.4 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-1999 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_epp: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
@@ -157,11 +97,6 @@
 
 static struct device baycom_device[NR_PORTS];
 
-static struct {
-	const char *mode;
-	int iobase;
-} baycom_ports[NR_PORTS] = { { NULL, 0 }, };
-
 /* --------------------------------------------------------------------- */
 
 /* EPP status register */
@@ -1477,7 +1412,18 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int baycom_epp_init(void))
+/*
+ * command line settable parameters
+ */
+static const char *mode[NR_PORTS] = { "", };
+static int iobase[NR_PORTS] = { 0x378, };
+
+/* --------------------------------------------------------------------- */
+
+#ifndef MODULE
+static
+#endif
+int __init init_module(void)
 {
 	struct device *dev;
 	int i, found = 0;
@@ -1490,10 +1436,10 @@
 	 */
 	for (i = 0; i < NR_PORTS; i++) {
 		dev = baycom_device+i;
-		if (!baycom_ports[i].mode)
+		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
-			baycom_ports[i].iobase = 0;
+			iobase[i] = 0;
 		memset(dev, 0, sizeof(struct device));
 		if (!(bc = dev->priv = kmalloc(sizeof(struct baycom_state), GFP_KERNEL)))
 			return -ENOMEM;
@@ -1513,7 +1459,7 @@
 		dev->init = baycom_probe;
 		dev->start = 0;
 		dev->tbusy = 1;
-		dev->base_addr = baycom_ports[i].iobase;
+		dev->base_addr = iobase[i];
 		dev->irq = 0;
 		dev->dma = 0;
 		if (register_netdev(dev)) {
@@ -1521,7 +1467,7 @@
 			kfree(dev->priv);
 			return -ENXIO;
 		}
-		if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
+		if (set_hw && baycom_setmode(bc, mode[i]))
 			set_hw = 0;
 		found++;
 	}
@@ -1534,39 +1480,14 @@
 
 #ifdef MODULE
 
-/*
- * command line settable parameters
- */
-static const char *mode[NR_PORTS] = { "epp", };
-static int iobase[NR_PORTS] = { 0x378, };
-
-#if LINUX_VERSION_CODE >= 0x20115
-
-MODULE_PARM(mode, "s");
-MODULE_PARM_DESC(mode, "baycom operating mode; epp");
-MODULE_PARM(iobase, "i");
+MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");
+MODULE_PARM_DESC(mode, "baycom operating mode");
+MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(iobase, "baycom io base address");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("Baycom epp amateur radio modem driver");
 
-#endif
-
-__initfunc(int init_module(void))
-{
-        int i;
-
-        for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {
-                baycom_ports[i].mode = mode[i];
-                baycom_ports[i].iobase = iobase[i];
-        }
-        if (i < NR_PORTS-1)
-                baycom_ports[i+1].mode = NULL;
-        return baycom_epp_init();
-}
-
-/* --------------------------------------------------------------------- */
-
 void cleanup_module(void)
 {
 	struct device *dev;
@@ -1587,27 +1508,30 @@
 }
 
 #else /* MODULE */
-/* --------------------------------------------------------------------- */
+
 /*
- * format: baycom=io,mode
- * mode: epp
+ * format: baycom_epp=io,mode
+ * mode: fpga config options
  */
 
-__initfunc(void baycom_epp_setup(char *str, int *ints))
+static int __init baycom_epp_setup(char *str)
 {
-	int i;
+        static unsigned __initdata nr_dev = 0;
+	int ints[11];
 
-	for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
-	if ((i >= NR_PORTS) || (ints[0] < 1)) {
-		printk(KERN_INFO "%s: too many or invalid interface "
-		       "specifications\n", bc_drvname);
-		return;
-	}
-	baycom_ports[i].mode = str;
-	baycom_ports[i].iobase = ints[1];
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
+        if (nr_dev >= NR_PORTS)
+                return 0;
+	str = get_options(str, ints);
+	if (ints[0] < 1)
+		return 0;
+	mode[nr_dev] = str;
+	iobase[nr_dev] = ints[1];
+	nr_dev++;
+	return 1;
 }
+
+__setup("baycom_epp=", baycom_epp_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c
--- v2.3.12/linux/drivers/net/hamradio/baycom_par.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hamradio/baycom_par.c	Fri Aug  6 11:16:54 1999
@@ -3,7 +3,7 @@
 /*
  *	baycom_par.c  -- baycom par96 and picpar radio modem driver.
  *
- *	Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 1996-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	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
@@ -58,10 +58,13 @@
  *   0.3  26.04.97  init code/data tagged
  *   0.4  08.07.97  alternative ser12 decoding algorithm (uses delta CTS ints)
  *   0.5  11.11.97  split into separate files for ser12/par96
+ *   0.6  03.08.99  adapt to Linus' new __setup/__initcall
+ *                  removed some pre-2.2 kernel compatibility cruft
  */
 
 /*****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -74,6 +77,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
@@ -83,56 +88,6 @@
 
 /* --------------------------------------------------------------------- */
 
-/*
- * currently this module is supposed to support both module styles, i.e.
- * the old one present up to about 2.1.9, and the new one functioning
- * starting with 2.1.21. The reason is I have a kit allowing to compile
- * this module also under 2.0.x which was requested by several people.
- * This will go in 2.2
- */
-#include <linux/version.h>
-
-#if LINUX_VERSION_CODE >= 0x20100
-#include <asm/uaccess.h>
-#else
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-#undef put_user
-#undef get_user
-
-#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
-#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-
-extern __inline__ int copy_from_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_READ, from, n);
-        if (i)
-                return i;
-        memcpy_fromfs(to, from, n);
-        return 0;
-}
-
-extern __inline__ int copy_to_user(void *to, const void *from, unsigned long n)
-{
-        int i = verify_area(VERIFY_WRITE, to, n);
-        if (i)
-                return i;
-        memcpy_tofs(to, from, n);
-        return 0;
-}
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#define __initfunc(x) x
-#endif
-
-/* --------------------------------------------------------------------- */
-
 #define BAYCOM_DEBUG
 
 /*
@@ -143,8 +98,8 @@
 /* --------------------------------------------------------------------- */
 
 static const char bc_drvname[] = "baycom_par";
-static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_par: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_par: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
@@ -152,11 +107,6 @@
 
 static struct device baycom_device[NR_PORTS];
 
-static struct {
-	const char *mode;
-	int iobase;
-} baycom_ports[NR_PORTS] = { { NULL, 0 }, };
-
 /* --------------------------------------------------------------------- */
 
 #define SER12_EXTENT 8
@@ -533,14 +483,24 @@
 
 /* --------------------------------------------------------------------- */
 
-int __init baycom_par_init(void)
+/*
+ * command line settable parameters
+ */
+static const char *mode[NR_PORTS] = { "picpar", };
+static int iobase[NR_PORTS] = { 0x378, };
+
+/* --------------------------------------------------------------------- */
+
+#ifndef MODULE
+static
+#endif
+int __init init_module(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
 	struct baycom_state *bc;
 	char ifname[HDLCDRV_IFNAMELEN];
 
-
 	printk(bc_drvinfo);
 	/*
 	 * register net devices
@@ -549,16 +509,15 @@
 		struct device *dev = baycom_device+i;
 		sprintf(ifname, "bcp%d", i);
 
-		if (!baycom_ports[i].mode)
+		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
-			baycom_ports[i].iobase = 0;
-		j = hdlcdrv_register_hdlcdrv(dev, &par96_ops,
-					     sizeof(struct baycom_state),
-					     ifname, baycom_ports[i].iobase, 0, 0);
+			iobase[i] = 0;
+		j = hdlcdrv_register_hdlcdrv(dev, &par96_ops, sizeof(struct baycom_state),
+					     ifname, iobase[i], 0, 0);
 		if (!j) {
 			bc = (struct baycom_state *)dev->priv;
-			if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
+			if (set_hw && baycom_setmode(bc, mode[i]))
 				set_hw = 0;
 			found++;
 		} else {
@@ -575,14 +534,6 @@
 
 #ifdef MODULE
 
-/*
- * command line settable parameters
- */
-static const char *mode[NR_PORTS] = { "picpar", };
-static int iobase[NR_PORTS] = { 0x378, };
-
-#if LINUX_VERSION_CODE >= 0x20115
-
 MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");
 MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar");
 MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");
@@ -591,23 +542,6 @@
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver");
 
-#endif
-
-int __init init_module(void)
-{
-	int i;
-
-	for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {
-		baycom_ports[i].mode = mode[i];
-		baycom_ports[i].iobase = iobase[i];
-	}
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
-	return baycom_par_init();
-}
-
-/* --------------------------------------------------------------------- */
-
 void cleanup_module(void)
 {
 	int i;
@@ -627,27 +561,30 @@
 }
 
 #else /* MODULE */
-/* --------------------------------------------------------------------- */
+
 /*
  * format: baycom_par=io,mode
  * mode: par96,picpar
  */
 
-void __init baycom_par_setup(char *str, int *ints)
+static int __init baycom_par_setup(char *str)
 {
-	int i;
+        static unsigned __initdata nr_dev = 0;
+	int ints[11];
 
-	for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
-	if ((i >= NR_PORTS) || (ints[0] < 1)) {
-		printk(KERN_INFO "%s: too many or invalid interface "
-		       "specifications\n", bc_drvname);
-		return;
-	}
-	baycom_ports[i].mode = str;
-	baycom_ports[i].iobase = ints[1];
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
+        if (nr_dev >= NR_PORTS)
+                return 0;
+        str = get_options(str, ints);
+        if (ints[0] < 1)
+                return 0;
+        mode[nr_dev] = str;
+        iobase[nr_dev] = ints[1];
+	nr_dev++;
+	return 1;
 }
+
+__setup("baycom_par=", baycom_par_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c
--- v2.3.12/linux/drivers/net/hamradio/baycom_ser_fdx.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hamradio/baycom_ser_fdx.c	Fri Aug  6 11:16:54 1999
@@ -3,7 +3,7 @@
 /*
  *	baycom_ser_fdx.c  -- baycom ser12 fullduplex radio modem driver.
  *
- *	Copyright (C) 1997-1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 1996-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	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
@@ -60,30 +60,20 @@
  *   0.6  24.01.98  Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
  *                  reduced interrupt load in transmit case
  *                  reworked receiver
+ *   0.7  03.08.99  adapt to Linus' new __setup/__initcall
  */
 
 /*****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/in.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
-#include <linux/version.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -97,8 +87,8 @@
 /* --------------------------------------------------------------------- */
 
 static const char bc_drvname[] = "baycom_ser_fdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1997-1998 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_fdx: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_ser_fdx: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
@@ -106,11 +96,6 @@
 
 static struct device baycom_device[NR_PORTS];
 
-static struct {
-	char *mode;
-	int iobase, irq, baud;
-} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, };
-
 /* --------------------------------------------------------------------- */
 
 #define RBR(iobase) (iobase+0)
@@ -605,7 +590,20 @@
 
 /* --------------------------------------------------------------------- */
 
-int __init baycom_ser_fdx_init(void)
+/*
+ * command line settable parameters
+ */
+static char *mode[NR_PORTS] = { "ser12*", };
+static int iobase[NR_PORTS] = { 0x3f8, };
+static int irq[NR_PORTS] = { 4, };
+static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };
+
+/* --------------------------------------------------------------------- */
+
+#ifndef MODULE
+static
+#endif
+int __init init_module(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -621,19 +619,17 @@
 		struct device *dev = baycom_device+i;
 		sprintf(ifname, "bcsf%d", i);
 
-		if (!baycom_ports[i].mode)
+		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
-			baycom_ports[i].iobase = baycom_ports[i].irq = 0;
-		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops,
-					     sizeof(struct baycom_state),
-					     ifname, baycom_ports[i].iobase,
-					     baycom_ports[i].irq, 0);
+			iobase[i] = irq[i] = 0;
+		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, sizeof(struct baycom_state),
+					     ifname, iobase[i], irq[i], 0);
 		if (!j) {
 			bc = (struct baycom_state *)dev->priv;
-			if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
+			if (set_hw && baycom_setmode(bc, mode[i]))
 				set_hw = 0;
-			bc->baud = baycom_ports[i].baud;
+			bc->baud = baud[i];
 			found++;
 		} else {
 			printk(KERN_WARNING "%s: cannot register net device\n",
@@ -649,16 +645,6 @@
 
 #ifdef MODULE
 
-/*
- * command line settable parameters
- */
-static char *mode[NR_PORTS] = { "ser12*", };
-static int iobase[NR_PORTS] = { 0x3f8, };
-static int irq[NR_PORTS] = { 4, };
-static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };
-
-#if LINUX_VERSION_CODE >= 0x20115
-
 MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");
 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
 MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");
@@ -671,25 +657,6 @@
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");
 
-#endif
-
-int __init init_module(void)
-{
-	int i;
-
-	for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {
-		baycom_ports[i].mode = mode[i];
-		baycom_ports[i].iobase = iobase[i];
-		baycom_ports[i].irq = irq[i];
-		baycom_ports[i].baud = baud[i];
-	}
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
-	return baycom_ser_fdx_init();
-}
-
-/* --------------------------------------------------------------------- */
-
 void cleanup_module(void)
 {
 	int i;
@@ -709,33 +676,34 @@
 }
 
 #else /* MODULE */
-/* --------------------------------------------------------------------- */
+
 /*
  * format: baycom_ser_fdx=io,irq,mode
  * mode: [*]
  * * indicates sofware DCD
  */
 
-void __init baycom_ser_fdx_setup(char *str, int *ints)
+static int __init baycom_ser_fdx_setup(char *str)
 {
-	int i;
+        static unsigned __initdata nr_dev = 0;
+        int ints[11];
 
-	for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
-	if ((i >= NR_PORTS) || (ints[0] < 2)) {
-		printk(KERN_INFO "%s: too many or invalid interface "
-		       "specifications\n", bc_drvname);
-		return;
-	}
-	baycom_ports[i].mode = str;
-	baycom_ports[i].iobase = ints[1];
-	baycom_ports[i].irq = ints[2];
+        if (nr_dev >= NR_PORTS)
+                return 0;
+        str = get_options(str, ints);
+        if (ints[0] < 2)
+                return 0;
+        mode[nr_dev] = str;
+        iobase[nr_dev] = ints[1];
+        irq[nr_dev] = ints[2];
 	if (ints[0] >= 3)
-		baycom_ports[i].baud = ints[3];
-	else
-		baycom_ports[i].baud = 1200;
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
+		baud[nr_dev] = ints[3];
+	nr_dev++;
+	return 1;
 }
+
+__setup("baycom_ser_fdx=", baycom_ser_fdx_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c
--- v2.3.12/linux/drivers/net/hamradio/baycom_ser_hdx.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hamradio/baycom_ser_hdx.c	Fri Aug  6 11:16:54 1999
@@ -3,7 +3,7 @@
 /*
  *	baycom_ser_hdx.c  -- baycom ser12 halfduplex radio modem driver.
  *
- *	Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 1996-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	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
@@ -49,30 +49,20 @@
  *   0.4  08.07.97  alternative ser12 decoding algorithm (uses delta CTS ints)
  *   0.5  11.11.97  ser12/par96 split into separate files
  *   0.6  14.04.98  cleanups
+ *   0.7  03.08.99  adapt to Linus' new __setup/__initcall
  */
 
 /*****************************************************************************/
 
+#include <linux/version.h>
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/in.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
-#include <linux/version.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -86,8 +76,8 @@
 /* --------------------------------------------------------------------- */
 
 static const char bc_drvname[] = "baycom_ser_hdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1997-1998 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_hdx: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
+static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom_ser_hdx: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
@@ -95,11 +85,6 @@
 
 static struct device baycom_device[NR_PORTS];
 
-static struct {
-	char *mode;
-	int iobase, irq;
-} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, };
-
 /* --------------------------------------------------------------------- */
 
 #define RBR(iobase) (iobase+0)
@@ -643,7 +628,19 @@
 
 /* --------------------------------------------------------------------- */
 
-int __init baycom_ser_hdx_init(void)
+/*
+ * command line settable parameters
+ */
+static char *mode[NR_PORTS] = { "ser12*", };
+static int iobase[NR_PORTS] = { 0x3f8, };
+static int irq[NR_PORTS] = { 4, };
+
+/* --------------------------------------------------------------------- */
+
+#ifndef MODULE
+static
+#endif
+int __init init_module(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -659,17 +656,15 @@
 		struct device *dev = baycom_device+i;
 		sprintf(ifname, "bcsh%d", i);
 
-		if (!baycom_ports[i].mode)
+		if (!mode[i])
 			set_hw = 0;
 		if (!set_hw)
-			baycom_ports[i].iobase = baycom_ports[i].irq = 0;
-		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops,
-					     sizeof(struct baycom_state),
-					     ifname, baycom_ports[i].iobase,
-					     baycom_ports[i].irq, 0);
+			iobase[i] = irq[i] = 0;
+		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, sizeof(struct baycom_state),
+					     ifname, iobase[i], irq[i], 0);
 		if (!j) {
 			bc = (struct baycom_state *)dev->priv;
-			if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
+			if (set_hw && baycom_setmode(bc, mode[i]))
 				set_hw = 0;
 			found++;
 		} else {
@@ -686,15 +681,6 @@
 
 #ifdef MODULE
 
-/*
- * command line settable parameters
- */
-static char *mode[NR_PORTS] = { "ser12*", };
-static int iobase[NR_PORTS] = { 0x3f8, };
-static int irq[NR_PORTS] = { 4, };
-
-#if LINUX_VERSION_CODE >= 0x20115
-
 MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");
 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
 MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");
@@ -705,24 +691,6 @@
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver");
 
-#endif
-
-int __init init_module(void)
-{
-	int i;
-
-	for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {
-		baycom_ports[i].mode = mode[i];
-		baycom_ports[i].iobase = iobase[i];
-		baycom_ports[i].irq = irq[i];
-	}
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
-	return baycom_ser_hdx_init();
-}
-
-/* --------------------------------------------------------------------- */
-
 void cleanup_module(void)
 {
 	int i;
@@ -742,29 +710,32 @@
 }
 
 #else /* MODULE */
-/* --------------------------------------------------------------------- */
+
 /*
- * format: baycom_ser_=io,irq,mode
+ * format: baycom_ser_hdx=io,irq,mode
  * mode: [*]
  * * indicates sofware DCD
  */
 
-void __init baycom_ser_hdx_setup(char *str, int *ints)
+static int __init baycom_ser_hdx_setup(char *str)
 {
-	int i;
+        static unsigned __initdata nr_dev = 0;
+	int ints[11];
 
-	for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
-	if ((i >= NR_PORTS) || (ints[0] < 2)) {
-		printk(KERN_INFO "%s: too many or invalid interface "
-		       "specifications\n", bc_drvname);
-		return;
-	}
-	baycom_ports[i].mode = str;
-	baycom_ports[i].iobase = ints[1];
-	baycom_ports[i].irq = ints[2];
-	if (i < NR_PORTS-1)
-		baycom_ports[i+1].mode = NULL;
+        if (nr_dev >= NR_PORTS)
+                return 0;
+	str = get_options(str, ints);
+	if (ints[0] < 2)
+		return 0;
+	mode[nr_dev] = str;
+	iobase[nr_dev] = ints[1];
+	irq[nr_dev] = ints[2];
+	nr_dev++;
+	return 1;
 }
+
+__setup("baycom_ser_hdx=", baycom_ser_hdx_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c
--- v2.3.12/linux/drivers/net/hamradio/hdlcdrv.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hamradio/hdlcdrv.c	Wed Aug  4 09:27:34 1999
@@ -3,7 +3,7 @@
 /*
  *	hdlcdrv.c  -- HDLC packet radio network driver.
  *
- *	Copyright (C) 1996-1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 1996-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	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
@@ -36,6 +36,7 @@
  *   0.5  30.07.97  made HDLC buffers bigger (solves a problem with the
  *                  soundmodem driver)
  *   0.6  05.04.98  add spinlocks
+ *   0.7  03.08.99  removed some old compatibility cruft
  */
 
 /*****************************************************************************/
@@ -516,11 +517,7 @@
 
 /* --------------------------------------------------------------------- */
 
-#if LINUX_VERSION_CODE >= 0x20119
 static struct net_device_stats *hdlcdrv_get_stats(struct device *dev)
-#else
-static struct enet_statistics *hdlcdrv_get_stats(struct device *dev)
-#endif
 {
 	struct hdlcdrv_state *sm;
 
@@ -695,9 +692,6 @@
 		bi.data.ocs.ptt = hdlcdrv_ptt(s);
 		bi.data.ocs.dcd = s->hdlcrx.dcd;
 		bi.data.ocs.ptt_keyed = s->ptt_keyed;
-#if LINUX_VERSION_CODE < 0x20100
-		bi.data.ocs.stats = s->stats;
-#endif
 		break;		
 
 	case HDLCDRVCTL_CALIBRATE:
@@ -900,48 +894,25 @@
 
 /* --------------------------------------------------------------------- */
 
-#if LINUX_VERSION_CODE >= 0x20115
-
 EXPORT_SYMBOL(hdlcdrv_receiver);
 EXPORT_SYMBOL(hdlcdrv_transmitter);
 EXPORT_SYMBOL(hdlcdrv_arbitrate);
 EXPORT_SYMBOL(hdlcdrv_register_hdlcdrv);
 EXPORT_SYMBOL(hdlcdrv_unregister_hdlcdrv);
 
-#else
-
-static struct symbol_table hdlcdrv_syms = {
-#include <linux/symtab_begin.h>
-        X(hdlcdrv_receiver),
-        X(hdlcdrv_transmitter),
-        X(hdlcdrv_arbitrate),
-        X(hdlcdrv_register_hdlcdrv),
-        X(hdlcdrv_unregister_hdlcdrv),
-#include <linux/symtab_end.h>
-};
-
-#endif
-
 /* --------------------------------------------------------------------- */
 
 #ifdef MODULE
 
-#if LINUX_VERSION_CODE >= 0x20115
-
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
 
-#endif
-
 /* --------------------------------------------------------------------- */
 
 int __init init_module(void)
 {
 	printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
-	printk(KERN_INFO "hdlcdrv: version 0.6 compiled " __TIME__ " " __DATE__ "\n");
-#if LINUX_VERSION_CODE < 0x20115
-        register_symtab(&hdlcdrv_syms);
-#endif
+	printk(KERN_INFO "hdlcdrv: version 0.7 compiled " __TIME__ " " __DATE__ "\n");
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c
--- v2.3.12/linux/drivers/net/hamradio/soundmodem/sm.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hamradio/soundmodem/sm.c	Wed Aug  4 09:27:34 1999
@@ -3,7 +3,7 @@
 /*
  *	sm.c  -- soundcard radio modem driver.
  *
- *	Copyright (C) 1996-1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 1996-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	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
@@ -41,34 +41,28 @@
  *   0.6  16.04.97  init code/data tagged
  *   0.7  30.07.97  fixed halfduplex interrupt handlers/hotfix for CS423X
  *   0.8  14.04.98  cleanups
+ *   0.9  03.08.99  adapt to Linus' new __setup/__initcall
+ *                  use parport lowlevel drivers instead of directly writing to a parallel port
+ *                  removed some pre-2.2 kernel compatibility cruft
  */
 
 /*****************************************************************************/
 
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
 #include <linux/ioport.h>
-#include <linux/net.h>
-#include <linux/in.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/parport.h>
 #include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/version.h>
 #include "sm.h"
 
 /* --------------------------------------------------------------------- */
 
 /*static*/ const char sm_drvname[] = "soundmodem";
-static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1998 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.8 compiled " __TIME__ " " __DATE__ "\n";
+static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1999 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "soundmodem: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
@@ -146,17 +140,8 @@
 
 #define NR_PORTS 4
 
-/* --------------------------------------------------------------------- */
-
 static struct device sm_device[NR_PORTS];
 
-static struct {
-	char *mode;
-	int iobase, irq, dma, dma2, seriobase, pariobase, midiiobase;
-} sm_ports[NR_PORTS] = {
-	{ NULL, -1, 0, 0, 0, -1, -1, -1 },
-};
-
 /* --------------------------------------------------------------------- */
 
 #define UART_RBR(iobase) (iobase+0)
@@ -174,13 +159,6 @@
 
 #define SER_EXTENT 8
 
-#define LPT_DATA(iobase)    (iobase+0)
-#define LPT_STATUS(iobase)  (iobase+1)
-#define LPT_CONTROL(iobase) (iobase+2)
-#define LPT_IRQ_ENABLE      0x10
-
-#define LPT_EXTENT 3
-
 #define MIDI_DATA(iobase)     (iobase)
 #define MIDI_STATUS(iobase)   (iobase+1)
 #define MIDI_READ_FULL 0x80   /* attention: negative logic!! */
@@ -202,47 +180,10 @@
 #define SP_PAR  2
 #define SP_MIDI 4
 
-/* --------------------------------------------------------------------- */
 /*
  * ===================== port checking routines ========================
  */
 
-/*
- * returns 0 if ok and != 0 on error;
- * the same behaviour as par96_check_lpt in baycom.c
- */
-
-/*
- * returns 0 if ok and != 0 on error;
- * the same behaviour as par96_check_lpt in baycom.c
- */
-
-static int check_lpt(unsigned int iobase)
-{
-	unsigned char b1,b2;
-	int i;
-
-	if (iobase <= 0 || iobase > 0x1000-LPT_EXTENT)
-		return 0;
-	if (check_region(iobase, LPT_EXTENT))
-		return 0;
-	b1 = inb(LPT_DATA(iobase));
-	b2 = inb(LPT_CONTROL(iobase));
-	outb(0xaa, LPT_DATA(iobase));
-	i = inb(LPT_DATA(iobase)) == 0xaa;
-	outb(0x55, LPT_DATA(iobase));
-	i &= inb(LPT_DATA(iobase)) == 0x55;
-	outb(0x0a, LPT_CONTROL(iobase));
-	i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a;
-	outb(0x05, LPT_CONTROL(iobase));
-	i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05;
-	outb(b1, LPT_DATA(iobase));
-	outb(b2, LPT_CONTROL(iobase));
-	return !i;
-}
-
-/* --------------------------------------------------------------------- */
-
 enum uart { c_uart_unknown, c_uart_8250,
 	c_uart_16450, c_uart_16550, c_uart_16550A};
 static const char *uart_str[] =
@@ -326,12 +267,10 @@
 		outb(dcd | (ptt << 1), UART_MCR(sm->hdrv.ptt_out.seriobase));
 		outb(0x40 & (-ptt), UART_LCR(sm->hdrv.ptt_out.seriobase));
 	}
-	if (sm->hdrv.ptt_out.flags & SP_PAR) {
-		outb(ptt | (dcd << 1), LPT_DATA(sm->hdrv.ptt_out.pariobase));
-	}
-	if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv)) {
+	if (sm->hdrv.ptt_out.flags & SP_PAR && sm->pardev && sm->pardev->port)
+		parport_write_data(sm->pardev->port, ptt | (dcd << 1));
+	if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv))
 		outb(0, MIDI_DATA(sm->hdrv.ptt_out.midiiobase));
-	}
 }
 
 /* --------------------------------------------------------------------- */
@@ -339,6 +278,7 @@
 static void sm_output_open(struct sm_state *sm)
 {
 	enum uart u = c_uart_unknown;
+	struct parport *pp = NULL;
 
 	sm->hdrv.ptt_out.flags = 0;
 	if (sm->hdrv.ptt_out.seriobase > 0 &&
@@ -353,11 +293,27 @@
 		outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */
 		/* LCR and MCR set by output_status */
 	}
-	if (sm->hdrv.ptt_out.pariobase > 0 &&
-	    sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT &&
-	    !check_lpt(sm->hdrv.ptt_out.pariobase)) {
-		sm->hdrv.ptt_out.flags |= SP_PAR;
-		request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt");
+	sm->pardev = NULL;
+	if (sm->hdrv.ptt_out.pariobase > 0) {
+		pp = parport_enumerate();
+		while (pp && pp->base != sm->hdrv.ptt_out.pariobase) 
+			pp = pp->next;
+		if (!pp)
+			printk(KERN_WARNING "%s: parport at address 0x%x not found\n", sm_drvname, sm->hdrv.ptt_out.pariobase);
+		else {
+			sm->pardev = parport_register_device(pp, sm->hdrv.ifname, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+			if (!sm->pardev) {
+				pp = NULL;
+				printk(KERN_WARNING "%s: cannot register parport device (address 0x%x)\n", sm_drvname, sm->hdrv.ptt_out.pariobase);
+			} else {
+				if (parport_claim(sm->pardev)) {
+					parport_unregister_device(sm->pardev);
+					sm->pardev = NULL;
+					printk(KERN_WARNING "%s: cannot claim parport at address 0x%x\n", sm_drvname, sm->hdrv.ptt_out.pariobase);
+				} else
+					sm->hdrv.ptt_out.flags |= SP_PAR;
+			}
+		}
 	}
 	if (sm->hdrv.ptt_out.midiiobase > 0 &&
 	    sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT &&
@@ -390,8 +346,10 @@
 	sm_output_status(sm);
 	if (sm->hdrv.ptt_out.flags & SP_SER)
 		release_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT);
-       	if (sm->hdrv.ptt_out.flags & SP_PAR)
-		release_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT);
+       	if (sm->hdrv.ptt_out.flags & SP_PAR && sm->pardev) {
+		        parport_release(sm->pardev);
+			parport_unregister_device(sm->pardev);
+	}
        	if (sm->hdrv.ptt_out.flags & SP_MIDI)
 		release_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT);
 	sm->hdrv.ptt_out.flags = 0;
@@ -639,11 +597,24 @@
 
 /* --------------------------------------------------------------------- */
 
-#ifdef MODULE
-static int __init sm_init(void)
-#else /* MODULE */
-int __init sm_init(void)
-#endif /* MODULE */
+/*
+ * command line settable parameters
+ */
+static char *mode[NR_PORTS] = { [0 ... NR_PORTS-1] = NULL };
+static int iobase[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 };
+static int irq[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 };
+static int dma[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 };
+static int dma2[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 };
+static int serio[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 };
+static int pario[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 };
+static int midiio[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 };
+
+/* --------------------------------------------------------------------- */
+
+#ifndef MODULE
+static
+#endif
+int __init init_module(void)
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -658,25 +629,39 @@
 		struct device *dev = sm_device+i;
 		sprintf(ifname, "sm%d", i);
 
-		if (!sm_ports[i].mode)
+		if (!mode[i])
 			set_hw = 0;
+		else {
+			if (!strncmp(mode[i], "sbc", 3)) {
+				if (iobase[i] == -1)
+					iobase[i] = 0x220;
+				if (irq[i] == -1)
+					irq[i] = 5;
+				if (dma[i] == -1)
+					dma[i] = 1;
+			} else {
+				if (iobase[i] == -1)
+					iobase[i] = 0x530;
+				if (irq[i] == -1)
+					irq[i] = 11;
+				if (dma[i] == -1)
+					dma[i] = 1;
+			}
+		}
 		if (!set_hw)
-			sm_ports[i].iobase = sm_ports[i].irq = 0;
-		j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state),
-					     ifname, sm_ports[i].iobase,
-					     sm_ports[i].irq, sm_ports[i].dma);
+			iobase[i] = irq[i] = 0;
+		j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), ifname, iobase[i], irq[i], dma[i]);
 		if (!j) {
 			sm = (struct sm_state *)dev->priv;
-			sm->hdrv.ptt_out.dma2 = sm_ports[i].dma2;
-			sm->hdrv.ptt_out.seriobase = sm_ports[i].seriobase;
-			sm->hdrv.ptt_out.pariobase = sm_ports[i].pariobase;
-			sm->hdrv.ptt_out.midiiobase = sm_ports[i].midiiobase;
-			if (set_hw && sethw(dev, sm, sm_ports[i].mode))
+			sm->hdrv.ptt_out.dma2 = dma2[i];
+			sm->hdrv.ptt_out.seriobase = serio[i];
+			sm->hdrv.ptt_out.pariobase = pario[i];
+			sm->hdrv.ptt_out.midiiobase = midiio[i];
+			if (set_hw && sethw(dev, sm, mode[i]))
 				set_hw = 0;
 			found++;
 		} else {
-			printk(KERN_WARNING "%s: cannot register net device\n",
-			       sm_drvname);
+			printk(KERN_WARNING "%s: cannot register net device\n", sm_drvname);
 		}
 	}
 	if (!found)
@@ -688,67 +673,26 @@
 
 #ifdef MODULE
 
-/*
- * command line settable parameters
- */
-static char *mode = NULL;
-static int iobase = -1;
-static int irq = -1;
-static int dma = -1;
-static int dma2 = -1;
-static int serio = 0;
-static int pario = 0;
-static int midiio = 0;
-
-#if LINUX_VERSION_CODE >= 0x20115
-
-MODULE_PARM(mode, "s");
+MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");
 MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600");
-MODULE_PARM(iobase, "i");
+MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(iobase, "soundmodem base address");
-MODULE_PARM(irq, "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(irq, "soundmodem interrupt");
-MODULE_PARM(dma, "i");
+MODULE_PARM(dma, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(dma, "soundmodem dma channel");
-MODULE_PARM(dma2, "i");
+MODULE_PARM(dma2, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only");
-MODULE_PARM(serio, "i");
+MODULE_PARM(serio, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port");
-MODULE_PARM(pario, "i");
+MODULE_PARM(pario, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port");
-MODULE_PARM(midiio, "i");
+MODULE_PARM(midiio, "1-" __MODULE_STRING(NR_PORTS) "i");
 MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("Soundcard amateur radio modem driver");
 
-#endif
-
-int __init init_module(void)
-{
-	if (mode) {
-		if (iobase == -1)
-			iobase = (!strncmp(mode, "sbc", 3)) ? 0x220 : 0x530;
-		if (irq == -1)
-			irq = (!strncmp(mode, "sbc", 3)) ? 5 : 11;
-		if (dma == -1)
-			dma = 1;
-	}
-	sm_ports[0].mode = mode;
-	sm_ports[0].iobase = iobase;
-	sm_ports[0].irq = irq;
-	sm_ports[0].dma = dma;
-	sm_ports[0].dma2 = dma2;
-	sm_ports[0].seriobase = serio;
-	sm_ports[0].pariobase = pario;
-	sm_ports[0].midiiobase = midiio;
-	sm_ports[1].mode = NULL;
-
-	return sm_init();
-}
-
-/* --------------------------------------------------------------------- */
-
 void cleanup_module(void)
 {
 	int i;
@@ -770,35 +714,43 @@
 }
 
 #else /* MODULE */
-/* --------------------------------------------------------------------- */
+
 /*
- * format: sm=io,irq,dma[,dma2[,serio[,pario]]],mode
+ * format: soundmodem=io,irq,dma[,dma2[,serio[,pario]]],mode
  * mode: hw:modem
  * hw: sbc, wss, wssfdx
  * modem: afsk1200, fsk9600
  */
 
-void __init sm_setup(char *str, int *ints)
+static int __init sm_setup(char *str)
 {
-	int i;
+	static unsigned __initdata nr_dev = 0;
+	int ints[11];
 
-	for (i = 0; (i < NR_PORTS) && (sm_ports[i].mode); i++);
-	if ((i >= NR_PORTS) || (ints[0] < 3)) {
-		printk(KERN_INFO "%s: too many or invalid interface "
-		       "specifications\n", sm_drvname);
-		return;
-	}
-	sm_ports[i].mode = str;
-	sm_ports[i].iobase = ints[1];
-	sm_ports[i].irq = ints[2];
-	sm_ports[i].dma = ints[3];
-	sm_ports[i].dma2 = (ints[0] >= 4) ? ints[4] : 0;
-	sm_ports[i].seriobase = (ints[0] >= 5) ? ints[5] : 0;
-	sm_ports[i].pariobase = (ints[0] >= 6) ? ints[6] : 0;
-	sm_ports[i].midiiobase = (ints[0] >= 7) ? ints[7] : 0;
-	if (i < NR_PORTS-1)
-		sm_ports[i+1].mode = NULL;
+	if (nr_dev >= NR_PORTS)
+		return 0;
+	str = get_options(str, ints);
+	mode[nr_dev] = str;
+	if (ints[0] >= 1)
+		iobase[nr_dev] = ints[1];
+	if (ints[0] >= 2)
+		irq[nr_dev] = ints[2];
+	if (ints[0] >= 3)
+		dma[nr_dev] = ints[3];
+	if (ints[0] >= 4)
+		dma2[nr_dev] = ints[4];
+	if (ints[0] >= 5)
+		serio[nr_dev] = ints[5];
+	if (ints[0] >= 6)
+		pario[nr_dev] = ints[6];
+	if (ints[0] >= 7)
+		midiio[nr_dev] = ints[7];
+	nr_dev++;
+	return 1;
 }
+
+__setup("soundmodem=", sm_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/soundmodem/sm.h linux/drivers/net/hamradio/soundmodem/sm.h
--- v2.3.12/linux/drivers/net/hamradio/soundmodem/sm.h	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hamradio/soundmodem/sm.h	Wed Aug  4 09:27:34 1999
@@ -3,7 +3,7 @@
 /*
  *	sm.h  --  soundcard radio modem driver internal header.
  *
- *	Copyright (C) 1996-1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 1996-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	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
@@ -34,6 +34,7 @@
 #include <linux/soundmodem.h>
 #include <asm/processor.h>
 #include <linux/bitops.h>
+#include <linux/parport.h>
 
 #define SM_DEBUG
 
@@ -49,6 +50,8 @@
 	const struct modem_rx_info *mode_rx;
 
 	const struct hardware_info *hwdrv;
+
+	struct pardevice *pardev;
 
 	/*
 	 * Hardware (soundcard) access routines state
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- v2.3.12/linux/drivers/net/hamradio/yam.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/yam.c	Thu Aug  5 14:35:52 1999
@@ -0,0 +1,1297 @@
+/*****************************************************************************/
+
+/*
+ *    yam.c  -- YAM radio modem driver.
+ *
+ *      Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr)
+ *      Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *      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.
+ *
+ *  Please note that the GPL allows you to use the driver, NOT the radio.
+ *  In order to use the radio, you need a license from the communications
+ *  authority of your country.
+ *
+ *
+ *  History:
+ *   0.0 F1OAT 06.06.98  Begin of work with baycom.c source code V 0.3
+ *   0.1 F1OAT 07.06.98  Add timer polling routine for channel arbitration
+ *   0.2 F6FBB 08.06.98  Added delay after FPGA programming
+ *   0.3 F6FBB 29.07.98  Delayed PTT implementation for dupmode=2
+ *   0.4 F6FBB 30.07.98  Added TxTail, Slottime and Persistance
+ *   0.5 F6FBB 01.08.98  Shared IRQs, /proc/net and network statistics
+ *   0.6 F6FBB 25.08.98  Added 1200Bds format
+ *   0.7 F6FBB 12.09.98  Added to the kernel configuration
+ *   0.8 F6FBB 14.10.98  Fixed slottime/persistance timing bug
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/if.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+/* prototypes for ax25_encapsulate and ax25_rebuild_header */
+#include <net/ax25.h>
+#endif							/* CONFIG_AX25 || CONFIG_AX25_MODULE */
+
+/* make genksyms happy */
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+
+#include <linux/yam.h>
+#include "yam9600.h"
+#include "yam1200.h"
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * currently this module is supposed to support both module styles, i.e.
+ * the old one present up to about 2.1.9, and the new one functioning
+ * starting with 2.1.21. The reason is I have a kit allowing to compile
+ * this module also under 2.0.x which was requested by several people.
+ * This will go in 2.2
+ */
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x20100
+#include <asm/uaccess.h>
+#else
+#include <asm/segment.h>
+#include <linux/mm.h>
+
+#undef put_user
+#undef get_user
+
+#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
+#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
+
+extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+{
+	int i = verify_area(VERIFY_READ, from, n);
+	if (i)
+		return i;
+	memcpy_fromfs(to, from, n);
+	return 0;
+}
+
+extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+{
+	int i = verify_area(VERIFY_WRITE, to, n);
+	if (i)
+		return i;
+	memcpy_tofs(to, from, n);
+	return 0;
+}
+#endif
+
+#if LINUX_VERSION_CODE < 0x20115
+extern __inline__ void dev_init_buffers(struct device *dev)
+{
+	int i;
+	for (i = 0; i < DEV_NUMBUFFS; i++) {
+		skb_queue_head_init(&dev->buffs[i]);
+	}
+}
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static const char yam_drvname[] = "yam";
+static const char yam_drvinfo[] = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
+
+/* --------------------------------------------------------------------- */
+
+#define YAM_9600	1
+#define YAM_1200	2
+
+#define NR_PORTS 	4
+#define YAM_MAGIC	0xF10A7654
+
+/* Transmitter states */
+
+#define TX_OFF  	0
+#define TX_HEAD		1
+#define TX_DATA  	2
+#define TX_CRC1  	3
+#define TX_CRC2  	4
+#define TX_TAIL  	5
+
+#define YAM_MAX_FRAME	1024
+
+#define DEFAULT_BITRATE	9600	/* bps */
+#define DEFAULT_HOLDD   10		/* sec */
+#define DEFAULT_TXD	    300		/* ms */
+#define DEFAULT_TXTAIL  10		/* ms */
+#define DEFAULT_SLOT    100		/* ms */
+#define DEFAULT_PERS    64		/* 0->255 */
+
+struct yam_port {
+	int magic;
+	int bitrate;
+	int baudrate;
+	int iobase;
+	int irq;
+	int dupmode;
+	char name[16];
+
+	struct device dev;
+
+	/* Stats section */
+
+#if LINUX_VERSION_CODE < 0x20119
+	struct enet_statistics stats;
+#else
+	struct net_device_stats stats;
+#endif
+	int nb_rxint;
+	int nb_mdint;
+
+	/* Parameters section */
+
+	int txd;					/* tx delay */
+	int holdd;					/* duplex ptt delay */
+	int txtail;					/* txtail delay */
+	int slot;					/* slottime */
+	int pers;					/* persistence */
+
+	/* Tx section */
+
+	int tx_state;
+	int tx_count;
+	int slotcnt;
+	unsigned char tx_buf[YAM_MAX_FRAME];
+	int tx_len;
+	int tx_crcl, tx_crch;
+	struct sk_buff_head send_queue;		/* Packets awaiting transmission */
+
+	/* Rx section */
+
+	int dcd;
+	unsigned char rx_buf[YAM_MAX_FRAME];
+	int rx_len;
+	int rx_crcl, rx_crch;
+};
+
+struct yam_mcs {
+	unsigned char bits[YAM_FPGA_SIZE];
+	int bitrate;
+	struct yam_mcs *next;
+};
+
+static struct yam_port yam_ports[NR_PORTS];
+
+static struct yam_mcs *yam_data = NULL;
+
+static unsigned irqs[16];
+
+static char ax25_bcast[7] =
+{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
+static char ax25_test[7] =
+{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
+
+static struct timer_list yam_timer;
+
+/* --------------------------------------------------------------------- */
+
+#define RBR(iobase) (iobase+0)
+#define THR(iobase) (iobase+0)
+#define IER(iobase) (iobase+1)
+#define IIR(iobase) (iobase+2)
+#define FCR(iobase) (iobase+2)
+#define LCR(iobase) (iobase+3)
+#define MCR(iobase) (iobase+4)
+#define LSR(iobase) (iobase+5)
+#define MSR(iobase) (iobase+6)
+#define SCR(iobase) (iobase+7)
+#define DLL(iobase) (iobase+0)
+#define DLM(iobase) (iobase+1)
+
+#define YAM_EXTENT 8
+
+/* Interrupt Identification Register Bit Masks */
+#define IIR_NOPEND 	1
+#define IIR_MSR  	0
+#define IIR_TX     	2
+#define IIR_RX     	4
+#define IIR_LSR   	6
+#define IIR_TIMEOUT	12			/* Fifo mode only */
+
+#define IIR_MASK	0x0F
+
+/* Interrupt Enable Register Bit Masks */
+#define IER_RX  1				/* enable rx interrupt */
+#define IER_TX  2				/* enable tx interrupt */
+#define IER_LSR 4				/* enable line status interrupts */
+#define IER_MSR 8				/* enable modem status interrupts */
+
+/* Modem Control Register Bit Masks */
+#define MCR_DTR  0x01			/* DTR output */
+#define MCR_RTS  0x02			/* RTS output */
+#define MCR_OUT1 0x04			/* OUT1 output (not accessible in RS232) */
+#define MCR_OUT2 0x08			/* Master Interrupt enable (must be set on PCs) */
+#define MCR_LOOP 0x10			/* Loopback enable */
+
+/* Modem Status Register Bit Masks */
+#define MSR_DCTS 0x01			/* Delta CTS input */
+#define MSR_DDSR 0x02			/* Delta DSR */
+#define MSR_DRIN 0x04			/* Delta RI */
+#define MSR_DDCD 0x08			/* Delta DCD */
+#define MSR_CTS  0x10			/* CTS input */
+#define MSR_DSR  0x20			/* DSR input */
+#define MSR_RING 0x40			/* RI  input */
+#define MSR_DCD  0x80			/* DCD input */
+
+/* line status register bit mask */
+#define LSR_RXC	   0x01
+#define LSR_OE	   0x02
+#define LSR_PE	   0x04
+#define LSR_FE	   0x08
+#define LSR_BREAK  0x10
+#define LSR_THRE   0x20
+#define LSR_TSRE   0x40
+
+/* Line Control Register Bit Masks */
+#define LCR_DLAB    0x80
+#define LCR_BREAK   0x40
+#define LCR_PZERO   0x28
+#define LCR_PEVEN   0x18
+#define LCR_PODD    0x08
+#define LCR_STOP1   0x00
+#define LCR_STOP2   0x04
+#define LCR_BIT5    0x00
+#define LCR_BIT6    0x02
+#define LCR_BIT7    0x01
+#define LCR_BIT8    0x03
+
+/* YAM Modem <-> UART Port mapping */
+
+#define TX_RDY 	  MSR_DCTS		/* transmitter ready to send */
+#define RX_DCD    MSR_DCD		/* carrier detect */
+#define RX_FLAG   MSR_RING		/* hdlc flag received */
+#define FPGA_DONE MSR_DSR		/* FPGA is configured */
+#define PTT_ON    (MCR_RTS|MCR_OUT2)	/* activate PTT */
+#define PTT_OFF   (MCR_DTR|MCR_OUT2)	/* release PTT */
+
+#define ENABLE_RXINT   IER_RX	/* enable uart rx interrupt during rx */
+#define ENABLE_TXINT   IER_MSR	/* enable uart ms interrupt during tx */
+#define ENABLE_RTXINT  (IER_RX|IER_MSR)		/* full duplex operations */
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+/*************************************************************************
+* CRC Tables
+************************************************************************/
+
+static const unsigned char chktabl[256] =
+{0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e,
+ 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64,
+ 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e,
+ 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50,
+ 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e,
+ 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44,
+ 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e,
+ 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38,
+ 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e,
+ 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24,
+ 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e,
+ 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10,
+ 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e,
+ 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04,
+ 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e,
+ 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9,
+ 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1,
+ 0x78};
+static const unsigned char chktabh[256] =
+{0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9,
+ 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb,
+ 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb,
+ 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f,
+ 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed,
+ 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf,
+ 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef,
+ 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07,
+ 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1,
+ 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3,
+ 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3,
+ 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87,
+ 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5,
+ 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7,
+ 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7,
+ 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f,
+ 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e,
+ 0x0f};
+
+/*************************************************************************
+* FPGA functions
+************************************************************************/
+
+static void delay(int ms)
+{
+	unsigned long timeout = jiffies + ((ms * HZ) / 1000);
+	while (jiffies < timeout);
+}
+
+/*
+ * reset FPGA
+ */
+
+static void fpga_reset(int iobase)
+{
+	outb(0, IER(iobase));
+	outb(LCR_DLAB | LCR_BIT5, LCR(iobase));
+	outb(1, DLL(iobase));
+	outb(0, DLM(iobase));
+
+	outb(LCR_BIT5, LCR(iobase));
+	inb(LSR(iobase));
+	inb(MSR(iobase));
+	/* turn off FPGA supply voltage */
+	outb(MCR_OUT1 | MCR_OUT2, MCR(iobase));
+	delay(100);
+	/* turn on FPGA supply voltage again */
+	outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase));
+	delay(100);
+}
+
+/*
+ * send one byte to FPGA
+ */
+
+static int fpga_write(int iobase, unsigned char wrd)
+{
+	unsigned char bit;
+	int k;
+	unsigned long timeout = jiffies + HZ / 10;
+
+	for (k = 0; k < 8; k++) {
+		bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR;
+		outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase));
+		wrd <<= 1;
+		outb(0xfc, THR(iobase));
+		while ((inb(LSR(iobase)) & LSR_TSRE) == 0)
+			if (jiffies > timeout)
+				return -1;
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+static void free_mcs(void)
+{
+	struct yam_mcs *p;
+
+	while (yam_data) {
+		p = yam_data;
+		yam_data = yam_data->next;
+		kfree(p);
+	}
+}
+#endif
+
+static unsigned char *
+ add_mcs(unsigned char *bits, int bitrate)
+{
+	struct yam_mcs *p;
+
+	/* If it already exists, replace the bit data */
+	p = yam_data;
+	while (p) {
+		if (p->bitrate == bitrate) {
+			memcpy(p->bits, bits, YAM_FPGA_SIZE);
+			return p->bits;
+		}
+		p = p->next;
+	}
+
+	/* Allocate a new mcs */
+	p = kmalloc(sizeof(struct yam_mcs), GFP_ATOMIC);
+	if (p == NULL) {
+		printk(KERN_WARNING "YAM: no memory to allocate mcs\n");
+		return NULL;
+	}
+	memcpy(p->bits, bits, YAM_FPGA_SIZE);
+	p->bitrate = bitrate;
+	p->next = yam_data;
+	yam_data = p;
+
+	return p->bits;
+}
+
+static unsigned char *get_mcs(int bitrate)
+{
+	struct yam_mcs *p;
+
+	p = yam_data;
+	while (p) {
+		if (p->bitrate == bitrate)
+			return p->bits;
+		p = p->next;
+	}
+
+	/* Load predefined mcs data */
+	switch (bitrate) {
+	case 1200:
+		return add_mcs(bits_1200, bitrate);
+	default:
+		return add_mcs(bits_9600, bitrate);
+	}
+}
+
+/*
+ * download bitstream to FPGA
+ * data is contained in bits[] array in fpgaconf.h
+ */
+
+static int fpga_download(int iobase, int bitrate)
+{
+	int i, rc;
+	unsigned char *pbits;
+
+	pbits = get_mcs(bitrate);
+	if (pbits == NULL)
+		return -1;
+
+	fpga_reset(iobase);
+	for (i = 0; i < YAM_FPGA_SIZE; i++) {
+		if (fpga_write(iobase, pbits[i])) {
+			printk("yam: error in write cycle\n");
+			return -1;			/* write... */
+		}
+	}
+
+	fpga_write(iobase, 0xFF);
+	rc = inb(MSR(iobase));		/* check DONE signal */
+
+	/* Needed for some hardwares */
+	delay(50);
+
+	return (rc & MSR_DSR) ? 0 : -1;
+}
+
+
+/************************************************************************
+* Serial port init 
+************************************************************************/
+
+static void yam_set_uart(struct device *dev)
+{
+	struct yam_port *yp = (struct yam_port *) dev->priv;
+	int divisor = 115200 / yp->baudrate;
+
+	outb(0, IER(dev->base_addr));
+	outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr));
+	outb(divisor, DLL(dev->base_addr));
+	outb(0, DLM(dev->base_addr));
+	outb(LCR_BIT8, LCR(dev->base_addr));
+	outb(PTT_OFF, MCR(dev->base_addr));
+	outb(0x00, FCR(dev->base_addr));
+
+	/* Flush pending irq */
+
+	inb(RBR(dev->base_addr));
+	inb(MSR(dev->base_addr));
+
+	/* Enable rx irq */
+
+	outb(ENABLE_RTXINT, IER(dev->base_addr));
+}
+
+
+/* --------------------------------------------------------------------- */
+
+enum uart {
+	c_uart_unknown, c_uart_8250,
+	c_uart_16450, c_uart_16550, c_uart_16550A
+};
+
+static const char *uart_str[] =
+{"unknown", "8250", "16450", "16550", "16550A"};
+
+static enum uart yam_check_uart(unsigned int iobase)
+{
+	unsigned char b1, b2, b3;
+	enum uart u;
+	enum uart uart_tab[] =
+	{c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A};
+
+	b1 = inb(MCR(iobase));
+	outb(b1 | 0x10, MCR(iobase));	/* loopback mode */
+	b2 = inb(MSR(iobase));
+	outb(0x1a, MCR(iobase));
+	b3 = inb(MSR(iobase)) & 0xf0;
+	outb(b1, MCR(iobase));		/* restore old values */
+	outb(b2, MSR(iobase));
+	if (b3 != 0x90)
+		return c_uart_unknown;
+	inb(RBR(iobase));
+	inb(RBR(iobase));
+	outb(0x01, FCR(iobase));	/* enable FIFOs */
+	u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
+	if (u == c_uart_16450) {
+		outb(0x5a, SCR(iobase));
+		b1 = inb(SCR(iobase));
+		outb(0xa5, SCR(iobase));
+		b2 = inb(SCR(iobase));
+		if ((b1 != 0x5a) || (b2 != 0xa5))
+			u = c_uart_8250;
+	}
+	return u;
+}
+
+/******************************************************************************
+* Rx Section
+******************************************************************************/
+static void inline
+ yam_rx_flag(struct device *dev, struct yam_port *yp)
+{
+	if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) {
+		int pkt_len = yp->rx_len - 2 + 1;	/* -CRC + kiss */
+		struct sk_buff *skb;
+
+		if ((yp->rx_crch & yp->rx_crcl) != 0xFF) {
+			/* Bad crc */
+		} else {
+			if (!(skb = dev_alloc_skb(pkt_len))) {
+				printk("%s: memory squeeze, dropping packet\n", dev->name);
+				++yp->stats.rx_dropped;
+			} else {
+				unsigned char *cp;
+				skb->dev = dev;
+				cp = skb_put(skb, pkt_len);
+				*cp++ = 0;		/* KISS kludge */
+				memcpy(cp, yp->rx_buf, pkt_len - 1);
+				skb->protocol = htons(ETH_P_AX25);
+				skb->mac.raw = skb->data;
+				netif_rx(skb);
+				++yp->stats.rx_packets;
+			}
+		}
+	}
+	yp->rx_len = 0;
+	yp->rx_crcl = 0x21;
+	yp->rx_crch = 0xf3;
+}
+
+static void inline
+ yam_rx_byte(struct device *dev, struct yam_port *yp, unsigned char rxb)
+{
+	if (yp->rx_len < YAM_MAX_FRAME) {
+		unsigned char c = yp->rx_crcl;
+		yp->rx_crcl = (chktabl[c] ^ yp->rx_crch);
+		yp->rx_crch = (chktabh[c] ^ rxb);
+		yp->rx_buf[yp->rx_len++] = rxb;
+	}
+}
+
+/********************************************************************************
+* TX Section
+********************************************************************************/
+
+static void ptt_on(struct device *dev)
+{
+	outb(PTT_ON, MCR(dev->base_addr));
+}
+
+static void ptt_off(struct device *dev)
+{
+	outb(PTT_OFF, MCR(dev->base_addr));
+}
+
+static int yam_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct yam_port *yp = dev->priv;
+
+	if (skb == NULL) {
+		return 0;
+	}
+	skb_queue_tail(&yp->send_queue, skb);
+	dev->trans_start = jiffies;
+	return 0;
+}
+
+static void yam_start_tx(struct device *dev, struct yam_port *yp)
+{
+	if ((yp->tx_state == TX_TAIL) || (yp->txd == 0))
+		yp->tx_count = 1;
+	else
+		yp->tx_count = (yp->bitrate * yp->txd) / 8000;
+	yp->tx_state = TX_HEAD;
+	ptt_on(dev);
+}
+
+static unsigned short random_seed;
+
+static inline unsigned short random_num(void)
+{
+	random_seed = 28629 * random_seed + 157;
+	return random_seed;
+}
+
+static void yam_arbitrate(struct device *dev)
+{
+	struct yam_port *yp = dev->priv;
+
+	if (!yp || yp->magic != YAM_MAGIC
+		|| yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) {
+		return;
+	}
+	/* tx_state is TX_OFF and there is data to send */
+
+	if (yp->dupmode) {
+		/* Full duplex mode, don't wait */
+		yam_start_tx(dev, yp);
+		return;
+	}
+	if (yp->dcd) {
+		/* DCD on, wait slotime ... */
+		yp->slotcnt = yp->slot / 10;
+		return;
+	}
+	/* Is slottime passed ? */
+	if ((--yp->slotcnt) > 0)
+		return;
+
+	yp->slotcnt = yp->slot / 10;
+
+	/* is random > persist ? */
+	if ((random_num() % 256) > yp->pers)
+		return;
+
+	yam_start_tx(dev, yp);
+}
+
+static void yam_dotimer(unsigned long dummy)
+{
+	int i;
+
+	for (i = 0; i < NR_PORTS; i++) {
+		struct device *dev = &yam_ports[i].dev;
+		if (dev->start)
+			yam_arbitrate(dev);
+	}
+	yam_timer.expires = jiffies + HZ / 100;
+	add_timer(&yam_timer);
+}
+
+static void yam_tx_byte(struct device *dev, struct yam_port *yp)
+{
+	struct sk_buff *skb;
+	unsigned char b, temp;
+
+	switch (yp->tx_state) {
+	case TX_OFF:
+		break;
+	case TX_HEAD:
+		if (--yp->tx_count <= 0) {
+			if (!(skb = skb_dequeue(&yp->send_queue))) {
+				ptt_off(dev);
+				yp->tx_state = TX_OFF;
+				break;
+			}
+			yp->tx_state = TX_DATA;
+			if (skb->data[0] != 0) {
+/*                              do_kiss_params(s, skb->data, skb->len); */
+				dev_kfree_skb(skb);
+				break;
+			}
+			yp->tx_len = skb->len - 1;	/* strip KISS byte */
+			if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) {
+				dev_kfree_skb(skb);
+				break;
+			}
+			memcpy(yp->tx_buf, skb->data + 1, yp->tx_len);
+			dev_kfree_skb(skb);
+			yp->tx_count = 0;
+			yp->tx_crcl = 0x21;
+			yp->tx_crch = 0xf3;
+			yp->tx_state = TX_DATA;
+		}
+		break;
+	case TX_DATA:
+		b = yp->tx_buf[yp->tx_count++];
+		outb(b, THR(dev->base_addr));
+		temp = yp->tx_crcl;
+		yp->tx_crcl = chktabl[temp] ^ yp->tx_crch;
+		yp->tx_crch = chktabh[temp] ^ b;
+		if (yp->tx_count >= yp->tx_len) {
+			yp->tx_state = TX_CRC1;
+		}
+		break;
+	case TX_CRC1:
+		yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch;
+		yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff;
+		outb(yp->tx_crcl, THR(dev->base_addr));
+		yp->tx_state = TX_CRC2;
+		break;
+	case TX_CRC2:
+		outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr));
+		if (skb_queue_empty(&yp->send_queue)) {
+			yp->tx_count = (yp->bitrate * yp->txtail) / 8000;
+			if (yp->dupmode == 2)
+				yp->tx_count += (yp->bitrate * yp->holdd) / 8;
+			if (yp->tx_count == 0)
+				yp->tx_count = 1;
+			yp->tx_state = TX_TAIL;
+		} else {
+			yp->tx_count = 1;
+			yp->tx_state = TX_HEAD;
+		}
+		++yp->stats.tx_packets;
+		break;
+	case TX_TAIL:
+		if (--yp->tx_count <= 0) {
+			yp->tx_state = TX_OFF;
+			ptt_off(dev);
+		}
+		break;
+	}
+}
+
+/***********************************************************************************
+* ISR routine
+************************************************************************************/
+
+static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev;
+	struct yam_port *yp;
+	unsigned char iir;
+	int counter = 100;
+	int i;
+
+	sti();
+
+	for (i = 0; i < NR_PORTS; i++) {
+		yp = &yam_ports[i];
+		dev = &yp->dev;
+
+		if (!dev->start)
+			continue;
+
+		while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
+			unsigned char msr = inb(MSR(dev->base_addr));
+			unsigned char lsr = inb(LSR(dev->base_addr));
+			unsigned char rxb;
+
+			if (lsr & LSR_OE)
+				++yp->stats.rx_fifo_errors;
+
+			yp->dcd = (msr & RX_DCD) ? 1 : 0;
+
+			if (--counter <= 0) {
+				printk("%s: too many irq iir=%d\n", dev->name, iir);
+				return;
+			}
+			if (msr & TX_RDY) {
+				++yp->nb_mdint;
+				yam_tx_byte(dev, yp);
+			}
+			if (lsr & LSR_RXC) {
+				++yp->nb_rxint;
+				rxb = inb(RBR(dev->base_addr));
+				if (msr & RX_FLAG)
+					yam_rx_flag(dev, yp);
+				else
+					yam_rx_byte(dev, yp, rxb);
+			}
+		}
+	}
+}
+
+static int yam_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	int len = 0;
+	int i;
+	off_t pos = 0;
+	off_t begin = 0;
+
+	cli();
+
+	for (i = 0; i < NR_PORTS; i++) {
+		if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
+			continue;
+		len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
+		len += sprintf(buffer + len, "  Up       %d\n", yam_ports[i].dev.start);
+		len += sprintf(buffer + len, "  Speed    %u\n", yam_ports[i].bitrate);
+		len += sprintf(buffer + len, "  IoBase   0x%x\n", yam_ports[i].iobase);
+		len += sprintf(buffer + len, "  BaudRate %u\n", yam_ports[i].baudrate);
+		len += sprintf(buffer + len, "  IRQ      %u\n", yam_ports[i].irq);
+		len += sprintf(buffer + len, "  TxState  %u\n", yam_ports[i].tx_state);
+		len += sprintf(buffer + len, "  Duplex   %u\n", yam_ports[i].dupmode);
+		len += sprintf(buffer + len, "  HoldDly  %u\n", yam_ports[i].holdd);
+		len += sprintf(buffer + len, "  TxDelay  %u\n", yam_ports[i].txd);
+		len += sprintf(buffer + len, "  TxTail   %u\n", yam_ports[i].txtail);
+		len += sprintf(buffer + len, "  SlotTime %u\n", yam_ports[i].slot);
+		len += sprintf(buffer + len, "  Persist  %u\n", yam_ports[i].pers);
+		len += sprintf(buffer + len, "  TxFrames %lu\n", yam_ports[i].stats.tx_packets);
+		len += sprintf(buffer + len, "  RxFrames %lu\n", yam_ports[i].stats.rx_packets);
+		len += sprintf(buffer + len, "  TxInt    %u\n", yam_ports[i].nb_mdint);
+		len += sprintf(buffer + len, "  RxInt    %u\n", yam_ports[i].nb_rxint);
+		len += sprintf(buffer + len, "  RxOver   %lu\n", yam_ports[i].stats.rx_fifo_errors);
+		len += sprintf(buffer + len, "\n");
+
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if (pos > offset + length)
+			break;
+	}
+
+	sti();
+
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+
+	if (len > length)
+		len = length;
+
+	return len;
+}
+
+#ifdef CONFIG_INET
+#ifndef PROC_NET_YAM
+#define PROC_NET_YAM (PROC_NET_LAST+10)		/* Sorry again... */
+#endif
+
+struct proc_dir_entry yam_proc_dir_entry =
+{
+	PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0,
+	&proc_net_inode_operations, yam_net_get_info
+};
+
+#define yam_net_procfs_init()   proc_net_register(&yam_proc_dir_entry);
+#define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM);
+#else
+#define yam_net_procfs_init()
+#define yam_net_procfs_remove()
+#endif
+
+/* --------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= 0x20119
+static struct net_device_stats *
+ yam_get_stats(struct device *dev)
+#else
+static struct enet_statistics *
+ yam_get_stats(struct device *dev)
+#endif
+{
+	struct yam_port *yp;
+
+	if (!dev || !dev->priv)
+		return NULL;
+
+	yp = (struct yam_port *) dev->priv;
+	if (yp->magic != YAM_MAGIC)
+		return NULL;
+
+	/* 
+	 * Get the current statistics.  This may be called with the
+	 * card open or closed. 
+	 */
+	return &yp->stats;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int yam_open(struct device *dev)
+{
+	struct yam_port *yp = (struct yam_port *) dev->priv;
+	enum uart u;
+	int i;
+
+	printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq);
+
+	if (!dev || !yp || !yp->bitrate)
+		return -ENXIO;
+	if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT ||
+		dev->irq < 2 || dev->irq > 15) {
+		return -ENXIO;
+	}
+	if (check_region(dev->base_addr, YAM_EXTENT)) {
+		printk("%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
+		return -EACCES;
+	}
+	if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) {
+		printk("%s: cannot find uart type\n", dev->name);
+		return -EIO;
+	}
+	if (fpga_download(dev->base_addr, yp->bitrate)) {
+		printk("%s: cannot init FPGA\n", dev->name);
+		return -EIO;
+	}
+	outb(0, IER(dev->base_addr));
+	if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, NULL)) {
+		printk("%s: irq %d busy\n", dev->name, dev->irq);
+		return -EBUSY;
+	}
+	request_region(dev->base_addr, YAM_EXTENT, dev->name);
+
+	yam_set_uart(dev);
+	dev->start = 1;
+	yp->slotcnt = yp->slot / 10;
+
+	/* Reset overruns for all ports - FPGA programming makes overruns */
+	for (i = 0; i < NR_PORTS; i++) {
+		inb(LSR(yam_ports[i].dev.base_addr));
+		yam_ports[i].stats.rx_fifo_errors = 0;
+	}
+
+	printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq,
+		   uart_str[u]);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int yam_close(struct device *dev)
+{
+	struct sk_buff *skb;
+	struct yam_port *yp = (struct yam_port *) dev->priv;
+
+	if (!dev || !yp)
+		return -EINVAL;
+	/*
+	 * disable interrupts
+	 */
+	outb(0, IER(dev->base_addr));
+	outb(1, MCR(dev->base_addr));
+	/* Remove IRQ handler if last */
+	free_irq(dev->irq, NULL);
+	release_region(dev->base_addr, YAM_EXTENT);
+	dev->start = 0;
+	dev->tbusy = 1;
+	while ((skb = skb_dequeue(&yp->send_queue)))
+		dev_kfree_skb(skb);
+
+	printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n",
+		   yam_drvname, dev->base_addr, dev->irq);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int yam_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct yam_port *yp = (struct yam_port *) dev->priv;
+	struct yamdrv_ioctl_cfg yi;
+	struct yamdrv_ioctl_mcs *ym;
+	int ioctl_cmd;
+
+	if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int)))
+		 return -EFAULT;
+
+	if (yp == NULL || yp->magic != YAM_MAGIC)
+		return -EINVAL;
+
+	if (!suser())
+		return -EPERM;
+
+	if (cmd != SIOCDEVPRIVATE)
+		return -EINVAL;
+
+	switch (ioctl_cmd) {
+
+	case SIOCYAMRESERVED:
+		return -EINVAL;			/* unused */
+
+	case SIOCYAMSMCS:
+		if (dev->start)
+			return -EINVAL;		/* Cannot change this parameter when up */
+		ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
+		ym->bitrate = 9600;
+		if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs)))
+			 return -EFAULT;
+		if (ym->bitrate > YAM_MAXBITRATE)
+			return -EINVAL;
+		add_mcs(ym->bits, ym->bitrate);
+		kfree(ym);
+		break;
+
+	case SIOCYAMSCFG:
+		if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
+			 return -EFAULT;
+
+		if ((yi.cfg.mask & YAM_IOBASE) && dev->start)
+			return -EINVAL;		/* Cannot change this parameter when up */
+		if ((yi.cfg.mask & YAM_IRQ) && dev->start)
+			return -EINVAL;		/* Cannot change this parameter when up */
+		if ((yi.cfg.mask & YAM_BITRATE) && dev->start)
+			return -EINVAL;		/* Cannot change this parameter when up */
+		if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start)
+			return -EINVAL;		/* Cannot change this parameter when up */
+
+		if (yi.cfg.mask & YAM_IOBASE) {
+			yp->iobase = yi.cfg.iobase;
+			dev->base_addr = yi.cfg.iobase;
+		}
+		if (yi.cfg.mask & YAM_IRQ) {
+			if (yi.cfg.irq > 15)
+				return -EINVAL;
+			yp->irq = yi.cfg.irq;
+			dev->irq = yi.cfg.irq;
+		}
+		if (yi.cfg.mask & YAM_BITRATE) {
+			if (yi.cfg.bitrate > YAM_MAXBITRATE)
+				return -EINVAL;
+			yp->bitrate = yi.cfg.bitrate;
+		}
+		if (yi.cfg.mask & YAM_BAUDRATE) {
+			if (yi.cfg.baudrate > YAM_MAXBAUDRATE)
+				return -EINVAL;
+			yp->baudrate = yi.cfg.baudrate;
+		}
+		if (yi.cfg.mask & YAM_MODE) {
+			if (yi.cfg.mode > YAM_MAXMODE)
+				return -EINVAL;
+			yp->dupmode = yi.cfg.mode;
+		}
+		if (yi.cfg.mask & YAM_HOLDDLY) {
+			if (yi.cfg.holddly > YAM_MAXHOLDDLY)
+				return -EINVAL;
+			yp->holdd = yi.cfg.holddly;
+		}
+		if (yi.cfg.mask & YAM_TXDELAY) {
+			if (yi.cfg.txdelay > YAM_MAXTXDELAY)
+				return -EINVAL;
+			yp->txd = yi.cfg.txdelay;
+		}
+		if (yi.cfg.mask & YAM_TXTAIL) {
+			if (yi.cfg.txtail > YAM_MAXTXTAIL)
+				return -EINVAL;
+			yp->txtail = yi.cfg.txtail;
+		}
+		if (yi.cfg.mask & YAM_PERSIST) {
+			if (yi.cfg.persist > YAM_MAXPERSIST)
+				return -EINVAL;
+			yp->pers = yi.cfg.persist;
+		}
+		if (yi.cfg.mask & YAM_SLOTTIME) {
+			if (yi.cfg.slottime > YAM_MAXSLOTTIME)
+				return -EINVAL;
+			yp->slot = yi.cfg.slottime;
+			yp->slotcnt = yp->slot / 10;
+		}
+		break;
+
+	case SIOCYAMGCFG:
+		yi.cfg.mask = 0xffffffff;
+		yi.cfg.iobase = yp->iobase;
+		yi.cfg.irq = yp->irq;
+		yi.cfg.bitrate = yp->bitrate;
+		yi.cfg.baudrate = yp->baudrate;
+		yi.cfg.mode = yp->dupmode;
+		yi.cfg.txdelay = yp->txd;
+		yi.cfg.holddly = yp->holdd;
+		yi.cfg.txtail = yp->txtail;
+		yi.cfg.persist = yp->pers;
+		yi.cfg.slottime = yp->slot;
+		if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg)))
+			 return -EFAULT;
+		break;
+
+	default:
+		return -EINVAL;
+
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int yam_set_mac_address(struct device *dev, void *addr)
+{
+	struct sockaddr *sa = (struct sockaddr *) addr;
+
+	/* addr is an AX.25 shifted ASCII mac address */
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int yam_probe(struct device *dev)
+{
+	struct yam_port *yp;
+
+	if (!dev)
+		return -ENXIO;
+
+	yp = (struct yam_port *) dev->priv;
+
+	dev->open = yam_open;
+	dev->stop = yam_close;
+	dev->do_ioctl = yam_ioctl;
+	dev->hard_start_xmit = yam_send_packet;
+	dev->get_stats = yam_get_stats;
+
+	dev_init_buffers(dev);
+	skb_queue_head_init(&yp->send_queue);
+
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+	dev->hard_header = ax25_encapsulate;
+	dev->rebuild_header = ax25_rebuild_header;
+#else							/* CONFIG_AX25 || CONFIG_AX25_MODULE */
+	dev->hard_header = NULL;
+	dev->rebuild_header = NULL;
+#endif							/* CONFIG_AX25 || CONFIG_AX25_MODULE */
+
+	dev->set_mac_address = yam_set_mac_address;
+
+	dev->type = ARPHRD_AX25;	/* AF_AX25 device */
+	dev->hard_header_len = 73;	/* We do digipeaters now */
+	dev->mtu = 256;				/* AX25 is the default */
+	dev->addr_len = 7;			/* sizeof an ax.25 address */
+	memcpy(dev->broadcast, ax25_bcast, 7);
+	memcpy(dev->dev_addr, ax25_test, 7);
+
+	/* New style flags */
+	dev->flags = 0;
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+__initfunc(int yam_init(struct device *dev))
+{
+	int i;
+
+	printk(yam_drvinfo);
+
+	/* Clears the IRQ table */
+	memset(irqs, 0, sizeof(irqs));
+	memset(yam_ports, 0, sizeof(yam_ports));
+
+	for (i = 0; i < NR_PORTS; i++) {
+		sprintf(yam_ports[i].name, "yam%d", i);
+		yam_ports[i].magic = YAM_MAGIC;
+		yam_ports[i].bitrate = DEFAULT_BITRATE;
+		yam_ports[i].baudrate = DEFAULT_BITRATE * 2;
+		yam_ports[i].iobase = 0;
+		yam_ports[i].irq = 0;
+		yam_ports[i].dupmode = 0;
+		yam_ports[i].holdd = DEFAULT_HOLDD;
+		yam_ports[i].txd = DEFAULT_TXD;
+		yam_ports[i].txtail = DEFAULT_TXTAIL;
+		yam_ports[i].slot = DEFAULT_SLOT;
+		yam_ports[i].pers = DEFAULT_PERS;
+
+		dev = &yam_ports[i].dev;
+
+		dev->priv = &yam_ports[i];
+		dev->name = yam_ports[i].name;
+		dev->base_addr = yam_ports[i].iobase;
+		dev->irq = yam_ports[i].irq;
+		dev->init = yam_probe;
+		dev->if_port = 0;
+		dev->start = 0;
+		dev->tbusy = 1;
+
+		if (register_netdev(dev)) {
+			printk(KERN_WARNING "yam: cannot register net  device %s\n", dev->name);
+			return -ENXIO;
+		}
+	}
+
+	yam_timer.function = yam_dotimer;
+	yam_timer.expires = jiffies + HZ / 100;
+	add_timer(&yam_timer);
+
+	yam_net_procfs_init();
+
+	/* do not keep this device */
+	return 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+/*
+ * command line settable parameters
+ */
+
+#if LINUX_VERSION_CODE >= 0x20115
+
+MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
+MODULE_DESCRIPTION("Yam amateur radio modem driver");
+
+#endif
+
+__initfunc(int init_module(void))
+{
+	int ret = yam_init(NULL);
+
+	return (ret == 1) ? 0 : ret;
+}
+
+/* --------------------------------------------------------------------- */
+
+void cleanup_module(void)
+{
+	int i;
+
+	del_timer(&yam_timer);
+	for (i = 0; i < NR_PORTS; i++) {
+		struct device *dev = &yam_ports[i].dev;
+		if (!dev->priv)
+			continue;
+		if (dev->start)
+			yam_close(dev);
+		unregister_netdev(dev);
+	}
+	free_mcs();
+	yam_net_procfs_remove();
+}
+
+#endif							/* MODULE */
+/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/yam1200.h linux/drivers/net/hamradio/yam1200.h
--- v2.3.12/linux/drivers/net/hamradio/yam1200.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/yam1200.h	Thu Aug  5 14:35:52 1999
@@ -0,0 +1,343 @@
+/*
+ *
+ * File yam1k2b5.mcs converted to h format by mcs2h
+ *
+ * (C) F6FBB 1998
+ *
+ * Tue Aug 25 20:24:08 1998
+ *
+ */
+
+static unsigned char bits_1200[]= {
+0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xf3,0xcb,0xff,0xdb,0xfc,0xf2,
+0xff,0xf6,0xff,0x3c,0xbf,0xfd,0xbf,0xdf,0x6e,0x3f,0x6f,0xf1,0x7d,0xb4,0xfd,0xbf,
+0xdf,0x6f,0x3f,0x6f,0xf7,0x0b,0xff,0xdb,0xfd,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff,
+0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xef,0xff,0xff,0xff,
+0xfd,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xbf,
+0xff,0xff,0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfc,0xff,0xfe,0xff,0xff,0xff,0xf0,
+0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xf1,0xff,0xff,0xfe,0x7f,0xbf,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xff,0xff,0xf0,0x9f,
+0xff,0xff,0xff,0xfe,0xff,0xfd,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xff,
+0xff,0xff,0xfb,0xff,0xfb,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xf0,0x5f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xbf,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,
+0xff,0xff,0xff,0xfd,0xff,0xbf,0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xfb,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,
+0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xf7,0xff,0xff,0xf1,0xff,0xff,0xf7,0xbf,0xe7,0xff,0xff,0xff,0xff,0xfb,
+0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdb,
+0xff,0xff,0xf5,0xa5,0xfd,0x4b,0x6e,0xef,0x33,0x32,0xdd,0xd3,0x4a,0xd6,0x92,0xfe,
+0xb3,0x3f,0xbd,0xf1,0xfa,0xdb,0xfe,0xf7,0xf6,0x96,0xbd,0xbd,0xff,0xbd,0xff,0xed,
+0x7f,0x6b,0x7f,0xfb,0xdf,0xfe,0xfb,0xfe,0x90,0xcf,0xff,0xff,0xff,0xfe,0xbe,0xef,
+0xff,0xff,0xdb,0x5f,0xf6,0xff,0xf6,0x8f,0xfd,0xa5,0xdd,0xff,0xff,0xff,0xff,0x6f,
+0x7f,0xdb,0xf1,0xfc,0xbf,0xff,0x6f,0xff,0xef,0xfc,0x5b,0x5d,0xda,0xdf,0xf4,0xff,
+0xf2,0xff,0xfd,0xbf,0xff,0xff,0xff,0xd0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
+0xff,0xfb,0xef,0xb7,0xfc,0x33,0xff,0xfb,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,
+0x0f,0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x72,0x0f,0xf1,0x6f,0xff,0xfe,0x94,0x3f,
+0xff,0xff,0xff,0x7b,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf0,
+0xf7,0xef,0xb7,0xfc,0x33,0xff,0xff,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,0x0f,
+0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x73,0x8f,0xf2,0x6f,0xff,0xfe,0x94,0x3f,0xff,
+0xff,0xff,0x7d,0x9f,0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x9e,
+0xff,0xfc,0xef,0xd3,0xfb,0xff,0x7f,0xf5,0x5f,0xfe,0x59,0xff,0xff,0xff,0xfc,0xf1,
+0xfe,0x7f,0xff,0xff,0xfa,0x17,0xff,0xe7,0xef,0xef,0xff,0xff,0x3f,0xf1,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xfc,0xea,
+0xff,0xf0,0xff,0xff,0xbf,0xf9,0x3f,0xb1,0xef,0xff,0xd7,0xff,0xfb,0xff,0xf0,0xff,
+0xff,0xf3,0xff,0xdf,0xff,0x7b,0xff,0xfd,0xff,0xf6,0xff,0xbf,0xff,0xff,0xbf,0xff,
+0xff,0xff,0xda,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x01,0x00,0x00,0x02,0x02,
+0x02,0x02,0x00,0x40,0x40,0x40,0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00,
+0x00,0x00,0x00,0x00,0x19,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
+0x00,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfb,0xff,0xfd,0xff,
+0xff,0x7f,0xff,0xff,0xbf,0xff,0xef,0xff,0xff,0xfd,0xff,0xff,0xf1,0xff,0xdf,0xff,
+0xff,0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf,
+0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xdf,0xff,0x7f,0xff,0xff,0xff,0xff,
+0xdf,0xdf,0xff,0xef,0xff,0x9e,0xef,0xff,0xff,0x7f,0xff,0xf1,0xef,0xff,0xff,0xff,
+0xf7,0xfa,0xbf,0xff,0xff,0xfe,0x47,0xef,0xff,0xbd,0xf6,0xff,0xff,0xdf,0xf5,0xf0,
+0xf0,0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x01,0x02,0x08,
+0x16,0x00,0x00,0x00,0x80,0x00,0x01,0x02,0x00,0x80,0x01,0x0c,0x02,0x00,0x00,0x01,
+0x00,0x00,0x20,0x00,0x00,0x06,0x00,0x20,0x00,0x10,0x00,0x14,0x00,0x04,0xc1,0xf0,
+0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,
+0xec,0xff,0xff,0xfa,0xff,0xbf,0xff,0x6f,0xff,0xe1,0xff,0xff,0xff,0xff,0xbd,0xfe,
+0x46,0xff,0xef,0x7f,0xcd,0xdf,0xff,0xff,0xfd,0xff,0xbd,0xff,0x7f,0x7f,0xf0,0x4f,
+0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa4,0xbc,0xcd,0x6d,0x6b,0x6f,0x5b,0xdc,0x33,
+0x5a,0xf6,0xf7,0xf6,0xb3,0x3f,0xbd,0xc1,0xfa,0x5a,0xf6,0xf6,0xb6,0xf7,0xff,0xbd,
+0xbb,0x3c,0xce,0xcf,0x34,0xef,0x33,0xbb,0xcc,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,
+0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xd6,0xff,0xfd,0xfd,0xbf,0xff,0xad,
+0xbf,0xf9,0x7f,0x6f,0xfc,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0xff,0xda,0xdb,0xfc,
+0xdb,0xff,0x76,0x8f,0xf6,0xff,0xcd,0xab,0xfe,0xfb,0xff,0xd0,0xff,0xff,0xff,0xff,
+0xfe,0xff,0x9f,0xff,0xf4,0x20,0xaf,0x6d,0x0b,0xc1,0x7b,0xff,0xff,0xff,0xcb,0xff,
+0x3f,0xf0,0xef,0x7f,0x0f,0xf1,0xc3,0x3c,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x0b,
+0x1d,0x6a,0x64,0x05,0x6b,0x99,0x01,0xff,0xfd,0xef,0xf0,0x2f,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xf4,0x00,0x2f,0xcc,0x0b,0xc3,0x7f,0xff,0xff,0xff,0x0a,0xdf,0xbf,
+0xfd,0x7f,0xff,0xff,0xf1,0xc3,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x4a,0x0e,
+0x96,0x64,0x02,0x97,0x99,0x10,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xfe,0x84,0xf9,0xd5,0x27,0xf1,0x7f,0xff,0xf8,0xeb,0xdf,0xf3,0xcf,0x3f,
+0x1f,0xff,0xf7,0x11,0xff,0xcf,0xff,0xfe,0x67,0xff,0xff,0xff,0xff,0xc4,0xff,0xff,
+0xb3,0xa1,0xff,0xf9,0xe0,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,
+0xff,0xfb,0x7f,0xe0,0xff,0xc7,0xfe,0x7f,0x3f,0xff,0xfd,0x77,0x8d,0x7f,0x0f,0xff,
+0xc3,0xff,0xf1,0xbf,0x8f,0xcf,0xff,0xff,0xdd,0x7b,0xff,0xf6,0xfa,0xf7,0xff,0x40,
+0x9f,0xf9,0x7f,0xd8,0xff,0xff,0xfa,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,
+0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x00,0x10,
+0x00,0x01,0x00,0x10,0x20,0x20,0x00,0x00,0x10,0x00,0x04,0x01,0x05,0x00,0x00,0x00,
+0x00,0x40,0x40,0x00,0x00,0x3c,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,
+0xff,0xff,0xfe,0x7f,0x7f,0xff,0xef,0xff,0xff,0xdf,0xff,0xff,0xdf,0xff,0xef,0xf7,
+0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xfc,0xfd,0xff,0x7f,
+0x7e,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0xff,0xff,
+0xff,0xff,0xfe,0xeb,0xfd,0x6f,0xff,0xf7,0xfe,0xf5,0x7f,0xff,0xff,0x7f,0xbf,0xb1,
+0xff,0xff,0x9f,0xbf,0xfb,0xff,0xfe,0xff,0xfe,0xff,0xf7,0xeb,0xdf,0xbf,0x5f,0xdd,
+0xff,0xdb,0xfd,0xd0,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x00,0x42,0x00,
+0x00,0x00,0x30,0x18,0x04,0x08,0x09,0x21,0x82,0x80,0x02,0x00,0x08,0x00,0x01,0x00,
+0x00,0x00,0x0c,0x20,0x10,0x00,0x11,0x00,0x44,0x84,0x00,0x20,0x20,0x84,0x80,0x00,
+0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xf7,0xff,0xfb,0xdd,0xf9,0xff,
+0xda,0xff,0xdc,0xdd,0xfc,0xfb,0xff,0xbf,0xfb,0x3e,0xd7,0x96,0xfe,0x61,0xf7,0xff,
+0x7f,0xff,0x3f,0xfd,0xff,0xdf,0xcf,0xf7,0xdf,0xf7,0xbf,0xfd,0xff,0xfe,0xef,0xef,
+0xfe,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf3,0xbd,0xfd,0x4b,0x74,0xcf,
+0x73,0x5b,0xcb,0x3b,0xdf,0xfe,0xf7,0xfe,0xd3,0x75,0xac,0xa1,0xfb,0xdf,0xfe,0xf7,
+0x76,0x96,0xb5,0x24,0xbd,0xa5,0xad,0x49,0x2f,0x69,0x2b,0x52,0x5b,0xbd,0xff,0xff,
+0xf0,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0xff,0xcc,
+0xa7,0xfb,0xad,0xff,0x7f,0x6f,0xff,0x6d,0x7f,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,
+0x6f,0xff,0xdb,0xff,0xdb,0xff,0xf6,0x97,0xf6,0xff,0xb5,0xb5,0xff,0xff,0xff,0xd0,
+0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa5,0xbc,0x43,0xfc,0x7c,0x03,0xe7,
+0xff,0xff,0x20,0xff,0xff,0xff,0xcc,0xfd,0x7d,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,
+0xba,0x56,0x66,0x6a,0xad,0x9a,0xa9,0x9a,0x97,0xa5,0xaa,0xbb,0xff,0xff,0xf0,0x0f,
+0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xfd,0xf7,0xfd,0x43,0xff,0xfd,0x6b,0xe7,0xff,
+0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0x3f,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,0xb5,
+0xa6,0x66,0x6a,0xad,0x9a,0xa9,0x99,0x6b,0x5a,0xaa,0xff,0xff,0xb7,0xf0,0x3f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x9c,0xf7,0xfd,0xd2,0x41,0xff,0xff,0xf2,0x7f,
+0x8f,0xff,0xff,0x3d,0xf3,0xff,0x17,0xf1,0xff,0xff,0xff,0xff,0xff,0x7f,0xdf,0xfc,
+0x8f,0x38,0xff,0xef,0x23,0xff,0xfb,0xf7,0xc8,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,
+0xff,0xfe,0xf5,0x7f,0xff,0xfd,0xff,0xe4,0xff,0xeb,0xff,0xcf,0xbf,0xfa,0xff,0xab,
+0xef,0xff,0xfb,0xff,0xf3,0xfd,0x61,0xff,0xff,0xff,0xff,0xfa,0xff,0xfb,0xfd,0x0d,
+0xff,0xfe,0xff,0x43,0x7f,0xfe,0xbf,0xd0,0xfd,0xff,0xfa,0xf0,0x3f,0xff,0xff,0xff,
+0xfe,0xf3,0xc0,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x00,0x60,0xc0,0x40,0x00,0x00,
+0x00,0x00,0x34,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x00,
+0x00,0x03,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x3c,0xf0,0x3f,0xff,0xff,0xff,0xfe,
+0xfd,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfd,0xff,
+0xff,0xff,0xff,0xfe,0xfe,0x5f,0xff,0xff,0xcb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,
+0xff,0xff,0xfd,0xff,0xef,0xe3,0xde,0xee,0xd9,0xc5,0x93,0xff,0xff,0xfe,0xfe,0xff,
+0xfb,0xee,0xfe,0xf1,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xbf,0xf7,0xff,0xff,0x7f,
+0xaf,0xbd,0xdf,0xdf,0xfb,0xf3,0xf3,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x34,
+0x00,0x06,0x61,0x00,0x18,0x01,0xa0,0x05,0x17,0x00,0x20,0x05,0x28,0x20,0x00,0x00,
+0x05,0x00,0x41,0x00,0x00,0x40,0x00,0x09,0x00,0x01,0x20,0x86,0x82,0x08,0x40,0x03,
+0x80,0x30,0x70,0x08,0x14,0x02,0xc1,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
+0xff,0xff,0xbd,0xef,0xfb,0xff,0xff,0xfb,0x9c,0x7f,0xef,0xdf,0xff,0xbf,0xeb,0xde,
+0xff,0xc1,0x7f,0xff,0xfb,0x7f,0xff,0xff,0xff,0x5f,0xff,0xff,0xff,0xdf,0xbf,0xef,
+0x3f,0xf7,0x8f,0xef,0x7f,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbd,
+0xdf,0xef,0x7d,0x6d,0x2b,0x5a,0x5d,0xd2,0xdf,0xf6,0x92,0xb6,0xb2,0xb3,0xac,0xa1,
+0xfb,0xdf,0xfe,0xf1,0xee,0xf5,0xf6,0xbc,0x6b,0xbd,0x7d,0xaf,0x1a,0xef,0x5f,0x6b,
+0xc6,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,
+0xf6,0xff,0xf6,0xb7,0xfd,0xad,0xfd,0xbf,0xf3,0x6f,0xff,0x6f,0xff,0xdb,0xd1,0xfd,
+0xbf,0xff,0x6f,0xf5,0x6b,0xbc,0x5b,0x3c,0xda,0xef,0x16,0xaf,0x16,0xff,0xcd,0xab,
+0xff,0x6f,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xbf,0xff,0xff,
+0xff,0x6c,0x03,0x10,0xc1,0xf3,0xff,0xf3,0x3a,0xf3,0xca,0xff,0xaf,0xf1,0xff,0xff,
+0xff,0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,
+0xff,0x5f,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,
+0xea,0x0f,0x50,0xc3,0xf3,0x7f,0xff,0xf3,0xf3,0xc3,0xff,0xaf,0xf1,0xff,0xff,0xff,
+0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,0xff,
+0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xd7,0xff,0xff,0x5f,0xc1,
+0x3f,0xf7,0x5e,0xf5,0xce,0x9e,0x5f,0x3f,0x17,0xff,0xf3,0xe1,0xff,0xff,0xff,0xff,
+0xd8,0xff,0xfa,0xfe,0x67,0xff,0xfe,0xbf,0x5a,0xff,0xff,0xaf,0xf5,0xff,0xff,0xff,
+0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfd,0xff,0xf7,0xff,0xfd,0x4e,0x3d,
+0x3f,0xe7,0x0b,0xbf,0x8f,0xf9,0xff,0xeb,0xe3,0xff,0xe1,0xff,0xff,0xfc,0xff,0xc7,
+0x9f,0xff,0x3e,0x39,0xe5,0xff,0xcf,0x9b,0xf9,0xff,0xff,0xc5,0xff,0xff,0xfa,0xf0,
+0x5f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
+0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x20,
+0x00,0x01,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xf0,0x4f,
+0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xbf,
+0x3f,0xff,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf1,0xff,0xff,0xff,0xff,0xf7,0xff,0xf7,
+0xff,0xed,0xff,0xfb,0xfe,0xff,0x7f,0xff,0x7f,0xdf,0xff,0xff,0xdd,0xf0,0x3f,0xff,
+0xff,0xff,0xfe,0xf0,0xff,0xff,0xf3,0xff,0xf7,0xff,0xfe,0x5f,0xff,0xf7,0xff,0xff,
+0xdf,0xff,0xff,0xff,0xf7,0xfe,0x7b,0xf1,0xff,0xfd,0xfd,0xff,0xdf,0xdf,0xff,0x7d,
+0x73,0xf9,0xff,0xc3,0x7e,0xfe,0xff,0xef,0xd7,0xff,0xcf,0xd0,0xf0,0x6f,0xff,0xff,
+0xff,0xfe,0xf8,0x30,0x00,0x00,0x40,0x04,0x00,0x01,0x41,0x20,0x00,0x04,0x00,0x02,
+0xd5,0x09,0x00,0x02,0x80,0x02,0x01,0x00,0x00,0x00,0x0a,0x04,0x00,0x07,0x00,0x01,
+0x50,0x01,0x80,0x02,0x61,0x40,0x41,0x0c,0x14,0x08,0xc1,0xf0,0x9f,0xff,0xff,0xff,
+0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xdf,0xcb,0x5f,0xfe,0xef,0xff,0xfe,
+0xff,0x3f,0xff,0x7f,0xfd,0xc1,0xff,0xff,0x7f,0xff,0xdf,0xfd,0xfc,0xfd,0xf7,0xee,
+0xff,0xff,0x4e,0xff,0xdf,0xcf,0xdb,0xeb,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0x7f,
+0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,
+0xf7,0xfb,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0x7f,0xff,0xff,0xff,0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdd,0xff,
+0xff,0xff,0xa5,0xff,0x6f,0x6b,0xe9,0x6f,0xda,0xca,0xfb,0xdd,0xee,0xf7,0xf6,0xb2,
+0xb3,0xa4,0xa1,0x5b,0x5b,0xf6,0xd7,0xf4,0xf7,0x7b,0xbd,0xbd,0xad,0xcf,0xef,0x7f,
+0x6b,0x7f,0x3b,0xdf,0xdb,0xff,0xff,0x30,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,
+0xff,0xff,0xff,0xf6,0xfe,0x96,0xff,0xfd,0xb5,0xfd,0xbf,0xad,0x7f,0xff,0x6f,0xff,
+0xde,0xd1,0xad,0xad,0xe9,0xff,0xf1,0xec,0xef,0xde,0x3f,0xcb,0xff,0xf6,0xff,0x32,
+0xff,0xc5,0xbd,0xff,0xff,0xff,0xd0,0xbf,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xf4,
+0x28,0xbf,0xff,0xfd,0xfb,0xd3,0xff,0xff,0x42,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,
+0xc1,0xff,0x33,0xff,0xc0,0x15,0x6b,0x70,0xff,0xf0,0xf2,0x4f,0xff,0xfc,0x3e,0x97,
+0x3c,0xff,0xff,0xfd,0xef,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x78,
+0xbf,0xff,0xfd,0xf3,0xef,0x55,0xff,0x7e,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,0xc1,
+0xff,0x33,0xff,0xc0,0x15,0x6f,0xff,0x0f,0xf0,0xf0,0x0f,0xff,0xfc,0x3d,0x6b,0xc3,
+0xff,0xff,0xfe,0xf7,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,
+0xff,0x23,0xf8,0x7f,0xff,0x4e,0xff,0xff,0xff,0xfb,0xf9,0x17,0xff,0xf6,0xf1,0xff,
+0xcf,0xef,0xff,0xff,0x13,0xdf,0xe6,0x2f,0xc7,0xff,0xff,0xe7,0xc1,0xfd,0xff,0xfe,
+0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xfe,0xae,0xff,
+0xff,0x7f,0x3b,0x3f,0xfc,0x7f,0xfc,0xef,0xff,0xfc,0xe2,0x7b,0xff,0xf1,0xfd,0xed,
+0xef,0xff,0xff,0x35,0x73,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,
+0xff,0xfa,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x00,0x0c,0x04,0x01,0x40,0x40,0x00,
+0x00,0x30,0x28,0x04,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,
+0x38,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xfb,0xff,0x7f,
+0xff,0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xdf,0xdf,0xff,
+0xff,0xff,0xff,0xed,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xbf,0xbf,0xff,0xff,0xc3,
+0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xfd,0xff,0xbf,0xff,0xff,0xfd,0xff,0xff,
+0xff,0xff,0xff,0xfd,0x7b,0xff,0x7f,0xff,0xbd,0xff,0xf1,0xef,0xff,0xff,0xfd,0xdf,
+0xfd,0xfb,0xff,0xff,0xbf,0xbe,0xff,0xcd,0x7f,0xfc,0xf7,0xf7,0x6f,0xbf,0xd8,0xf0,
+0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x00,0xa0,0x00,0x00,
+0xc0,0x00,0x00,0x20,0x34,0x00,0x00,0x00,0x0c,0x81,0x00,0x20,0xa4,0x20,0x00,0x10,
+0x08,0x04,0x48,0x08,0x00,0x40,0x93,0x00,0x10,0x00,0x38,0x18,0x20,0xc1,0xf0,0x3f,
+0xff,0xff,0xff,0xfe,0xff,0xfb,0xff,0xff,0xb9,0xdf,0xfe,0xb3,0xff,0xff,0xe7,0xfd,
+0xff,0xff,0x3b,0xff,0x7f,0xff,0xbf,0xff,0xc1,0xff,0xfc,0xff,0xff,0x3f,0x77,0xfe,
+0xfe,0xcf,0xff,0xbf,0xfd,0xbf,0xff,0xfe,0xed,0xf2,0xfd,0xf7,0xff,0xf0,0x2f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xf3,0xad,0xcf,0xef,0x70,0xc9,0x73,0x3b,0xdf,0x5b,0x4a,
+0xf6,0xb7,0xfe,0xd7,0xf5,0xbc,0xc1,0x33,0xca,0xd6,0xb7,0x6e,0xf7,0xfb,0xbd,0xc5,
+0x24,0xcf,0x6f,0x2f,0x4d,0x2b,0xba,0x5a,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,
+0xfe,0xbf,0xff,0xff,0xff,0xff,0xf6,0xf6,0xd7,0xff,0xff,0xad,0xbd,0xff,0xff,0xff,
+0xef,0xf7,0x7f,0xfc,0x5b,0xb1,0xfd,0xbd,0x75,0x6f,0xef,0x6a,0xfd,0x5b,0xfb,0xdb,
+0x3a,0xbf,0x8e,0x9f,0xff,0xbf,0xfd,0xff,0x6f,0xff,0xd0,0x6f,0xff,0xff,0xff,0xfe,
+0xff,0xbb,0xff,0xf0,0x3f,0xff,0xff,0xfd,0xfb,0x7f,0xde,0xff,0xff,0x5a,0xd6,0xbf,
+0xd8,0x2a,0xbf,0xbf,0xf1,0xe5,0xff,0xcc,0xc0,0xa9,0x70,0xff,0xf3,0x3c,0x3c,0xfd,
+0x57,0xfd,0x98,0x03,0x00,0xc3,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xff,0x3d,0xbf,0xff,0xfd,0xfb,0xff,0xdb,0xff,0xff,0x0f,0xfc,0x3f,0xd8,
+0x2a,0xbf,0xbf,0xf1,0xef,0xff,0xcc,0xc0,0x96,0xbe,0xff,0xf3,0x3f,0xff,0xfd,0x57,
+0xfd,0x99,0x0f,0xff,0xc3,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,
+0xff,0xf1,0xe7,0xff,0xff,0xf3,0x8e,0x7b,0xff,0xa8,0xff,0xdf,0x7f,0x8e,0x78,0x73,
+0xff,0xf1,0x51,0x62,0xff,0xfc,0x4b,0xff,0xf3,0xff,0x7e,0xcf,0xf9,0xff,0xfd,0xff,
+0xff,0x7f,0xff,0xe0,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,
+0xfb,0xfd,0xae,0xff,0xfc,0xfe,0x6f,0x3f,0xf8,0xfd,0x77,0xaf,0xfe,0x37,0xfe,0x7b,
+0xff,0xb1,0x8c,0xff,0xef,0xfd,0xf8,0xe7,0xbf,0xff,0xf1,0xfe,0x3e,0xf7,0xfe,0x95,
+0x3e,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,
+0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x08,
+0x41,0x80,0x10,0x00,0x00,0x08,0x10,0x84,0x00,0x0c,0x04,0x02,0x61,0x00,0x00,0x81,
+0x00,0x00,0x00,0x00,0x3d,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,
+0xff,0xff,0x7f,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
+0x7f,0xbf,0xf7,0x7f,0xef,0xff,0xef,0xff,0xf7,0xfd,0xff,0xff,0xfd,0x7f,0xff,0xbe,
+0xdf,0xff,0xff,0xd9,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0x7f,0xfb,0xff,
+0xfb,0xff,0xbf,0xff,0xf3,0x7f,0xfb,0xfd,0xeb,0x7f,0xdf,0xfa,0xff,0xde,0xf0,0xed,
+0xff,0xb1,0xf7,0xf9,0x1f,0xb5,0x5b,0xfe,0x7e,0xf7,0xbe,0xfd,0x7f,0x5f,0xb5,0xf7,
+0xff,0xff,0xd0,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x01,0x00,0x07,0x42,0x01,
+0x00,0x6a,0x18,0x50,0x80,0x00,0x00,0x02,0x40,0x01,0x01,0x20,0x01,0x01,0x24,0x14,
+0x21,0x10,0x02,0x08,0x07,0x08,0x00,0x40,0x10,0x80,0x58,0x00,0x84,0x80,0x18,0x10,
+0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xff,0xdb,0xb7,0xf3,
+0xdf,0x7c,0xf8,0x74,0xff,0xff,0x6f,0x7d,0x3f,0x7e,0xec,0x7f,0xc1,0xf5,0xff,0xcf,
+0x6f,0x9f,0xf9,0xdf,0xbe,0xe5,0xe7,0xff,0xd7,0xf3,0xdd,0xfb,0xff,0xfc,0xff,0xbf,
+0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xf0,0x2f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xff,0xb4,0xcf,0xef,0x77,0x6f,0x73,
+0x3a,0x4a,0x3a,0xcb,0xd4,0xf7,0x2e,0xd6,0xbd,0xbd,0xa1,0x3b,0xdf,0xd6,0xf7,0xee,
+0xd3,0x35,0xbd,0xfb,0xbd,0xce,0xeb,0x2b,0x4d,0x2f,0xbb,0xda,0xff,0xff,0xfe,0xb0,
+0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdf,0x5f,0x36,0xaf,0x3f,0xed,0xb7,
+0xf5,0xfd,0xf3,0x2b,0xef,0x77,0xff,0xfb,0xda,0xb1,0xbd,0xa3,0x77,0x69,0x7f,0x4f,
+0xff,0xdb,0xfa,0x5b,0xff,0xf2,0xfe,0xff,0x96,0xff,0xff,0xfe,0xdf,0xff,0xd0,0xaf,
+0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x8f,0xfd,0x40,0x6f,0x9e,0x83,0x5a,0x0f,
+0xfa,0xc3,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xd0,0x00,0xfe,0xbf,0xcd,0x3f,0xf0,
+0xef,0xfc,0xc5,0x0c,0x3f,0xfd,0x68,0x0b,0xff,0xff,0xff,0xfe,0xdf,0xf0,0xff,0xff,
+0xff,0xff,0xfe,0xff,0xbb,0xff,0xfd,0x85,0xff,0xd4,0x6f,0x9f,0xc3,0x5a,0x0f,0xff,
+0xff,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xf0,0xfb,0xc2,0xbf,0xfc,0x00,0x37,0xef,
+0xfc,0xcd,0xbc,0x3f,0xff,0x0c,0xbf,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xff,0xd9,0xf7,0xd1,0xb7,0x7e,0x7f,0xf1,0xe4,0xfd,0xff,
+0xfb,0xfb,0xff,0x5f,0xff,0x7f,0xb1,0xbc,0x0f,0x67,0xeb,0xb8,0x3f,0xff,0xe2,0xff,
+0xe9,0xff,0xfd,0xe3,0xff,0x3f,0x9f,0xc2,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,
+0xfe,0xf5,0x7f,0xff,0xf0,0x3f,0xbc,0xff,0xd5,0xf5,0xce,0x3f,0xfe,0xff,0xfe,0x6d,
+0xff,0xf1,0xbf,0x7b,0xff,0xf1,0xfd,0xff,0x4f,0xff,0x87,0xff,0xae,0xff,0xb1,0xf8,
+0xfe,0xff,0xff,0x78,0x01,0xb9,0xff,0xff,0xff,0xfa,0xf0,0x2f,0xff,0xff,0xff,0xfe,
+0xf3,0xc0,0x00,0x00,0x00,0x04,0x02,0x13,0x02,0x00,0x80,0x40,0x00,0x90,0x10,0x00,
+0x10,0x00,0x02,0x00,0x01,0x20,0x80,0x12,0x10,0x00,0x40,0x08,0x00,0x04,0x00,0x00,
+0x02,0x00,0x01,0x40,0x00,0x80,0x00,0x00,0x3c,0xf0,0xef,0xff,0xff,0xff,0xfe,0xfd,
+0x1f,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xf7,0xdf,0xf7,0xff,
+0xf7,0xfb,0xeb,0xd1,0xff,0xff,0xff,0xff,0xef,0xf7,0xff,0xff,0xfb,0xff,0xfe,0xff,
+0xff,0x7e,0xff,0xfb,0xff,0xff,0xff,0xdb,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf0,0xff,
+0xff,0xb7,0xeb,0xf7,0xdf,0xff,0xfe,0xf5,0x6b,0xe7,0xed,0xf7,0x3e,0xec,0xff,0x54,
+0xef,0x6f,0xf1,0xf5,0xaf,0x6f,0xf6,0xfd,0xff,0xdd,0x7b,0xff,0xef,0xbf,0x7f,0xff,
+0xff,0xf7,0xff,0xf3,0x5f,0xf7,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,
+0x80,0x40,0x04,0x00,0x81,0x2c,0x04,0x24,0x00,0x02,0x01,0xc8,0x02,0x00,0x02,0x24,
+0x00,0x01,0xb4,0x42,0xdc,0x44,0x02,0x15,0x90,0x02,0x03,0x48,0x39,0x10,0x02,0x24,
+0xa0,0xba,0x00,0x00,0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
+0xfe,0xfc,0xf7,0xf0,0xee,0xb6,0x5d,0xfd,0xf5,0xff,0xdb,0xf7,0x7f,0x7f,0xbe,0xff,
+0xc1,0xfe,0xbf,0xfa,0xfa,0x5f,0xff,0xad,0xff,0xef,0xff,0x7f,0xdf,0x7f,0xfe,0xbf,
+0xb7,0x94,0xbf,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xfb,0xb5,0xff,
+0xef,0x7c,0xeb,0x2b,0x52,0x5b,0x3b,0xda,0xd4,0xf3,0x36,0x96,0xb5,0xbd,0xf1,0xfb,
+0xda,0xee,0xf6,0xfe,0xd3,0x35,0xbd,0xdf,0xad,0xcf,0xef,0x7e,0xcd,0x6b,0xbb,0xdf,
+0xff,0xff,0xfd,0xb0,0xef,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xd3,0x5f,0xf6,
+0xff,0xf6,0xff,0xfd,0xad,0xfd,0xff,0x7f,0xef,0xff,0x6f,0x7f,0xdb,0xf1,0xa5,0xa3,
+0x7f,0x6f,0x6b,0x4f,0xff,0xdb,0xfb,0xcb,0xff,0xf6,0xff,0xf4,0xd7,0xfd,0xbf,0xfe,
+0xdf,0xff,0xd0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdf,0xff,0xff,0xff,
+0x3f,0x7f,0xfc,0xe5,0xff,0x20,0xfe,0xff,0xff,0xdf,0x7f,0xff,0xf1,0x7f,0xff,0xfe,
+0xff,0xf0,0x7c,0x3d,0x4f,0xf3,0xc3,0x3f,0xff,0xff,0x6f,0xc3,0xff,0x0f,0xff,0xff,
+0xaf,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0xb7,0xe0,0x0f,0xff,0xff,0x2b,
+0xff,0x7d,0xbf,0xff,0xdf,0xff,0xff,0xf8,0x9f,0x7f,0xff,0xf1,0x55,0xff,0xff,0xff,
+0xfd,0x7c,0x3c,0xff,0xf3,0xc3,0x3f,0xff,0xff,0xef,0xc3,0xff,0xdf,0xff,0xff,0xff,
+0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0x9f,0xbf,0x7f,
+0xf9,0x19,0x47,0x8e,0xe7,0x9f,0x3f,0x17,0xff,0xfc,0x81,0xc1,0x7e,0xf3,0xd9,0xf9,
+0x73,0xdf,0xf4,0x7f,0xfa,0xff,0xff,0xff,0xfb,0x7f,0x77,0xc7,0xff,0xff,0xff,0xf0,
+0x2f,0xff,0xff,0xff,0xfe,0xf5,0xf7,0xff,0xfb,0xff,0xf7,0x3f,0xfc,0xbf,0x3e,0x3f,
+0xec,0xff,0x81,0xaf,0xfe,0x4f,0xf3,0xbb,0xff,0xf0,0x7e,0xff,0x6f,0xff,0x87,0xff,
+0xbb,0xff,0xd5,0xfc,0xff,0x7f,0xfc,0x6f,0xff,0xef,0xe7,0xff,0xff,0xfa,0xf0,0x3f,
+0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+0x00,0x30,0x10,0x60,0x20,0x00,0x08,0x00,0x01,0x20,0x80,0x00,0x10,0x00,0x04,0x00,
+0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x40,0x00,0x08,0x20,0x3c,0xf0,0x6f,0xff,
+0xff,0xff,0xfe,0xf5,0xbf,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x7f,0xfe,0x3f,0xff,
+0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xf1,0xdf,0xdf,0xff,0xff,0xff,0x7f,0xdf,0xff,
+0xfd,0xbd,0xff,0xff,0xff,0xfb,0xdf,0xff,0xff,0xff,0xff,0x5b,0xf0,0xff,0xff,0xff,
+0xff,0xfe,0xf0,0xbf,0xbf,0xbf,0xff,0xf7,0xfb,0xff,0xfe,0xee,0xfa,0xff,0xff,0xff,
+0x3d,0x3b,0xff,0xff,0xfe,0xfb,0xf1,0xff,0xbf,0x7b,0xff,0xff,0xef,0xff,0xbf,0xff,
+0xff,0xff,0xff,0xff,0xfe,0xff,0xf7,0xef,0xff,0xfb,0xd0,0xf0,0xdf,0xff,0xff,0xff,
+0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x00,0x0b,0x10,0x05,0x01,0x00,0x08,0x00,0x02,
+0x01,0x01,0x00,0x00,0x10,0x01,0xc8,0x08,0x00,0x00,0x00,0x00,0x42,0x02,0x00,0x00,
+0x00,0x80,0x02,0x00,0x00,0x40,0x24,0x80,0x00,0xc1,0xf0,0x3f,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xf7,0xfd,0xf7,0xfa,0xef,0xee,0xf9,0xfd,0xff,0xf7,0xfe,0xbf,
+0x1f,0xfd,0x9e,0xfd,0xd1,0xef,0xff,0xf7,0x7f,0x9f,0xff,0xef,0xff,0xf6,0xff,0xfe,
+0xfe,0x7b,0xff,0xbd,0xff,0x7e,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,0xff,
+0xff,0xf7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xfd,0xff,0xff,0xdf,0xff,
+0xff,0x5f,0xf1,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xef,0xff,
+0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfb,0xff,0xff,0xef,0xfb,0xfd,
+0xff,0xf1,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf7,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xe7,0xff,
+0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfb,0xff,0xfb,0xf1,
+0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7b,0xff,0xff,0xff,0x7f,0xff,0xf1,0xff,
+0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x57,0xff,0xfe,0xbf,0xfb,0xf1,0xff,0xff,
+0xfd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xd7,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd,
+0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xef,0x2f,0xf1,0x3c,0xbf,0xbc,
+0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff,
+0x01,0xe2,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff };
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hamradio/yam9600.h linux/drivers/net/hamradio/yam9600.h
--- v2.3.12/linux/drivers/net/hamradio/yam9600.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hamradio/yam9600.h	Thu Aug  5 14:35:52 1999
@@ -0,0 +1,343 @@
+/*
+ *
+ * File yam111.mcs converted to h format by mcs2h
+ *
+ * (C) F6FBB 1998
+ *
+ * Tue Aug 25 20:23:03 1998
+ *
+ */
+
+static unsigned char bits_9600[]= {
+0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xfb,0xcb,0xff,0xdb,0xfe,0xf2,
+0xff,0xf6,0xff,0x9c,0xbf,0xfd,0xbf,0xef,0x2e,0x3f,0x6f,0xf1,0xfd,0xb4,0xfd,0xbf,
+0xff,0x6f,0xff,0x6f,0xff,0x0b,0xff,0xdb,0xff,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff,
+0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,
+0xfb,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0x7f,0xf1,0xff,0xfe,0xff,0xbf,0xbf,
+0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xf0,
+0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xf7,
+0xff,0xff,0xf7,0xef,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0x7e,0xff,0xff,
+0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0xdf,
+0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xef,0xff,0xf3,0xfb,0xfe,0xff,0xf1,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdf,0xff,0xf0,0x7f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,
+0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xef,0xff,0x7f,0xff,0xef,
+0xff,0xef,0xff,0x7f,0xef,0xf1,0xff,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xff,0xbd,0xff,0xef,0x7f,0xef,0x7f,0xfb,0xdf,0xd3,0x5a,0xfe,0xd7,0xd6,
+0xf7,0x7f,0xbd,0xf1,0xbb,0x5d,0xd6,0xf7,0xfe,0x96,0xff,0xbd,0xaf,0xad,0xbf,0xef,
+0x7f,0x6b,0x7f,0xfb,0xd6,0xfe,0xf7,0xff,0x10,0xef,0xff,0xff,0xff,0xfe,0xbe,0xef,
+0xff,0xff,0xdb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xbf,0xff,0x7f,0xff,0x7f,
+0xdf,0xdb,0xf1,0xfd,0x35,0xff,0x6f,0xff,0x6f,0xff,0xdb,0xff,0xcb,0xff,0xf6,0xff,
+0xf2,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,
+0xff,0xf1,0x24,0xf0,0xff,0xff,0xcf,0xef,0x3f,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,
+0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,0xff,
+0xf1,0x00,0xf0,0xff,0xff,0xcf,0xdf,0xff,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,0xff,
+0xff,0xff,0x7d,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfe,0x7f,0xdf,0xff,0xff,0xff,0xf1,
+0xff,0xcf,0xff,0xf3,0xff,0x97,0xff,0xff,0x8f,0xe7,0xff,0xff,0xfc,0x71,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xf7,0xef,0xff,0xff,0xfc,0x7b,0xff,0xf1,0x3f,
+0xff,0xef,0xff,0xcf,0xe3,0xe3,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xbf,0xff,
+0xbf,0xff,0xda,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
+0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0x9f,0xff,
+0xff,0xff,0xf7,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xdb,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xdf,0xbf,0xf1,0xfe,0xfd,0xf7,0xff,
+0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xfd,0xf2,
+0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
+0x00,0x00,0x00,0x02,0x00,0x90,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x04,0x24,0x00,
+0x40,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0xc0,0xf0,
+0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xbf,0xff,0xff,0x6f,0xff,0xdf,0xff,0xd1,0xff,0xfe,0xff,0xff,0xff,0xff,
+0xff,0xff,0xdf,0xff,0xfb,0xff,0xfb,0xef,0xff,0xff,0xee,0xff,0xff,0x7f,0xf0,0xdf,
+0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xad,0xff,0x69,0x2a,0xed,0x6b,0xfb,0xdf,0x3a,
+0xdc,0xf4,0x96,0xee,0xb3,0x3d,0x35,0xc1,0xbb,0xdd,0xfe,0xf6,0xfe,0xd6,0xb5,0xad,
+0xbf,0xa5,0xad,0x49,0x2f,0x4f,0x2b,0xda,0x5f,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,
+0xff,0xfe,0xbf,0xff,0xff,0xfb,0x5b,0xf7,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xa5,
+0xf3,0x6f,0xf3,0x6e,0xfa,0x7b,0xd1,0xfd,0xb5,0x77,0x6f,0xe9,0x6f,0xff,0xdb,0xfb,
+0xdb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0x3f,0xfe,0xf7,0xff,0xd0,0x4f,0xff,0xff,0xff,
+0xfe,0xff,0x9f,0xff,0xff,0x0f,0xff,0xc0,0x3f,0x9c,0x03,0xff,0xff,0x8b,0xa5,0xfe,
+0x80,0x3e,0xc2,0xbf,0xac,0xb1,0x24,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xa3,
+0xff,0xfd,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0x0f,0xff,0xc0,0x3f,0xd4,0x6b,0xff,0xff,0xdb,0xff,0xfe,0x86,
+0xbf,0xc2,0xbf,0x30,0xa1,0x24,0xff,0xff,0xff,0xff,0xcc,0xff,0x0f,0xff,0xa3,0xff,
+0x05,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xfb,0xc7,0xff,0xc4,0xff,0xff,0x7f,0xff,0xec,0xfe,0x7f,0xdf,0xd8,0xb9,
+0x47,0xfc,0x36,0xc1,0xdf,0xff,0xff,0xf9,0xff,0xf3,0xff,0xf7,0xff,0xfc,0xff,0xfd,
+0x3f,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,
+0xff,0xff,0xff,0xfe,0xff,0xff,0x7e,0xbd,0x3f,0xff,0x2b,0xfe,0x2f,0xf5,0xa3,0xfc,
+0x5b,0xfe,0x61,0x9f,0x7f,0xef,0xff,0xff,0xa7,0xfb,0xff,0xff,0xfa,0xfe,0xff,0x33,
+0xf1,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x24,0x04,
+0x00,0x01,0x00,0x80,0x40,0x00,0x08,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x02,0x00,
+0x00,0x00,0x00,0x00,0x01,0x3d,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xfd,0xbd,0xff,0xfd,
+0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,0xf6,0xef,0xbf,0xf7,0xff,0x73,0xeb,
+0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xfd,0xfe,0xff,0xff,
+0xff,0xff,0xff,0xff,0xd9,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,0xbf,0x7f,0xff,0xff,
+0xff,0x7f,0xff,0xff,0xde,0xff,0xff,0xef,0xdd,0xde,0x77,0xf2,0xfb,0xed,0xe7,0xf1,
+0x73,0xfd,0xfd,0xdf,0xff,0x7d,0xbe,0xdf,0xff,0xfb,0xff,0xef,0xff,0xef,0xff,0xff,
+0xff,0xff,0xff,0xd0,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x02,0x00,0x22,
+0x40,0xc0,0x00,0x00,0x00,0x08,0x00,0x02,0x41,0x02,0x12,0x00,0x21,0x87,0x81,0x00,
+0x00,0x80,0x04,0x0b,0x28,0x01,0xb0,0x00,0x82,0x00,0x40,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,
+0xf7,0xff,0xfe,0x7f,0xed,0x79,0xff,0xde,0xeb,0x7f,0x74,0xf7,0xf7,0xe1,0xf9,0xff,
+0xf6,0x5f,0x7f,0xff,0xff,0xff,0xd7,0xdb,0xef,0xff,0xbb,0xff,0xff,0xff,0xcc,0xff,
+0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x3d,0xcd,0x49,0x7f,0x6f,
+0x2b,0xba,0x5c,0xd2,0xda,0xf6,0xf3,0x3e,0xf7,0xff,0xbd,0xf1,0xfa,0xdf,0xfe,0xf7,
+0xcc,0xf6,0xbb,0xa5,0xb3,0xad,0xbf,0x6f,0x7d,0x6f,0x6b,0xdb,0xdf,0xbd,0xff,0xfe,
+0xb0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xfb,0xdb,0x57,0xf6,0xfe,0x9f,0xd5,
+0xb7,0xff,0xaf,0xe5,0x3f,0xff,0xff,0x6f,0xff,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0x69,
+0x6c,0xdf,0xda,0xdf,0xcb,0xff,0xf6,0xff,0x76,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,
+0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfd,0xbd,0x08,0x03,0x89,0x4f,0x5a,
+0x0f,0xf0,0xff,0xf8,0xbf,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xf3,
+0xfa,0xa0,0xf0,0xf2,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,
+0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xfd,0x00,0x6b,0xff,0xff,0x5a,0x0f,
+0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xb3,0xf5,
+0x50,0xf0,0xf0,0xff,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xbc,0xff,0xe4,0xe7,0x71,0xff,0xf9,0xc4,0xf4,
+0x7f,0x7f,0xcf,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xfb,0xf7,0x73,0xbf,0x14,
+0xff,0xe6,0xff,0xff,0xe1,0x7d,0xff,0xff,0xe7,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,
+0xff,0xfe,0xf5,0xff,0xff,0xfe,0xd2,0xfa,0xff,0xc4,0xf4,0x5c,0xbf,0xfa,0xff,0xff,
+0xec,0x7e,0xbf,0xff,0xff,0xff,0xf1,0xff,0xff,0xef,0xff,0xff,0x6b,0xdb,0xff,0xdf,
+0xf9,0xfb,0xbf,0xff,0xf1,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf0,0xbf,0xff,0xff,0xff,
+0xfe,0xf3,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x80,0x00,
+0x00,0x00,0x00,0x40,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x20,0x00,0x00,0x00,0x00,
+0x01,0x00,0x01,0x00,0x00,0x80,0x02,0x00,0x01,0x3c,0xf0,0x5f,0xff,0xff,0xff,0xfe,
+0xfd,0xbf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0x7f,0xff,0xdf,0xff,0xef,0xff,
+0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,
+0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xc3,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf0,
+0xff,0xdf,0xff,0xff,0xf7,0x23,0xff,0xff,0xfd,0xff,0xef,0xff,0xfe,0x7f,0x7d,0xf7,
+0xfe,0xff,0x7f,0x71,0xff,0xfb,0x7f,0xff,0xff,0xff,0x6e,0xfd,0xf7,0xfd,0xff,0xbf,
+0xff,0xbf,0xf9,0xfd,0xff,0xdf,0xef,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x30,
+0x40,0x01,0x00,0x83,0x00,0x00,0x00,0x0c,0x06,0x08,0x04,0x26,0x26,0x00,0x00,0x06,
+0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x70,0x08,0x80,0x00,0x20,0x01,0x20,
+0x00,0x02,0x00,0x30,0x00,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
+0xff,0xff,0x7b,0x3f,0xf7,0xff,0xd7,0xfe,0xfe,0xfb,0xfe,0x3b,0xfe,0xbd,0xff,0x2f,
+0xff,0x71,0xff,0xfb,0x7f,0xe7,0xff,0xf9,0xef,0xff,0xd7,0xfa,0xff,0xb7,0xbb,0xfe,
+0xff,0xff,0x74,0xff,0xf7,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xb5,
+0xbd,0x6f,0x7c,0xeb,0x7f,0xfb,0xdb,0xd3,0x4b,0xee,0xd6,0xf6,0xb7,0xfd,0xac,0xa1,
+0xfb,0xdf,0xfe,0xf7,0xf4,0x96,0xbd,0xb4,0xc5,0xa5,0xaf,0x6f,0x69,0x4f,0x7f,0xba,
+0xdb,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,
+0xf6,0xff,0xf6,0xff,0xbd,0xbf,0xa5,0xbf,0xff,0x7d,0x7f,0xef,0xff,0xfb,0xf1,0xfd,
+0xbf,0xff,0x6f,0xff,0x6b,0x7a,0xdb,0xff,0xdb,0xdf,0xf6,0xfe,0xb6,0xfd,0xfd,0xbf,
+0xfe,0xf7,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf4,0x2f,0xff,
+0xfc,0x43,0x6b,0xff,0xff,0xff,0x0d,0xff,0xfc,0x33,0x3f,0xf0,0x5f,0xf1,0xff,0xff,
+0xff,0xff,0xf9,0xde,0xf0,0x4c,0xfe,0x77,0xaf,0xff,0xff,0xef,0xff,0xf0,0xff,0xdb,
+0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xfe,0xf7,0xff,0xf0,0x2f,0xff,0xfd,
+0x43,0x7f,0xff,0xff,0xf1,0x0f,0xff,0xfc,0x33,0x3f,0xff,0xaf,0xf1,0xff,0xff,0xff,
+0xff,0xf6,0xd7,0xff,0xbc,0xfd,0xbd,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,
+0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xfb,0xf1,
+0xbf,0xff,0xf9,0xfd,0xcf,0xf2,0x70,0xff,0x1f,0x9f,0xf3,0xf1,0xff,0xff,0xff,0xff,
+0xfc,0xf7,0xff,0x13,0x9f,0xfc,0xff,0xff,0x84,0xf7,0xff,0xff,0x47,0xff,0xff,0xff,
+0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xf1,0xfc,0xff,0xfe,0xfe,0x79,
+0x3f,0xff,0x1d,0x46,0xcf,0xff,0xcf,0xfc,0x7b,0xff,0xf1,0xff,0xff,0xff,0xff,0xed,
+0xf3,0xab,0xff,0xcb,0xff,0xf8,0xff,0xfc,0xf5,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,
+0x8f,0xff,0xff,0xff,0xfe,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
+0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x20,
+0x0c,0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x01,0x3c,0xf0,0x7f,
+0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,
+0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xef,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,
+0xff,0xdf,0xff,0xff,0xfb,0xf7,0x7f,0xff,0xfe,0xff,0xff,0xbf,0xdb,0xf0,0xff,0xff,
+0xff,0xff,0xfe,0xf0,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0x7f,0xf7,0xff,
+0xbf,0xbf,0xcf,0xff,0xff,0xff,0x3e,0xf1,0x7f,0xff,0xff,0xef,0xff,0xff,0xff,0xfe,
+0xff,0xfd,0xff,0xbf,0xbd,0xfe,0xff,0xfb,0xf7,0xdf,0xfb,0xd0,0xf0,0x9f,0xff,0xff,
+0xff,0xfe,0xf8,0x30,0x20,0x00,0x40,0x01,0x80,0xc0,0x30,0x00,0x00,0x20,0x00,0x10,
+0x50,0x88,0x20,0x00,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,
+0x00,0x00,0x01,0x80,0x08,0x00,0x00,0xa0,0x00,0x10,0xc1,0xf0,0xef,0xff,0xff,0xff,
+0xfe,0xfd,0xef,0x7f,0xff,0xff,0xbf,0xff,0xf7,0xff,0xef,0xfb,0xfd,0x77,0xef,0xbf,
+0xf7,0x7f,0xff,0xff,0xbf,0xd1,0x7f,0xff,0xff,0xf7,0xff,0xff,0xff,0xff,0xaf,0xff,
+0xdf,0xf7,0xfb,0xff,0xfd,0xff,0xfc,0xff,0xfd,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,
+0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x3f,0xff,0xff,0xff,0xfe,0xdd,0xff,
+0xff,0xff,0xa5,0xfd,0x6f,0x7d,0x6d,0x7f,0x52,0xdf,0x5a,0x4b,0xee,0xb6,0xee,0xf2,
+0xbb,0xac,0xa1,0x5b,0x4d,0xd6,0xf7,0xfe,0xb2,0xbd,0x35,0xb5,0xb5,0xdd,0x6f,0x7f,
+0xe9,0x5f,0x52,0xdf,0xbd,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,
+0xff,0xdb,0xfe,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xb5,0xbf,0xf9,0x7f,0x6f,0xff,
+0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0x69,0x7f,0xdb,0xff,0xd3,0xff,0xf6,0xfe,0xf2,
+0xff,0xad,0xbf,0xff,0xff,0xff,0xd0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,
+0x30,0x0f,0xff,0xff,0xfd,0x6b,0xca,0xff,0xf0,0x0f,0xd6,0xbf,0xcf,0x3f,0xff,0xff,
+0xf1,0xff,0xff,0xff,0xca,0xfe,0xbf,0xff,0xf0,0x05,0xaf,0x0f,0xff,0xfc,0xf0,0xcf,
+0xf0,0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0x30,
+0x0f,0xff,0xff,0xfc,0x3f,0xca,0xff,0x0f,0x0f,0xd6,0xbf,0xff,0xff,0xf5,0x5f,0xf1,
+0xff,0x8b,0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xfc,0xf0,0xcf,0xf0,
+0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xcf,0xff,
+0xff,0xbf,0x9f,0x3f,0xfe,0xfc,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xf7,0xf1,0xff,
+0xdf,0xfe,0x7e,0x3f,0x9f,0xf4,0xfc,0x7f,0xfc,0xff,0xff,0x3f,0xff,0x3f,0xfe,0x3f,
+0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfb,0xff,0xfe,0xff,
+0xff,0xff,0xff,0xbf,0xfb,0xff,0xf8,0xed,0xff,0x8f,0xff,0xbb,0xff,0xb1,0xf3,0xef,
+0x8f,0xf7,0xff,0xff,0xdb,0xff,0xff,0xff,0xef,0xbf,0xfd,0x79,0xbf,0xbf,0xff,0xff,
+0xff,0xfb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x04,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04,0x08,0x08,0x01,0x01,0x00,0x90,
+0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x00,0x01,
+0x3c,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0x9f,0xff,0xaf,0xdf,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,
+0xbf,0xef,0xff,0xff,0xff,0xed,0xff,0xff,0xff,0xef,0xff,0xbf,0xff,0xff,0xff,0xc3,
+0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xfd,0xff,0xff,0xff,0xfb,0xff,0xbb,0xff,
+0xff,0xff,0x7f,0xf6,0xff,0x7f,0xfb,0xfd,0xed,0xff,0xf1,0xff,0xfe,0x7f,0xff,0xff,
+0xff,0x5f,0xff,0xf7,0xff,0x7e,0xff,0xfd,0xff,0xef,0xff,0xff,0xff,0xef,0xf0,0xf0,
+0x8f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x80,0x00,0x04,0x00,0x00,0x40,0x02,0x00,0x03,
+0x00,0x05,0x04,0x20,0x00,0x00,0x01,0xd0,0x00,0x81,0x00,0x20,0x04,0x04,0x00,0x00,
+0x81,0x04,0x08,0x80,0x10,0x00,0xc0,0x00,0x00,0x00,0x20,0x00,0x08,0xc1,0xf0,0x6f,
+0xff,0xff,0xff,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xf3,0xfd,0xff,0xed,0xfc,
+0xff,0xff,0x9f,0xfb,0xfd,0xff,0xff,0xff,0xf1,0xff,0xff,0x7f,0xfb,0x3e,0xff,0x9f,
+0xff,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0x6f,0xff,
+0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xfd,0xbd,0xff,0xef,0x7c,0xeb,0x7f,0xfb,0xdb,0xfa,0xdc,
+0xee,0xf7,0xf6,0xd7,0xf5,0x2d,0xa1,0xbb,0xdd,0xee,0xf7,0x54,0xf7,0xfb,0x2c,0xb5,
+0xb4,0xbd,0x6b,0x6f,0xef,0x6f,0xbb,0xdf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,
+0xfe,0xbf,0xff,0xff,0xff,0xfb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xff,0xbf,0xef,
+0x6f,0xff,0x6f,0xfa,0xdb,0xf1,0xc5,0xbd,0xf5,0x6f,0xff,0x6f,0xca,0xdb,0xff,0xdb,
+0xfb,0xf6,0x97,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x9f,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0x7f,0xff,0xff,0xe7,0x63,0xff,0xff,
+0xff,0xfc,0x77,0xdf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,
+0xc3,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xfc,0xff,0xcf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,0xc3,
+0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xbf,0xff,0xca,0xff,0x9f,0xff,0xfa,0xb9,0xe7,
+0x9f,0xf3,0x81,0xff,0xff,0xfc,0x73,0xd7,0xff,0xff,0x77,0xff,0xfd,0xff,0xfc,0xff,
+0xff,0xff,0xff,0xcf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,
+0xff,0xf7,0xde,0xff,0xfe,0x7e,0xff,0xbf,0xff,0xbf,0xf1,0xb3,0xff,0xff,0xe3,0xfb,
+0xff,0xe1,0x1f,0x7f,0xff,0xf8,0x78,0xff,0xfb,0x1e,0xff,0xf7,0xfe,0xe7,0xff,0xff,
+0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x04,0x00,
+0x01,0x80,0x40,0x40,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
+0x80,0x00,0x00,0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xff,
+0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xf7,0xf1,
+0xfd,0xff,0xff,0xff,0xdf,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,
+0xff,0xff,0xff,0xdb,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xdf,0xff,0xff,0x7f,
+0xff,0xff,0xff,0xbe,0xd7,0xff,0xed,0xbd,0x7e,0xbf,0xfe,0xf6,0x7f,0xbf,0x71,0xff,
+0xff,0xda,0xff,0xf9,0xff,0xbf,0x7f,0xfe,0xff,0x6f,0x7f,0xff,0xff,0xff,0xff,0xff,
+0x7f,0xff,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x42,0x00,0x00,0x00,0x00,
+0x80,0xc1,0x00,0x00,0x90,0x00,0xc4,0x00,0x00,0x12,0x20,0x43,0x22,0x81,0x84,0x00,
+0x00,0x14,0x00,0x01,0x00,0x08,0x80,0x00,0x02,0x00,0x02,0x00,0x04,0x02,0x00,0x00,
+0x10,0xc1,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfd,0xff,0xff,0xdd,0xfe,0xff,
+0xb6,0x76,0xe5,0xbc,0xf9,0xf7,0xaf,0x5f,0xbf,0xfc,0xdf,0xcf,0xf1,0xff,0xef,0x79,
+0xff,0xbd,0xff,0xef,0xff,0xff,0xf7,0x6f,0x5f,0xff,0xff,0xfd,0xef,0xef,0xbf,0xff,
+0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xf0,0xff,0xff,0xff,0xff,0xfe,0xdb,0xff,0xff,0xfd,0x2d,0xff,0x69,0x2a,0xef,0x77,
+0xbb,0xdd,0x5a,0xdf,0xf6,0xf6,0xd6,0xf7,0x7d,0xbd,0xd1,0xb2,0x4a,0xd6,0xb2,0xbe,
+0x97,0xf5,0xbd,0xb3,0xad,0xff,0xef,0x7f,0x69,0x6b,0xfb,0xdf,0xff,0xff,0xff,0xf0,
+0x2f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0x9f,0xd4,0xbf,
+0xed,0xaf,0xff,0x6b,0x6f,0xf7,0xff,0xdd,0xdb,0x31,0xfd,0xbf,0xff,0x6f,0x7f,0xff,
+0xff,0xdb,0xff,0xcb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x8f,
+0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,
+0xa5,0xff,0xff,0xff,0xdf,0xb7,0xff,0xff,0xf1,0xff,0xff,0xff,0xf7,0xe9,0x6a,0xbf,
+0xff,0xff,0xfd,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xaf,0xf0,0x4f,0xff,
+0xff,0xff,0xfe,0xfe,0xdf,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,0xa5,
+0xff,0xff,0xff,0xc0,0x37,0xff,0xff,0xf1,0x99,0x8e,0xdc,0x7f,0xe9,0x6a,0xbf,0xff,
+0xf0,0x0f,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xff,0x07,0xff,0xc0,0xbe,0xff,0xff,0xcf,0xef,0x9f,0xff,
+0xff,0xfb,0xff,0xe7,0xff,0xff,0xa1,0xe3,0xce,0x3c,0x58,0x3f,0xf3,0xff,0xfd,0xef,
+0xf9,0xff,0xff,0xf7,0xf1,0x7f,0xff,0xcb,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,
+0xfe,0xf5,0x7f,0xff,0xf0,0xff,0xfe,0xff,0xc4,0x75,0xe7,0xb9,0xff,0xff,0xff,0xef,
+0xff,0xc7,0x37,0x3b,0xff,0xf0,0x13,0x9e,0x0f,0xf4,0xff,0xfe,0xfb,0xff,0xff,0xf9,
+0xfc,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xef,0xff,0xff,0xff,0xfe,
+0xf3,0xc0,0x01,0x00,0x00,0x02,0x00,0x02,0x22,0x00,0x00,0xc0,0x40,0x00,0x40,0x00,
+0x04,0x08,0x04,0x0a,0x01,0x01,0x10,0x20,0x20,0x00,0x00,0x04,0x08,0x08,0x04,0x00,
+0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x3c,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xfd,
+0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0xcf,0x9d,0xff,
+0xff,0xf7,0xfd,0xf1,0xff,0xff,0xff,0xee,0xbf,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xff,
+0xff,0xff,0xf7,0xf7,0xff,0xff,0xfe,0xbf,0xf7,0xff,0xff,0x5b,0xff,0xbf,0xf7,0xff,
+0xfd,0x7f,0x71,0xfd,0xff,0xed,0xf7,0xfe,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,
+0xff,0xff,0xef,0xff,0x7f,0xff,0xd0,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf8,0x30,0x11,
+0x00,0x48,0x60,0x40,0x82,0x60,0x24,0x60,0x00,0xcc,0x00,0x80,0x04,0x01,0x00,0x00,
+0x14,0x01,0x0c,0x04,0x00,0x30,0x00,0x00,0x00,0x08,0x08,0x00,0x01,0x00,0xc2,0x00,
+0x00,0x02,0x00,0x80,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,
+0xf7,0x7b,0xff,0xf3,0xeb,0xbf,0xff,0xf7,0xff,0xff,0xff,0xe7,0x5d,0x3f,0xff,0xf6,
+0xd1,0xfd,0xff,0xeb,0xf7,0x3d,0xff,0xff,0xff,0x5f,0xff,0x7f,0x7f,0xf3,0xff,0xff,
+0xef,0xfd,0xbf,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xb5,0xdf,
+0x6f,0x7d,0x69,0x7f,0xfb,0xdf,0x52,0x5f,0xf6,0xf7,0xfe,0xf6,0xf3,0xbd,0xb1,0xda,
+0xcd,0xfe,0xf6,0xee,0xd2,0xbd,0xa5,0xaf,0xbd,0xff,0x6f,0x7c,0xeb,0x2b,0xfa,0xda,
+0xff,0xfe,0xdf,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,
+0xff,0xf6,0xff,0xbd,0xbf,0xcd,0xbf,0xeb,0x6f,0xf7,0x6f,0xdf,0xdb,0x51,0xfd,0xbd,
+0xff,0x6f,0xff,0x6f,0xfb,0x5b,0xff,0xdb,0xff,0xf6,0xfe,0xf6,0xfd,0xfd,0xbf,0xfe,
+0xf7,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfa,0x50,0xff,0xff,0xff,
+0xf0,0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0xfc,0xff,0xff,
+0xf7,0xdb,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,
+0xaf,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xa0,0xff,0xff,0xff,0xf0,
+0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,
+0xf3,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,0xff,
+0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0x9f,0xf0,0x7f,
+0xff,0xf9,0xfc,0x4f,0xf3,0xff,0x27,0xeb,0xff,0xfc,0x81,0xfc,0x7f,0xfe,0x7b,0xff,
+0xf7,0xff,0x12,0x7f,0xff,0xff,0xff,0xff,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,
+0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xdf,0xfe,0xff,0xfc,0x7e,0x7f,0xbf,
+0xff,0xff,0xaf,0xef,0xff,0xdf,0xdf,0xfb,0xff,0xf1,0xc3,0xfe,0x6f,0xf1,0xcf,0x3f,
+0xfb,0xff,0xff,0xcf,0xfe,0xff,0xff,0xfe,0x7f,0xbf,0xff,0xff,0xbf,0xfa,0xf0,0xdf,
+0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
+0x20,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x80,0x00,0x02,0x3c,0xf0,0x2f,0xff,
+0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xf1,0xff,0x7f,0xff,0xff,0xff,0xff,0xef,0xff,
+0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x2f,0xff,0xff,
+0xff,0xfe,0xf0,0xff,0xff,0xff,0xfb,0xff,0xbf,0xff,0xff,0xff,0xff,0xf7,0xbf,0xfb,
+0xff,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xf7,0xbf,0xfb,0xff,0xff,0xff,0x7f,0xde,0xff,
+0xff,0xff,0xff,0xff,0xff,0xed,0xf7,0xff,0xff,0x7f,0xd0,0xf0,0x3f,0xff,0xff,0xff,
+0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x80,
+0x20,0x01,0x01,0x92,0x00,0x01,0x01,0x00,0xe0,0x1c,0x60,0x20,0x30,0x08,0x08,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xc1,0xf0,0x6f,0xff,0xff,0xff,0xfe,
+0xff,0xff,0xff,0xff,0xff,0xdb,0xfe,0xff,0xff,0xdf,0xff,0xfc,0x7f,0xfb,0xbf,0xff,
+0xff,0xff,0xff,0xff,0xf1,0xf6,0xff,0xf7,0x7e,0x3f,0xff,0x7f,0xff,0xff,0xff,0xf7,
+0xff,0xff,0xff,0xed,0xff,0xdf,0xff,0xb7,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,
+0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xbf,0xff,0xdf,
+0x57,0xef,0xf1,0xfd,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfb,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
+0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xdf,0xff,
+0xff,0xf1,0xfd,0xff,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xf7,0xfd,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,
+0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,
+0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0x6f,0xff,0xfe,0xbf,0xff,0xf1,0xff,
+0xf7,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,
+0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0x57,0xff,0xfd,0xbf,0xff,0xf1,0xff,0xef,
+0xfe,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,
+0xde,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd,
+0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xe7,0x2f,0xf1,0x3c,0xbf,0xfd,
+0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff,
+0x02,0x01,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff };
diff -u --recursive --new-file v2.3.12/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.3.12/linux/drivers/net/hp100.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/net/hp100.c	Thu Aug  5 15:04:52 1999
@@ -419,7 +419,7 @@
             continue;
           }
           /* found... */
-          ioaddr = pci_dev -> base_address[ 0 ] & ~3;
+          ioaddr = pci_dev ->resource[ 0 ].start;
           if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
           pci_read_config_word( pci_dev, PCI_COMMAND, &pci_command );
           if ( !( pci_command & PCI_COMMAND_IO ) ) {
diff -u --recursive --new-file v2.3.12/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.3.12/linux/drivers/net/irda/toshoboe.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/irda/toshoboe.c	Thu Aug  5 15:04:52 1999
@@ -713,7 +713,7 @@
   dev_self[i] = self;
 
   self->pdev = pci_dev;
-  self->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+  self->base = pci_dev->resource[0].start;
 
   idev = &self->idev;
 
@@ -850,7 +850,7 @@
       if (pci_dev)
         {
           printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
-                  pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK,
+                  pci_dev->resource[0],
                   pci_dev->irq);
 
           if (!toshoboe_open (pci_dev))
diff -u --recursive --new-file v2.3.12/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.3.12/linux/drivers/net/lance.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/lance.c	Thu Aug  5 15:04:52 1999
@@ -382,7 +382,7 @@
 			unsigned short pci_command;
 
 			pci_irq_line = pdev->irq;
-			pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+			pci_ioaddr = pdev->resource[0].start;
 			/* PCI Spec 2.1 states that it is either the driver or PCI card's
 	 		 * responsibility to set the PCI Master Enable Bit if needed.
 			 *	(From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
diff -u --recursive --new-file v2.3.12/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.3.12/linux/drivers/net/macsonic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/macsonic.c	Mon Aug  9 12:32:28 1999
@@ -0,0 +1,485 @@
+/*
+ * macsonic.c
+ *
+ * (C) 1998 Alan Cox
+ *
+ * Debugging Andreas Ehliar, Michael Schmitz
+ *
+ * Based on code
+ * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
+ * 
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ * 
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ * A driver for the Mac onboard Sonic ethernet chip.
+ *
+ * 98/12/21 MSch: judged from tests on Q800, it's basically working, 
+ *		  but eating up both receive and transmit resources
+ *		  and duplicating packets. Needs more testing.
+ *
+ * 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/nubus.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/macintosh.h>
+
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <config/macsonic.h>
+
+#define SREGS_PAD(n)    u16 n;
+
+#include "sonic.h"
+
+extern int mac_onboard_sonic_probe(void);
+
+static int setup_debug = -1;
+static int setup_offset = -1;
+static int setup_shift = -1;
+
+/*
+ * This seems to be the right default for the Q800
+ */
+
+static int reg_offset = 0;
+static int reg_shift = 0;
+
+/*
+ * Macros to access SONIC registers
+ */
+ 
+#define MAC_SONIC_REGISTERS	0x50F0A000
+#define MAC_SONIC_PROM_BASE	0x50f08000
+#define MAC_SONIC_IRQ		9	/* Nubus 9 */
+
+/*
+ *    FIXME: We may need to invert the byte ordering. These should
+ *      be ok for other aspects as they are uncached spaces.
+ *      The original macros from jazzsonic.c works for me
+ *      on my LC 630, YMMV /Andreas Ehliar
+ */
+
+#if 0
+#define SONIC_READ(reg) \
+	*((volatile unsigned int *)base_addr+((reg)<<2)+2)
+
+#define SONIC_WRITE(reg,val) \
+	*((volatile unsigned int *)base_addr+((reg)<<2)+2) = val
+#else
+#define SONIC_READ(reg) \
+	*((volatile unsigned int *)base_addr+reg)
+
+#define SONIC_WRITE(reg,val) \
+	*((volatile unsigned int *)base_addr+reg) = val
+#endif
+
+#define SONIC_READ_PROM(addr) \
+	*((volatile unsigned char *)prom_addr+addr)
+/*
+ * Function : mac_sonic_setup(char *str, int *ints)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+ * Currently unused in the new driver; need to add settable parameters to the 
+ * detect function.
+ *
+ */
+
+void mac_sonic_setup(char *str, int *ints) {
+	/* Format of macsonic parameter is:
+	 *   macsonic=<debug>,<offset>,<shift>
+	 * Negative values mean don't change.
+	 */
+	
+	/* Grmbl... the standard parameter parsing can't handle negative numbers
+	 * :-( So let's do it ourselves!
+	 */
+
+	int i = ints[0]+1, fact;
+
+	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
+		if (*str == '-')
+			fact = -1, ++str;
+		else
+			fact = 1;
+		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
+		if ((str = strchr( str, ',' )) != NULL)
+			++str;
+	}
+	ints[0] = i-1;
+	
+	if (ints[0] < 1) {
+		printk( "mac_sonic_setup: no arguments!\n" );
+		return;
+	}
+
+	if (ints[0] >= 1) {
+	       	/* 0 <= n <= 2 */
+		if (ints[1] >= 0 && ints[1] <= 8)
+			setup_debug = ints[1];
+		else if (ints[1] > 16)
+			printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] );
+	}
+	if (ints[0] >= 2) {
+	       	/* 0 <= n <= 2 */
+		if (ints[2] >= 0 && ints[2] <= 16)
+			setup_offset = ints[2];
+		else if (ints[2] > 16)
+			printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] );
+	}
+	if (ints[0] >= 3) {
+	       	/* 0 <= n <= 2 */
+		if (ints[3] >= 0 && ints[3] <= 16)
+			setup_shift = ints[3];
+		else if (ints[3] > 16)
+			printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] );
+	}
+}
+
+static int sonic_debug = 0;
+
+/*
+ * For reversing the PROM address
+ */
+
+static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
+				    1, 9, 5, 13, 3, 11, 7, 15};
+
+__initfunc(int mac_onboard_sonic_probe(void))
+{
+	struct device *dev;
+	unsigned int silicon_revision;
+	unsigned int val;
+	struct sonic_local *lp;
+	int i;
+	int base_addr = MAC_SONIC_REGISTERS;
+	int prom_addr = MAC_SONIC_PROM_BASE;
+	static int one=0;
+	
+	if (!MACH_IS_MAC)
+		return -ENODEV;
+
+	if(++one!=1)	/* Only one is allowed */
+		return -ENODEV;
+
+	printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
+
+	if (macintosh_config->ether_type != MAC_ETHER_SONIC)
+	{
+		printk("none.\n");
+		return -ENODEV;
+	}
+	
+	printk("yes\n");
+	
+	if (setup_debug >= 0)
+	  sonic_debug = setup_debug;
+
+	/*
+	 * This may depend on the actual Mac model ... works for me.
+	 */
+	reg_offset = 
+	  (setup_offset >= 0) ? setup_offset : 0;
+	reg_shift = 
+	  (setup_shift >= 0) ? setup_shift : 0;
+
+	/*
+	 * get the Silicon Revision ID. If this is one of the known
+	 * one assume that we found a SONIC ethernet controller at
+	 * the expected location.
+	 * (This is not implemented in the Macintosh driver yet; need
+	 * to collect values from various sources. Mine is 0x4 ...)
+	 */
+
+	silicon_revision = SONIC_READ(SONIC_SR);
+	if (sonic_debug > 1)
+		printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision);
+
+	/*
+	 * We need to allocate sonic_local later on, making sure it's
+	 * aligned on a 64k boundary. So, no space for dev->priv allocated
+	 * here ...
+	 */
+	dev = init_etherdev(0,0);
+	
+	if(dev==NULL)
+		return -ENOMEM;
+
+	printk("%s: %s found at 0x%08x, ",
+	       dev->name, "SONIC ethernet", base_addr);
+
+	if (sonic_debug > 1)
+		printk("using offset %d shift %d,", reg_offset, reg_shift);
+
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = base_addr;
+	dev->irq = MAC_SONIC_IRQ;
+
+	/*
+	 * Put the sonic into software reset, then
+	 * retrieve and print the ethernet address.
+	 */
+
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+
+	/*
+	 *        We can't trust MacOS to initialise things it seems.
+	 */
+
+	if (sonic_debug > 1)
+		printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR));
+	
+	SONIC_WRITE(SONIC_DCR,
+		    SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW);
+
+	/*
+	 *  We don't want floating spare IRQ's around, not on
+	 *  level triggered systems!
+	 *  Strange though - writing to the ISR only clears currently
+	 *  pending IRQs, but doesn't disable them... Does this make 
+	 *  a difference?? Seems it does ...
+	 */
+#if 1
+	SONIC_WRITE(SONIC_ISR,0x7fff);
+	SONIC_WRITE(SONIC_IMR,0);
+#else
+	SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT);
+#endif
+	
+	/* This is how it is done in jazzsonic.c
+	 * It doesn't seem to work here though.
+	 */
+	if (sonic_debug > 2) {
+		printk("Retreiving CAM entry 0. This should be the HW address.\n");
+		
+		SONIC_WRITE(SONIC_CEP, 0);
+		for (i = 0; i < 3; i++)
+		{
+			val = SONIC_READ(SONIC_CAP0 - i);
+			dev->dev_addr[i * 2] = val;
+			dev->dev_addr[i * 2 + 1] = val >> 8;
+		}
+
+		printk("HW Address from CAM 0: ");
+		for (i = 0; i < 6; i++)
+		{
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+		printk("\n");
+
+		printk("Retreiving CAM entry 15. Another candidate...\n");
+
+		/*
+		 * MacOS seems to use CAM entry 15 ...
+		 */
+	       	SONIC_WRITE(SONIC_CEP, 15);
+		for (i = 0; i < 3; i++)
+		{
+			val = SONIC_READ(SONIC_CAP0 - i);
+			dev->dev_addr[i * 2] = val;
+			dev->dev_addr[i * 2 + 1] = val >> 8;
+		}
+
+		printk("HW Address from CAM 15: ");
+		for (i = 0; i < 6; i++)
+		{
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+		printk("\n");
+	}
+
+	/*
+	 * if we can read the PROM, we're safe :-)
+	 */
+	if (sonic_debug > 1)
+		printk("Retreiving HW address from the PROM: ");
+
+	for(i=0;i<6;i++){
+                dev->dev_addr[i]=SONIC_READ_PROM(i);
+        }                             
+	if (sonic_debug > 1) {
+	        for (i = 0; i < 6; i++)
+		{
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i <	5)
+				printk(":");
+		}
+		printk("\n");
+	}
+	/*
+	 *                If its not one of these we have
+	 *          screwed up on this Mac model
+	 */
+
+	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+	    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+	    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+	{
+		/*
+		 * Try bit reversed
+		 */
+		for(i=0;i<6;i++){
+			val = SONIC_READ_PROM(i);
+			dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) | 
+					  nibbletab[(val >> 4) &0xf];
+		}
+		if (sonic_debug > 1) {
+			printk("Trying bit reversed:  ");
+			for (i = 0; i < 6; i++)
+			{
+				printk("%2.2x", dev->dev_addr[i]);
+				if (i < 5)
+					printk(":");
+			}
+			printk("\n");
+		}
+		if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+		    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+		    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+		{
+		        /*
+			 * Still nonsense ... messed up someplace!
+			 */
+			printk("ERROR (INVALID MAC)\n");
+			return -EIO;
+		}
+	}
+
+	printk(" MAC ");
+	for (i = 0; i < 6; i++)
+	{
+		printk("%2.2x", dev->dev_addr[i]);
+		if (i < 5)
+			printk(":");
+	}
+
+	printk(" IRQ %d\n", MAC_SONIC_IRQ);
+
+	/* Initialize the device structure. */
+	if (dev->priv == NULL)
+	{
+		if (sonic_debug > 2) {
+			printk("Allocating memory for dev->priv aka lp\n");
+			printk("Memory to allocate: %d\n",sizeof(*lp));
+		}
+		/*
+		 * the memory be located in the same 64kb segment
+		 */
+		lp = NULL;
+		i = 0;
+		do
+		{
+			lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL);
+			if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16)
+			{
+				/* FIXME, free the memory later */
+				kfree(lp);
+				lp = NULL;
+			}
+		}
+		while (lp == NULL && i++ < 20);
+
+		if (lp == NULL)
+		{
+			printk("%s: couldn't allocate memory for descriptors\n",
+			       dev->name);
+			return -ENOMEM;
+		}
+
+		if (sonic_debug > 2) {
+			printk("Memory allocated after %d tries\n",i);
+		}
+
+		/* XXX sonic_local has the TDA, RRA, RDA, don't cache */
+		kernel_set_cachemode((u32)lp, 8192, IOMAP_NOCACHE_SER);
+		memset(lp, 0, sizeof(struct sonic_local));
+
+		lp->cda_laddr = (u32)lp;
+		if (sonic_debug > 2) {
+			printk("memory allocated for sonic at 0x%x\n",lp);
+		}
+		lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda);
+		lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda);
+		lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra);
+
+		/* allocate receive buffer area */
+		/* FIXME, maybe we should use skbs */
+		if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL)
+		{
+			printk("%s: couldn't allocate receive buffers\n", dev->name);
+			return -ENOMEM;
+		}
+		/* XXX RBA written by Sonic, not cached either */
+		kernel_set_cachemode((u32)lp->rba, 6*8192, IOMAP_NOCACHE_SER);
+		lp->rba_laddr = (u32)lp->rba;
+		flush_cache_all();
+		dev->priv = (struct sonic_local *) lp;
+	}
+	lp = (struct sonic_local *) dev->priv;
+	dev->open = sonic_open;
+	dev->stop = sonic_close;
+	dev->hard_start_xmit = sonic_send_packet;
+	dev->get_stats = sonic_get_stats;
+	dev->set_multicast_list = &sonic_multicast_list;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+	return 0;
+}
+
+/*
+ *    SONIC uses a nubus IRQ
+ */
+
+#define sonic_request_irq(irq, vec, flags, name, dev) \
+		nubus_request_irq(irq, dev, vec)
+#define sonic_free_irq(irq,id)	nubus_free_irq(irq)
+
+/*
+ *    No funnies on memory mapping.
+ */
+
+#define sonic_chiptomem(x)	(x)
+
+/*
+ *    No VDMA on a Macintosh. So we need request no such facility.
+ */
+
+#define vdma_alloc(x,y)		((u32)(x))
+#define vdma_free(x)
+#define PHYSADDR(x)		(x)
+
+#include "sonic.c"
diff -u --recursive --new-file v2.3.12/linux/drivers/net/mvme147.c linux/drivers/net/mvme147.c
--- v2.3.12/linux/drivers/net/mvme147.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/mvme147.c	Mon Aug  9 12:32:28 1999
@@ -0,0 +1,209 @@
+/* mvme147.c  : the  Linux/mvme147/lance ethernet driver
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ * Uses the generic 7990.c LANCE code.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/mvme147hw.h>
+
+/* We have 16834 bytes of RAM for the init block and buffers. This places
+ * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
+ * buffers and 2 Tx buffers.
+ */
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+
+#include "7990.h"                                 /* use generic LANCE code */
+
+/* Our private data structure */
+struct m147lance_private {
+	struct lance_private lance;
+	void *base;
+	void *ram;
+};
+
+/* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+ * plus board-specific init, open and close actions.
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+int mvme147lance_probe(struct device *dev);
+static int m147lance_open(struct device *dev);
+static int m147lance_close(struct device *dev);
+static void m147lance_writerap(struct m147lance_private *lp, unsigned short value);
+static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value);
+static unsigned short m147lance_readrdp(struct m147lance_private *lp);
+
+typedef void (*writerap_t)(void *, unsigned short);
+typedef void (*writerdp_t)(void *, unsigned short);
+typedef void (*readrdp_t)(void *);
+
+#ifdef MODULE
+static struct m147lance_private *root_m147lance_dev = NULL;
+#endif
+
+/* Initialise the one and only on-board 7990 */
+__initfunc(int mvme147lance_probe(struct device *dev))
+{
+	static int called = 0;
+	static const char name[] = "MVME147 LANCE";
+	struct m147lance_private *lp;
+	u_long *addr;
+	u_long address;
+
+	if (!MACH_IS_MVME147 || called)
+		return(ENODEV);
+	called++;
+
+	dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0, sizeof(struct m147lance_private));
+
+	/* Fill the dev fields */
+	dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
+	dev->open = &m147lance_open;
+	dev->stop = &m147lance_close;
+	dev->hard_start_xmit = &lance_start_xmit;
+	dev->get_stats = &lance_get_stats;
+	dev->set_multicast_list = &lance_set_multicast;
+	dev->dma = 0;
+
+	addr=(u_long *)ETHERNET_ADDRESS;
+	address = *addr;
+	dev->dev_addr[0]=0x08;
+	dev->dev_addr[1]=0x00;
+	dev->dev_addr[2]=0x3e;
+	address=address>>8;
+	dev->dev_addr[5]=address&0xff;
+	address=address>>8;
+	dev->dev_addr[4]=address&0xff;
+	address=address>>8;
+	dev->dev_addr[3]=address&0xff;
+
+	printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+		dev->name, dev->base_addr, MVME147_LANCE_IRQ,
+		dev->dev_addr[0],
+		dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4],
+		dev->dev_addr[5]);
+
+	lp = (struct m147lance_private *)dev->priv;
+	lp->ram = (void *)__get_dma_pages(GFP_ATOMIC, 3);	/* 16K */
+	if (!lp->ram)
+	{
+		printk("%s: No memory for LANCE buffers\n", dev->name);
+		return -ENODEV;
+	}
+
+	lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
+	lp->lance.ll = (struct lance_regs *)(dev->base_addr);
+	lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */
+	lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram);                 /* LANCE addr of same RAM */
+	lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
+	lp->lance.irq = MVME147_LANCE_IRQ;
+	lp->lance.writerap = (writerap_t)m147lance_writerap;
+	lp->lance.writerdp = (writerdp_t)m147lance_writerdp;
+	lp->lance.readrdp = (readrdp_t)m147lance_readrdp;
+	lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
+	lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+	lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+	lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+	ether_setup(dev);
+
+#ifdef MODULE
+	dev->ifindex = dev_new_index();
+	lp->next_module = root_m147lance_dev;
+	root_m147lance_dev = lp;
+#endif /* MODULE */
+
+	return 0;
+}
+
+static void m147lance_writerap(struct m147lance_private *lp, unsigned short value)
+{
+	lp->lance.ll->rap = value;
+}
+
+static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value)
+{
+	lp->lance.ll->rdp = value;
+}
+
+static unsigned short m147lance_readrdp(struct m147lance_private *lp)
+{
+	return lp->lance.ll->rdp;
+}
+
+static int m147lance_open(struct device *dev)
+{
+	int status;
+
+	status = lance_open(dev);                 /* call generic lance open code */
+	if (status)
+		return status;
+	/* enable interrupts at board level. */
+	m147_pcc->lan_cntrl=0;       /* clear the interrupts (if any) */
+	m147_pcc->lan_cntrl=0x08 | 0x04;     /* Enable irq 4 */
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int m147lance_close(struct device *dev)
+{
+	/* disable interrupts at boardlevel */
+	m147_pcc->lan_cntrl=0x0; /* disable interrupts */
+	lance_close(dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	root_lance_dev = NULL;
+	return mvme147lance_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+	/* Walk the chain of devices, unregistering them */
+	struct m147lance_private *lp;
+	while (root_m147lance_dev) {
+		lp = root_m147lance_dev->next_module;
+		unregister_netdev(root_lance_dev->dev);
+		free_pages(lp->ram, 3);
+		kfree(root_lance_dev->dev);
+		root_lance_dev = lp;
+	}
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.3.12/linux/drivers/net/ne.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/ne.c	Thu Aug  5 15:04:52 1999
@@ -218,7 +218,7 @@
 		unsigned int pci_ioaddr;
 
 		while ((pdev = pci_find_device(pci_clone_list[i].vendor, pci_clone_list[i].dev_id, pdev))) {
-			pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+			pci_ioaddr = pdev->resource[0].start;
 			/* Avoid already found cards from previous calls */
 			if (check_region(pci_ioaddr, NE_IO_EXTENT))
 				continue;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.3.12/linux/drivers/net/ne2k-pci.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/ne2k-pci.c	Thu Aug  5 15:04:52 1999
@@ -208,7 +208,7 @@
 		if (pci_clone_list[i].vendor == 0)
 			continue;
 
-		pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+		pci_ioaddr = pdev->resource[0].start;
 		pci_irq_line = pdev->irq;
 		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.3.12/linux/drivers/net/net_init.c	Tue May 25 13:06:34 1999
+++ linux/drivers/net/net_init.c	Thu Aug  5 14:34:02 1999
@@ -111,6 +111,8 @@
 		alloc_size &= ~3;		/* Round to dword boundary. */
 
 		dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+		if(dev==NULL)
+			return NULL;
 		memset(dev, 0, alloc_size);
 		if (sizeof_priv)
 			dev->priv = (void *) (dev + 1);
@@ -233,6 +235,8 @@
 		alloc_size &= ~3;		/* Round to dword boundary. */
 
 		dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+		if(dev==NULL)
+			return NULL;
 		memset(dev, 0, alloc_size);
 		if (sizeof_priv)
 			dev->priv = (void *) (dev + 1);
@@ -563,6 +567,8 @@
 
 		alloc_size &= ~3;		/* Round to dword boundary. */
 		dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+		if(dev==NULL)
+			return NULL;
 		memset(dev, 0, alloc_size);
 		if (sizeof_priv)
 			dev->priv = (void *) (dev + 1);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c
--- v2.3.12/linux/drivers/net/ni5010.c	Wed Oct  7 15:51:45 1998
+++ linux/drivers/net/ni5010.c	Thu Aug  5 14:34:02 1999
@@ -119,7 +119,7 @@
 static void 	show_registers(struct device *dev);
 
 
-__initfunc(int ni5010_probe(struct device *dev))
+int __init ni5010_probe(struct device *dev)
 {
 	int *port;
 
@@ -157,7 +157,7 @@
 	return inb(IE_SAPROM);
 }
 
-__initfunc(void trigger_irq(int ioaddr))
+void __init trigger_irq(int ioaddr)
 {
 		outb(0x00, EDLC_RESET);	/* Clear EDLC hold RESET state */
 		outb(0x00, IE_RESET);	/* Board reset */
@@ -182,7 +182,7 @@
  *      verifies that the correct device exists and functions.
  */
 
-__initfunc(static int ni5010_probe1(struct device *dev, int ioaddr))
+static int __init ni5010_probe1(struct device *dev, int ioaddr)
 {
 	static unsigned version_printed = 0;
 	int i;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ni52.c linux/drivers/net/ni52.c
--- v2.3.12/linux/drivers/net/ni52.c	Tue Jun  8 10:27:18 1999
+++ linux/drivers/net/ni52.c	Thu Aug  5 14:34:02 1999
@@ -358,7 +358,7 @@
 /**********************************************
  * probe the ni5210-card
  */
-__initfunc(int ni52_probe(struct device *dev))
+int __init ni52_probe(struct device *dev)
 {
 #ifndef MODULE
 	int *port;
@@ -409,7 +409,7 @@
 	return ENODEV;
 }
 
-__initfunc(static int ni52_probe1(struct device *dev,int ioaddr))
+static int __init ni52_probe1(struct device *dev,int ioaddr)
 {
 	int i,size;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.3.12/linux/drivers/net/ni65.c	Tue Jun  8 10:27:18 1999
+++ linux/drivers/net/ni65.c	Thu Aug  5 14:34:02 1999
@@ -326,7 +326,7 @@
 #ifdef MODULE
 static
 #endif
-__initfunc(int ni65_probe(struct device *dev))
+int __init ni65_probe(struct device *dev)
 {
 	int *port;
 	static int ports[] = {0x360,0x300,0x320,0x340, 0};
@@ -348,7 +348,7 @@
 /*
  * this is the real card probe ..
  */
-__initfunc(static int ni65_probe1(struct device *dev,int ioaddr))
+static int __init ni65_probe1(struct device *dev,int ioaddr)
 {
 	int i,j;
 	struct priv *p;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.3.12/linux/drivers/net/pcnet32.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/net/pcnet32.c	Thu Aug  5 15:06:47 1999
@@ -461,10 +461,7 @@
 	    if (pcnet32_tbl[chip_idx].vendor_id == 0)
 		continue;
 	    
-	    ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-#if defined(ADDR_64BITS) && defined(__alpha__)
-	    ioaddr |= ((long)pdev->base_address[1]) << 32;
-#endif
+	    ioaddr = pdev->resource[0].start;
 	    irq_line = pdev->irq;
 	    
 	    /* Avoid already found cards from previous pcnet32_probe() calls */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.3.12/linux/drivers/net/plip.c	Sun Mar  7 15:47:46 1999
+++ linux/drivers/net/plip.c	Thu Aug  5 14:34:02 1999
@@ -233,8 +233,8 @@
    then calls us here.
 
    */
-__initfunc(int
-plip_init_dev(struct device *dev, struct parport *pb))
+int __init
+plip_init_dev(struct device *dev, struct parport *pb)
 {
 	struct net_local *nl;
 	struct pardevice *pardev;
@@ -1223,8 +1223,8 @@
 	return 0;
 }
 
-__initfunc(int
-plip_init(void))
+int __init
+plip_init(void)
 {
 	struct parport *pb = parport_enumerate();
 	int i=0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.3.12/linux/drivers/net/ppp_async.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/ppp_async.c	Fri Aug  6 10:44:11 1999
@@ -0,0 +1,957 @@
+/*
+ * PPP async serial channel driver for Linux.
+ *
+ * Copyright 1999 Paul Mackerras.
+ *
+ *  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 driver provides the encapsulation and framing for sending
+ * and receiving PPP frames over async serial lines.  It relies on
+ * the generic PPP layer to give it frames to send and to process
+ * received frames.  It implements the PPP line discipline.
+ *
+ * Part of the code in this driver was inspired by the old async-only
+ * PPP driver, written by Michael Callahan and Al Longyear, and
+ * subsequently hacked by Paul Mackerras.
+ *
+ * ==FILEVERSION 990806==
+ */
+
+/* $Id$ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/tty.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/ppp_channel.h>
+#include <asm/uaccess.h>
+
+#define PPP_VERSION	"2.4.0"
+
+#define OBUFSIZE	256
+
+/* Structure for storing local state. */
+struct asyncppp {
+	struct tty_struct *tty;
+	unsigned int	flags;
+	unsigned int	state;
+	unsigned int	rbits;
+	int		mru;
+	unsigned long	busy;
+	u32		xaccm[8];
+	u32		raccm;
+	unsigned int	bytes_sent;
+	unsigned int	bytes_rcvd;
+
+	struct sk_buff	*tpkt;
+	int		tpkt_pos;
+	u16		tfcs;
+	unsigned char	*optr;
+	unsigned char	*olim;
+	struct sk_buff_head xq;
+	unsigned long	last_xmit;
+
+	struct sk_buff	*rpkt;
+	struct sk_buff_head rq;
+	wait_queue_head_t rwait;
+
+	struct ppp_channel chan;	/* interface to generic ppp layer */
+	int		connected;
+	unsigned char	obuf[OBUFSIZE];
+};
+
+/* Bit numbers in busy */
+#define XMIT_BUSY	0
+#define RECV_BUSY	1
+#define XMIT_WAKEUP	2
+#define XMIT_FULL	3
+
+/* State bits */
+#define SC_TOSS		0x20000000
+#define SC_ESCAPE	0x40000000
+
+/* Bits in rbits */
+#define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+
+#define PPPASYNC_MAX_RQLEN	32	/* arbitrary */
+
+static int flag_time = HZ;
+MODULE_PARM(flag_time, "i");
+
+/*
+ * Prototypes.
+ */
+static int ppp_async_encode(struct asyncppp *ap);
+static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb);
+static int ppp_async_push(struct asyncppp *ap);
+static void ppp_async_flush_output(struct asyncppp *ap);
+static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
+			    char *flags, int count);
+
+struct ppp_channel_ops async_ops = {
+	ppp_async_send
+};
+
+/*
+ * Routines for locking and unlocking the transmit and receive paths.
+ */
+static inline void
+lock_path(struct asyncppp *ap, int bit)
+{
+	do {
+		while (test_bit(bit, &ap->busy))
+		       mb();
+	} while (test_and_set_bit(bit, &ap->busy));
+	mb();
+}
+
+static inline int
+trylock_path(struct asyncppp *ap, int bit)
+{
+	if (test_and_set_bit(bit, &ap->busy))
+		return 0;
+	mb();
+	return 1;
+}
+
+static inline void
+unlock_path(struct asyncppp *ap, int bit)
+{
+	mb();
+	clear_bit(bit, &ap->busy);
+}
+
+#define lock_xmit_path(ap)	lock_path(ap, XMIT_BUSY)
+#define trylock_xmit_path(ap)	trylock_path(ap, XMIT_BUSY)
+#define unlock_xmit_path(ap)	unlock_path(ap, XMIT_BUSY)
+#define lock_recv_path(ap)	lock_path(ap, RECV_BUSY)
+#define trylock_recv_path(ap)	trylock_path(ap, RECV_BUSY)
+#define unlock_recv_path(ap)	unlock_path(ap, RECV_BUSY)
+
+static inline void
+flush_skb_queue(struct sk_buff_head *q)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(q)) != 0)
+		kfree_skb(skb);
+}
+
+/*
+ * Routines implementing the PPP line discipline.
+ */
+
+/*
+ * Called when a tty is put into PPP line discipline.
+ */
+static int
+ppp_async_open(struct tty_struct *tty)
+{
+	struct asyncppp *ap;
+
+	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+	if (ap == 0)
+		return -ENOMEM;
+
+	MOD_INC_USE_COUNT;
+
+	/* initialize the asyncppp structure */
+	memset(ap, 0, sizeof(*ap));
+	ap->tty = tty;
+	ap->mru = PPP_MRU;
+	ap->xaccm[0] = ~0U;
+	ap->xaccm[3] = 0x60000000U;
+	ap->raccm = ~0U;
+	ap->optr = ap->obuf;
+	ap->olim = ap->obuf;
+	skb_queue_head_init(&ap->xq);
+	skb_queue_head_init(&ap->rq);
+	init_waitqueue_head(&ap->rwait);
+
+	tty->disc_data = ap;
+
+	return 0;
+}
+
+/*
+ * Called when the tty is put into another line discipline
+ * (or it hangs up).
+ */
+static void
+ppp_async_close(struct tty_struct *tty)
+{
+	struct asyncppp *ap = tty->disc_data;
+
+	if (ap == 0)
+		return;
+	tty->disc_data = 0;
+	lock_xmit_path(ap);
+	lock_recv_path(ap);
+	if (ap->rpkt != 0)
+		kfree_skb(ap->rpkt);
+	flush_skb_queue(&ap->rq);
+	if (ap->tpkt != 0)
+		kfree_skb(ap->tpkt);
+	flush_skb_queue(&ap->xq);
+	if (ap->connected)
+		ppp_unregister_channel(&ap->chan);
+	kfree(ap);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Read a PPP frame.  pppd can use this to negotiate over the
+ * channel before it joins it to a bundle.
+ */
+static ssize_t
+ppp_async_read(struct tty_struct *tty, struct file *file,
+	       unsigned char *buf, size_t count)
+{
+	struct asyncppp *ap = tty->disc_data;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret;
+	struct sk_buff *skb = 0;
+
+	ret = -ENXIO;
+	if (ap == 0)
+		goto out;		/* should never happen */
+
+	add_wait_queue(&ap->rwait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	for (;;) {
+		ret = -EAGAIN;
+		skb = skb_dequeue(&ap->rq);
+		if (skb)
+			break;
+		if (file->f_flags & O_NONBLOCK)
+			break;
+		ret = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&ap->rwait, &wait);
+
+	if (skb == 0)
+		goto out;
+
+	ret = -EOVERFLOW;
+	if (skb->len > count)
+		goto outf;
+	ret = -EFAULT;
+	if (copy_to_user(buf, skb->data, skb->len))
+		goto outf;
+	ret = skb->len;
+
+ outf:
+	kfree_skb(skb);
+ out:
+	return ret;
+}
+
+/*
+ * Write a ppp frame.  pppd can use this to send frames over
+ * this particular channel.
+ */
+static ssize_t
+ppp_async_write(struct tty_struct *tty, struct file *file,
+		const unsigned char *buf, size_t count)
+{
+	struct asyncppp *ap = tty->disc_data;
+	struct sk_buff *skb;
+	ssize_t ret;
+
+	ret = -ENXIO;
+	if (ap == 0)
+		goto out;	/* should never happen */
+
+	ret = -ENOMEM;
+	skb = alloc_skb(count + 2, GFP_KERNEL);
+	if (skb == 0)
+		goto out;
+	skb_reserve(skb, 2);
+	ret = -EFAULT;
+	if (copy_from_user(skb_put(skb, count), buf, count)) {
+		kfree_skb(skb);
+		goto out;
+	}
+
+	skb_queue_tail(&ap->xq, skb);
+	ppp_async_push(ap);
+
+	ret = count;
+
+ out:
+	return ret;
+}
+
+static int
+ppp_async_ioctl(struct tty_struct *tty, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct asyncppp *ap = tty->disc_data;
+	int err, val;
+	u32 accm[8];
+	struct sk_buff *skb;
+
+	err = -ENXIO;
+	if (ap == 0)
+		goto out;	/* should never happen */
+	err = -EPERM;
+	if (!capable(CAP_NET_ADMIN))
+		goto out;
+
+	err = -EFAULT;
+	switch (cmd) {
+	case PPPIOCGFLAGS:
+		val = ap->flags | ap->rbits;
+		if (put_user(ap->flags, (int *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSFLAGS:
+		if (get_user(val, (int *) arg))
+			break;
+		ap->flags = val & ~SC_RCV_BITS;
+		ap->rbits = val & SC_RCV_BITS;
+		err = 0;
+		break;
+
+	case PPPIOCGASYNCMAP:
+		if (put_user(ap->xaccm[0], (u32 *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSASYNCMAP:
+		if (get_user(ap->xaccm[0], (u32 *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCGRASYNCMAP:
+		if (put_user(ap->raccm, (u32 *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSRASYNCMAP:
+		if (get_user(ap->raccm, (u32 *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCGXASYNCMAP:
+		if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm)))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSXASYNCMAP:
+		if (copy_from_user(accm, (void *) arg, sizeof(accm)))
+			break;
+		accm[2] &= ~0x40000000U;	/* can't escape 0x5e */
+		accm[3] |= 0x60000000U;		/* must escape 0x7d, 0x7e */
+		memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
+		err = 0;
+		break;
+
+	case PPPIOCGMRU:
+		if (put_user(ap->mru, (int *) arg))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSMRU:
+		if (get_user(val, (int *) arg))
+			break;
+		if (val < PPP_MRU)
+			val = PPP_MRU;
+		ap->mru = val;
+		err = 0;
+		break;
+
+	case PPPIOCATTACH:
+		if (get_user(val, (int *) arg))
+			break;
+		err = -EALREADY;
+		if (ap->connected)
+			break;
+		ap->chan.private = ap;
+		ap->chan.ops = &async_ops;
+		err = ppp_register_channel(&ap->chan, val);
+		if (err != 0)
+			break;
+		ap->connected = 1;
+		break;
+	case PPPIOCDETACH:
+		err = -ENXIO;
+		if (!ap->connected)
+			break;
+		ppp_unregister_channel(&ap->chan);
+		ap->connected = 0;
+		err = 0;
+		break;
+
+	case TCGETS:
+	case TCGETA:
+		err = n_tty_ioctl(tty, file, cmd, arg);
+		break;
+
+	case TCFLSH:
+		/* flush our buffers and the serial port's buffer */
+		if (arg == TCIFLUSH || arg == TCIOFLUSH)
+			flush_skb_queue(&ap->rq);
+		if (arg == TCIOFLUSH || arg == TCOFLUSH)
+			ppp_async_flush_output(ap);
+		err = n_tty_ioctl(tty, file, cmd, arg);
+		break;
+
+	case FIONREAD:
+		val = 0;
+		if ((skb = skb_peek(&ap->rq)) != 0)
+			val = skb->len;
+		if (put_user(val, (int *) arg))
+			break;
+		err = 0;
+		break;
+
+	default:
+		err = -ENOIOCTLCMD;
+	}
+ out:
+	return err;
+}
+
+static unsigned int
+ppp_async_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
+{
+	struct asyncppp *ap = tty->disc_data;
+	unsigned int mask;
+
+	if (ap == 0)
+		return 0;	/* should never happen */
+	poll_wait(file, &ap->rwait, wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (skb_peek(&ap->rq))
+		mask |= POLLIN | POLLRDNORM;
+	if (test_bit(TTY_OTHER_CLOSED, &tty->flags) || tty_hung_up_p(file))
+		mask |= POLLHUP;
+	return mask;
+}
+
+static int
+ppp_async_room(struct tty_struct *tty)
+{
+	return 65535;
+}
+
+static void
+ppp_async_receive(struct tty_struct *tty, const unsigned char *buf,
+		  char *flags, int count)
+{
+	struct asyncppp *ap = tty->disc_data;
+
+	if (ap == 0)
+		return;
+	trylock_recv_path(ap);
+	ppp_async_input(ap, buf, flags, count);
+	unlock_recv_path(ap);
+	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
+	    && tty->driver.unthrottle)
+		tty->driver.unthrottle(tty);
+}
+
+static void
+ppp_async_wakeup(struct tty_struct *tty)
+{
+	struct asyncppp *ap = tty->disc_data;
+
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+	if (ap == 0)
+		return;
+	if (ppp_async_push(ap) && ap->connected)
+		ppp_output_wakeup(&ap->chan);
+}
+
+
+static struct tty_ldisc ppp_ldisc = {
+	magic:	TTY_LDISC_MAGIC,
+	name:	"ppp",
+	open:	ppp_async_open,
+	close:	ppp_async_close,
+	read:	ppp_async_read,
+	write:	ppp_async_write,
+	ioctl:	ppp_async_ioctl,
+	poll:	ppp_async_poll,
+	receive_room: ppp_async_room,
+	receive_buf: ppp_async_receive,
+	write_wakeup: ppp_async_wakeup,
+};
+
+int
+ppp_async_init(void)
+{
+	int err;
+
+	err = tty_register_ldisc(N_PPP, &ppp_ldisc);
+	if (err != 0)
+		printk(KERN_ERR "PPP_async: error %d registering line disc.\n",
+		       err);
+	return err;
+}
+
+/*
+ * Procedures for encapsulation and framing.
+ */
+
+u16 ppp_crc16_table[256] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+EXPORT_SYMBOL(ppp_crc16_table);
+#define fcstab	ppp_crc16_table		/* for PPP_FCS macro */
+
+/*
+ * Procedure to encode the data for async serial transmission.
+ * Does octet stuffing (escaping), puts the address/control bytes
+ * on if A/C compression is disabled, and does protocol compression.
+ * Assumes ap->tpkt != 0 on entry.
+ * Returns 1 if we finished the current frame, 0 otherwise.
+ */
+
+#define PUT_BYTE(ap, buf, c, islcp)	do {		\
+	if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\
+		*buf++ = PPP_ESCAPE;			\
+		*buf++ = c ^ 0x20;			\
+	} else						\
+		*buf++ = c;				\
+} while (0)
+
+static int
+ppp_async_encode(struct asyncppp *ap)
+{
+	int fcs, i, count, c, proto;
+	unsigned char *buf, *buflim;
+	unsigned char *data;
+	int islcp;
+
+	buf = ap->obuf;
+	ap->olim = buf;
+	ap->optr = buf;
+	i = ap->tpkt_pos;
+	data = ap->tpkt->data;
+	count = ap->tpkt->len;
+	fcs = ap->tfcs;
+	proto = (data[0] << 8) + data[1];
+
+	/*
+	 * LCP packets with code values between 1 (configure-reqest)
+	 * and 7 (code-reject) must be sent as though no options
+	 * had been negotiated.
+	 */
+	islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+	if (i == 0) {
+		/*
+		 * Start of a new packet - insert the leading FLAG
+		 * character if necessary.
+		 */
+		if (islcp || flag_time == 0
+		    || jiffies - ap->last_xmit >= flag_time)
+			*buf++ = PPP_FLAG;
+		ap->last_xmit = jiffies;
+		fcs = PPP_INITFCS;
+
+		/*
+		 * Put in the address/control bytes if necessary
+		 */
+		if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
+			PUT_BYTE(ap, buf, 0xff, islcp);
+			fcs = PPP_FCS(fcs, 0xff);
+			PUT_BYTE(ap, buf, 0x03, islcp);
+			fcs = PPP_FCS(fcs, 0x03);
+		}
+	}
+
+	/*
+	 * Once we put in the last byte, we need to put in the FCS
+	 * and closing flag, so make sure there is at least 7 bytes
+	 * of free space in the output buffer.
+	 */
+	buflim = ap->obuf + OBUFSIZE - 6;
+	while (i < count && buf < buflim) {
+		c = data[i++];
+		if (i == 1 && c == 0 && (ap->flags & SC_COMP_PROT))
+			continue;	/* compress protocol field */
+		fcs = PPP_FCS(fcs, c);
+		PUT_BYTE(ap, buf, c, islcp);
+	}
+
+	if (i < count) {
+		/*
+		 * Remember where we are up to in this packet.
+		 */
+		ap->olim = buf;
+		ap->tpkt_pos = i;
+		ap->tfcs = fcs;
+		return 0;
+	}
+
+	/*
+	 * We have finished the packet.  Add the FCS and flag.
+	 */
+	fcs = ~fcs;
+	c = fcs & 0xff;
+	PUT_BYTE(ap, buf, c, islcp);
+	c = (fcs >> 8) & 0xff;
+	PUT_BYTE(ap, buf, c, islcp);
+	*buf++ = PPP_FLAG;
+	ap->olim = buf;
+
+	kfree_skb(ap->tpkt);
+	ap->tpkt = 0;
+	return 1;
+}
+
+/*
+ * Transmit-side routines.
+ */
+
+/*
+ * Send a packet to the peer over an async tty line.
+ * Returns 1 iff the packet was accepted.
+ * If the packet was not accepted, we will call ppp_output_wakeup
+ * at some later time.
+ */
+static int
+ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb)
+{
+	struct asyncppp *ap = chan->private;
+
+	ppp_async_push(ap);
+
+	if (test_and_set_bit(XMIT_FULL, &ap->busy))
+		return 0;	/* already full */
+	ap->tpkt = skb;
+	ap->tpkt_pos = 0;
+
+	ppp_async_push(ap);
+	return 1;
+}
+
+/*
+ * Push as much data as possible out to the tty.
+ */
+static int
+ppp_async_push(struct asyncppp *ap)
+{
+	int avail, sent, done = 0;
+	struct tty_struct *tty = ap->tty;
+	int tty_stuffed = 0;
+
+	if (!trylock_xmit_path(ap)) {
+		set_bit(XMIT_WAKEUP, &ap->busy);
+		return 0;
+	}
+	for (;;) {
+		if (test_and_clear_bit(XMIT_WAKEUP, &ap->busy))
+			tty_stuffed = 0;
+		if (!tty_stuffed && ap->optr < ap->olim) {
+			avail = ap->olim - ap->optr;
+			set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+			sent = tty->driver.write(tty, 0, ap->optr, avail);
+			if (sent < 0)
+				goto flush;	/* error, e.g. loss of CD */
+			ap->optr += sent;
+			if (sent < avail)
+				tty_stuffed = 1;
+			continue;
+		}
+		if (ap->optr == ap->olim && ap->tpkt != 0) {
+			if (ppp_async_encode(ap)) {
+				/* finished processing ap->tpkt */
+				struct sk_buff *skb = skb_dequeue(&ap->xq);
+				if (skb != 0) {
+					ap->tpkt = skb;
+				} else {
+					clear_bit(XMIT_FULL, &ap->busy);
+					done = 1;
+				}
+			}
+			continue;
+		}
+		/* haven't made any progress */
+		unlock_xmit_path(ap);
+		if (!(test_bit(XMIT_WAKEUP, &ap->busy)
+		      || (!tty_stuffed && ap->tpkt != 0)))
+			break;
+		if (!trylock_xmit_path(ap))
+			break;
+	}
+	return done;
+
+flush:
+	if (ap->tpkt != 0) {
+		kfree_skb(ap->tpkt);
+		ap->tpkt = 0;
+		clear_bit(XMIT_FULL, &ap->busy);
+		done = 1;
+	}
+	ap->optr = ap->olim;
+	unlock_xmit_path(ap);
+	return done;
+}
+
+/*
+ * Flush output from our internal buffers.
+ * Called for the TCFLSH ioctl.
+ */
+static void
+ppp_async_flush_output(struct asyncppp *ap)
+{
+	int done = 0;
+
+	flush_skb_queue(&ap->xq);
+	lock_xmit_path(ap);
+	ap->optr = ap->olim;
+	if (ap->tpkt != NULL) {
+		kfree_skb(ap->tpkt);
+		ap->tpkt = 0;
+		clear_bit(XMIT_FULL, &ap->busy);
+		done = 1;
+	}
+	unlock_xmit_path(ap);
+	if (done && ap->connected)
+		ppp_output_wakeup(&ap->chan);
+}
+
+/*
+ * Receive-side routines.
+ */
+
+/* see how many ordinary chars there are at the start of buf */
+static inline int
+scan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count)
+{
+	int i, c;
+
+	for (i = 0; i < count; ++i) {
+		c = buf[i];
+		if (c == PPP_ESCAPE || c == PPP_FLAG
+		    || (c < 0x20 && (ap->raccm & (1 << c)) != 0))
+			break;
+	}
+	return i;
+}
+
+/* called when a flag is seen - do end-of-packet processing */
+static inline void
+process_input_packet(struct asyncppp *ap)
+{
+	struct sk_buff *skb;
+	unsigned char *p;
+	unsigned int len, fcs;
+	int code = 0;
+
+	skb = ap->rpkt;
+	ap->rpkt = 0;
+	if ((ap->state & (SC_TOSS | SC_ESCAPE)) || skb == 0) {
+		ap->state &= ~(SC_TOSS | SC_ESCAPE);
+		if (skb != 0)
+			kfree_skb(skb);
+		return;
+	}
+
+	/* check the FCS */
+	p = skb->data;
+	len = skb->len;
+	if (len < 3)
+		goto err;	/* too short */
+	fcs = PPP_INITFCS;
+	for (; len > 0; --len)
+		fcs = PPP_FCS(fcs, *p++);
+	if (fcs != PPP_GOODFCS)
+		goto err;	/* bad FCS */
+	skb_trim(skb, skb->len - 2);
+
+	/* check for address/control and protocol compression */
+	p = skb->data;
+	if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+		/* chop off address/control */
+		if (skb->len < 3)
+			goto err;
+		p = skb_pull(skb, 2);
+	}
+	if (p[0] & 1) {
+		/* protocol is compressed */
+		skb_push(skb, 1)[0] = 0;
+	} else if (skb->len < 2)
+		goto err;
+
+	/* all OK, give it to the generic layer or queue it */
+	if (ap->connected) {
+		ppp_input(&ap->chan, skb);
+	} else {
+		skb_queue_tail(&ap->rq, skb);
+		/* drop old frames if queue too long */
+		while (ap->rq.qlen > PPPASYNC_MAX_RQLEN
+		       && (skb = skb_dequeue(&ap->rq)) != 0)
+			kfree(skb);
+		wake_up_interruptible(&ap->rwait);
+	}
+	return;
+
+ err:
+	kfree_skb(skb);
+	if (ap->connected)
+		ppp_input_error(&ap->chan, code);
+}
+
+static inline void
+input_error(struct asyncppp *ap, int code)
+{
+	ap->state |= SC_TOSS;
+	if (ap->connected)
+		ppp_input_error(&ap->chan, code);
+}
+
+/* called when the tty driver has data for us. */
+static void
+ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
+		char *flags, int count)
+{
+	struct sk_buff *skb;
+	int c, i, j, n, s, f;
+	unsigned char *sp;
+
+	/* update bits used for 8-bit cleanness detection */
+	if (~ap->rbits & SC_RCV_BITS) {
+		s = 0;
+		for (i = 0; i < count; ++i) {
+			c = buf[i];
+			if (flags != 0 && flags[i] != 0)
+				continue;
+			s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0;
+			c = ((c >> 4) ^ c) & 0xf;
+			s |= (0x6996 & (1 << c))? SC_RCV_ODDP: SC_RCV_EVNP;
+		}
+		ap->rbits |= s;
+	}
+
+	while (count > 0) {
+		/* scan through and see how many chars we can do in bulk */
+		if ((ap->state & SC_ESCAPE) && buf[0] == PPP_ESCAPE)
+			n = 1;
+		else
+			n = scan_ordinary(ap, buf, count);
+
+		f = 0;
+		if (flags != 0 && (ap->state & SC_TOSS) == 0) {
+			/* check the flags to see if any char had an error */
+			for (j = 0; j < n; ++j)
+				if ((f = flags[j]) != 0)
+					break;
+		}
+		if (f != 0) {
+			/* start tossing */
+			input_error(ap, f);
+
+		} else if (n > 0 && (ap->state & SC_TOSS) == 0) {
+			/* stuff the chars in the skb */
+			skb = ap->rpkt;
+			if (skb == 0) {
+				skb = alloc_skb(ap->mru + PPP_HDRLEN + 2,
+						GFP_ATOMIC);
+				if (skb == 0)
+					goto nomem;
+				/* Try to get the payload 4-byte aligned */
+				if (buf[0] != PPP_ALLSTATIONS)
+					skb_reserve(skb, 2 + (buf[0] & 1));
+				ap->rpkt = skb;
+			}
+			if (n > skb_tailroom(skb)) {
+				/* packet overflowed MRU */
+				input_error(ap, 1);
+			} else {
+				sp = skb_put(skb, n);
+				memcpy(sp, buf, n);
+				if (ap->state & SC_ESCAPE) {
+					sp[0] ^= 0x20;
+					ap->state &= ~SC_ESCAPE;
+				}
+			}
+		}
+
+		if (n >= count)
+			break;
+
+		c = buf[n];
+		if (c == PPP_FLAG) {
+			process_input_packet(ap);
+		} else if (c == PPP_ESCAPE) {
+			ap->state |= SC_ESCAPE;
+		}
+		/* otherwise it's a char in the recv ACCM */
+		++n;
+
+		buf += n;
+		if (flags != 0)
+			flags += n;
+		count -= n;
+	}
+	return;
+
+ nomem:
+	printk(KERN_ERR "PPPasync: no memory (input pkt)\n");
+	input_error(ap, 0);
+}
+
+#ifdef MODULE
+int
+init_module(void)
+{
+	return ppp_async_init();
+}
+
+void
+cleanup_module(void)
+{
+	if (tty_register_ldisc(N_PPP, NULL) != 0)
+		printk(KERN_ERR "failed to unregister PPP line discipline\n");
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.3.12/linux/drivers/net/ppp_generic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/ppp_generic.c	Fri Aug  6 10:44:11 1999
@@ -0,0 +1,1576 @@
+/*
+ * Generic PPP layer for Linux.
+ *
+ * Copyright 1999 Paul Mackerras.
+ *
+ *  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.
+ *
+ * The generic PPP layer handles the PPP network interfaces, the
+ * /dev/ppp device, packet and VJ compression, and multilink.
+ * It talks to PPP `channels' via the interface defined in
+ * include/linux/ppp_channel.h.  Channels provide the basic means for
+ * sending and receiving PPP frames on some kind of communications
+ * channel.
+ *
+ * Part of the code in this driver was inspired by the old async-only
+ * PPP driver, written by Michael Callahan and Al Longyear, and
+ * subsequently hacked by Paul Mackerras.
+ *
+ * ==FILEVERSION 990806==
+ */
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp-comp.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/slhc_vj.h>
+#include <asm/spinlock.h>
+
+#define PPP_VERSION	"2.4.0"
+
+EXPORT_SYMBOL(ppp_register_channel);
+EXPORT_SYMBOL(ppp_unregister_channel);
+EXPORT_SYMBOL(ppp_input);
+EXPORT_SYMBOL(ppp_input_error);
+EXPORT_SYMBOL(ppp_output_wakeup);
+EXPORT_SYMBOL(ppp_register_compressor);
+EXPORT_SYMBOL(ppp_unregister_compressor);
+
+/*
+ * Network protocols we support.
+ */
+#define NP_IP	0		/* Internet Protocol V4 */
+#define NP_IPV6	1		/* Internet Protocol V6 */
+#define NP_IPX	2		/* IPX protocol */
+#define NP_AT	3		/* Appletalk protocol */
+#define NUM_NP	4		/* Number of NPs. */
+
+/*
+ * Data structure describing one ppp unit.
+ * A ppp unit corresponds to a ppp network interface device
+ * and represents a multilink bundle.
+ * It may have 0 or more ppp channels connected to it.
+ */
+struct ppp {
+	struct list_head list;		/* link in list of ppp units */
+	int		index;		/* interface unit number */
+	char		name[16];	/* unit name */
+	int		refcnt;		/* # open /dev/ppp attached */
+	unsigned long	busy;		/* lock and other bits */
+	struct list_head channels;	/* list of attached channels */
+	int		n_channels;	/* how many channels are attached */
+	int		mru;		/* max receive unit */
+	unsigned int	flags;		/* control bits */
+	unsigned int	xstate;		/* transmit state bits */
+	unsigned int	rstate;		/* receive state bits */
+	int		debug;		/* debug flags */
+	struct slcompress *vj;		/* state for VJ header compression */
+	struct sk_buff_head xq;		/* pppd transmit queue */
+	struct sk_buff_head rq;		/* receive queue for pppd */
+	wait_queue_head_t rwait;	/* for poll on reading /dev/ppp */
+	enum NPmode	npmode[NUM_NP];	/* what to do with each net proto */
+	struct sk_buff	*xmit_pending;	/* a packet ready to go out */
+	struct sk_buff_head recv_pending;/* pending input packets */
+	struct compressor *xcomp;	/* transmit packet compressor */
+	void		*xc_state;	/* its internal state */
+	struct compressor *rcomp;	/* receive decompressor */
+	void		*rc_state;	/* its internal state */
+	unsigned long	last_xmit;	/* jiffies when last pkt sent */
+	unsigned long	last_recv;	/* jiffies when last pkt rcvd */
+	struct device	dev;		/* network interface device */
+	struct net_device_stats stats;	/* statistics */
+};
+
+static LIST_HEAD(all_ppp_units);
+static spinlock_t all_ppp_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Private data structure for each channel.
+ * Ultimately this will have multilink stuff etc. in it.
+ */
+struct channel {
+	struct list_head list;		/* link in list of channels per unit */
+	struct ppp_channel *chan;	/* public channel data structure */
+	int		blocked;	/* if channel refused last packet */
+	struct ppp	*ppp;		/* ppp unit we're connected to */
+};
+
+/* Bit numbers in busy */
+#define XMIT_BUSY	0
+#define RECV_BUSY	1
+#define XMIT_WAKEUP	2
+
+/*
+ * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC.
+ * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
+ * Bits in xstate: SC_COMP_RUN
+ */
+#define SC_FLAG_BITS	(SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC)
+
+/* Get the PPP protocol number from a skb */
+#define PPP_PROTO(skb)	(((skb)->data[0] << 8) + (skb)->data[1])
+
+/* We limit the length of ppp->rq to this (arbitrary) value */
+#define PPP_MAX_RQLEN	32
+
+/* Prototypes. */
+static void ppp_xmit_unlock(struct ppp *ppp);
+static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
+static void ppp_push(struct ppp *ppp);
+static void ppp_recv_unlock(struct ppp *ppp);
+static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb);
+static struct sk_buff *ppp_decompress_frame(struct ppp *ppp,
+					    struct sk_buff *skb);
+static int ppp_set_compress(struct ppp *ppp, unsigned long arg);
+static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound);
+static void ppp_ccp_closed(struct ppp *ppp);
+static struct compressor *find_compressor(int type);
+static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
+static struct ppp *ppp_create_unit(int unit, int *retp);
+static struct ppp *ppp_find_unit(int unit);
+
+/* Translates a PPP protocol number to a NP index (NP == network protocol) */
+static inline int proto_to_npindex(int proto)
+{
+	switch (proto) {
+	case PPP_IP:
+		return NP_IP;
+	case PPP_IPV6:
+		return NP_IPV6;
+	case PPP_IPX:
+		return NP_IPX;
+	case PPP_AT:
+		return NP_AT;
+	}
+	return -EINVAL;
+}
+
+/* Translates an NP index into a PPP protocol number */
+static const int npindex_to_proto[NUM_NP] = {
+	PPP_IP,
+	PPP_IPV6,
+	PPP_IPX,
+	PPP_AT,
+};
+	
+/* Translates an ethertype into an NP index */
+static inline int ethertype_to_npindex(int ethertype)
+{
+	switch (ethertype) {
+	case ETH_P_IP:
+		return NP_IP;
+	case ETH_P_IPV6:
+		return NP_IPV6;
+	case ETH_P_IPX:
+		return NP_IPX;
+	case ETH_P_PPPTALK:
+	case ETH_P_ATALK:
+		return NP_AT;
+	}
+	return -1;
+}
+
+/* Translates an NP index into an ethertype */
+static const int npindex_to_ethertype[NUM_NP] = {
+	ETH_P_IP,
+	ETH_P_IPV6,
+	ETH_P_IPX,
+	ETH_P_PPPTALK,
+};
+
+/*
+ * Routines for locking and unlocking the transmit and receive paths
+ * of each unit.
+ */
+static inline void
+lock_path(struct ppp *ppp, int bit)
+{
+	int timeout = 1000000;
+
+	do {
+		while (test_bit(bit, &ppp->busy)) {
+		       mb();
+		       if (--timeout == 0) {
+			       printk(KERN_ERR "lock_path timeout ppp=%p bit=%x\n", ppp, bit);
+			       return;
+		       }
+		}
+	} while (test_and_set_bit(bit, &ppp->busy));
+	mb();
+}
+
+static inline int
+trylock_path(struct ppp *ppp, int bit)
+{
+	if (test_and_set_bit(bit, &ppp->busy))
+		return 0;
+	mb();
+	return 1;
+}
+
+static inline void
+unlock_path(struct ppp *ppp, int bit)
+{
+	mb();
+	clear_bit(bit, &ppp->busy);
+}
+
+#define lock_xmit_path(ppp)	lock_path(ppp, XMIT_BUSY)
+#define trylock_xmit_path(ppp)	trylock_path(ppp, XMIT_BUSY)
+#define unlock_xmit_path(ppp)	unlock_path(ppp, XMIT_BUSY)
+#define lock_recv_path(ppp)	lock_path(ppp, RECV_BUSY)
+#define trylock_recv_path(ppp)	trylock_path(ppp, RECV_BUSY)
+#define unlock_recv_path(ppp)	unlock_path(ppp, RECV_BUSY)
+
+static inline void
+free_skbs(struct sk_buff_head *head)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(head)) != 0)
+		kfree_skb(skb);
+}
+
+/*
+ * /dev/ppp device routines.
+ * The /dev/ppp device is used by pppd to control the ppp unit.
+ * It supports the read, write, ioctl and poll functions.
+ */
+static int ppp_open(struct inode *inode, struct file *file)
+{
+	/*
+	 * This could (should?) be enforced by the permissions on /dev/ppp.
+	 */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ppp_release(struct inode *inode, struct file *file)
+{
+	struct ppp *ppp = (struct ppp *) file->private_data;
+	struct list_head *list, *next;
+	int ref;
+
+	if (ppp == 0)
+		goto out;
+	file->private_data = 0;
+	spin_lock(&all_ppp_lock);
+	ref = --ppp->refcnt;
+	if (ref == 0)
+		list_del(&ppp->list);
+	spin_unlock(&all_ppp_lock);
+	if (ref != 0)
+		goto out;
+
+	/* Last fd open to this ppp unit is being closed -
+	   mark the interface down, free the ppp unit */
+	rtnl_lock();
+	dev_close(&ppp->dev);
+	rtnl_unlock();
+	for (list = ppp->channels.next; list != &ppp->channels; list = next) {
+		/* forcibly detach this channel */
+		struct channel *chan;
+		chan = list_entry(list, struct channel, list);
+		chan->chan->ppp = 0;
+		next = list->next;
+		kfree(chan);
+	}
+
+	/* Free up resources. */
+	ppp_ccp_closed(ppp);
+	lock_xmit_path(ppp);
+	lock_recv_path(ppp);
+	if (ppp->vj) {
+		slhc_free(ppp->vj);
+		ppp->vj = 0;
+	}
+	free_skbs(&ppp->xq);
+	free_skbs(&ppp->rq);
+	free_skbs(&ppp->recv_pending);
+	unregister_netdev(&ppp->dev);
+	kfree(ppp);
+
+ out:
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static ssize_t ppp_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	struct ppp *ppp = (struct ppp *) file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret;
+	struct sk_buff *skb = 0;
+
+	ret = -ENXIO;
+	if (ppp == 0)
+		goto out;		/* not currently attached */
+
+	add_wait_queue(&ppp->rwait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	for (;;) {
+		ret = -EAGAIN;
+		skb = skb_dequeue(&ppp->rq);
+		if (skb)
+			break;
+		if (file->f_flags & O_NONBLOCK)
+			break;
+		ret = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&ppp->rwait, &wait);
+
+	if (skb == 0)
+		goto out;
+
+	ret = -EOVERFLOW;
+	if (skb->len > count)
+		goto outf;
+	ret = -EFAULT;
+	if (copy_to_user(buf, skb->data, skb->len))
+		goto outf;
+	ret = skb->len;
+
+ outf:
+	kfree_skb(skb);
+ out:
+	return ret;
+}
+
+static ssize_t ppp_write(struct file *file, const char *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct ppp *ppp = (struct ppp *) file->private_data;
+	struct sk_buff *skb;
+	ssize_t ret;
+
+	ret = -ENXIO;
+	if (ppp == 0)
+		goto out;
+
+	ret = -ENOMEM;
+	skb = alloc_skb(count + 2, GFP_KERNEL);
+	if (skb == 0)
+		goto out;
+	skb_reserve(skb, 2);
+	ret = -EFAULT;
+	if (copy_from_user(skb_put(skb, count), buf, count)) {
+		kfree_skb(skb);
+		goto out;
+	}
+
+	skb_queue_tail(&ppp->xq, skb);
+	if (trylock_xmit_path(ppp))
+		ppp_xmit_unlock(ppp);
+
+	ret = count;
+
+ out:
+	return ret;
+}
+
+static unsigned int ppp_poll(struct file *file, poll_table *wait)
+{
+	struct ppp *ppp = (struct ppp *) file->private_data;
+	unsigned int mask;
+
+	if (ppp == 0)
+		return 0;
+	poll_wait(file, &ppp->rwait, wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (skb_peek(&ppp->rq) != 0)
+		mask |= POLLIN | POLLRDNORM;
+	return mask;
+}
+
+static int ppp_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct ppp *ppp = (struct ppp *) file->private_data;
+	int err, val, val2, i;
+	struct ppp_idle idle;
+	struct npioctl npi;
+
+	if (cmd == PPPIOCNEWUNIT) {
+		/* Create a new ppp unit */
+		int unit, ret;
+
+		if (ppp != 0)
+			return -EINVAL;
+		if (get_user(unit, (int *) arg))
+			return -EFAULT;
+		ppp = ppp_create_unit(unit, &ret);
+		if (ppp == 0)
+			return ret;
+		file->private_data = ppp;
+		if (put_user(ppp->index, (int *) arg))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == PPPIOCATTACH) {
+		/* Attach to an existing ppp unit */
+		int unit;
+
+		if (ppp != 0)
+			return -EINVAL;
+		if (get_user(unit, (int *) arg))
+			return -EFAULT;
+		spin_lock(&all_ppp_lock);
+		ppp = ppp_find_unit(unit);
+		if (ppp != 0)
+			++ppp->refcnt;
+		spin_unlock(&all_ppp_lock);
+		if (ppp == 0)
+			return -ENXIO;
+		file->private_data = ppp;
+		return 0;
+	}
+
+	if (ppp == 0)
+		return -ENXIO;
+	err = -EFAULT;
+	switch (cmd) {
+	case PPPIOCSMRU:
+		if (get_user(val, (int *) arg))
+			break;
+		ppp->mru = val;
+		err = 0;
+		break;
+
+	case PPPIOCSFLAGS:
+		if (get_user(val, (int *) arg))
+			break;
+		if (ppp->flags & ~val & SC_CCP_OPEN)
+			ppp_ccp_closed(ppp);
+		ppp->flags = val & SC_FLAG_BITS;
+		err = 0;
+		break;
+
+	case PPPIOCGFLAGS:
+		val = ppp->flags | ppp->xstate | ppp->rstate;
+		if (put_user(val, (int *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCSCOMPRESS:
+		err = ppp_set_compress(ppp, arg);
+		break;
+
+	case PPPIOCGUNIT:
+		if (put_user(ppp->index, (int *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCSDEBUG:
+		if (get_user(val, (int *) arg))
+			break;
+		ppp->debug = val;
+		err = 0;
+		break;
+
+	case PPPIOCGDEBUG:
+		if (put_user(ppp->debug, (int *) arg))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCGIDLE:
+		idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+		idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
+		if (copy_to_user((void *) arg, &idle, sizeof(idle)))
+			break;
+		err = 0;
+		break;
+
+	case PPPIOCSMAXCID:
+		if (get_user(val, (int *) arg))
+			break;
+		val2 = 15;
+		if ((val >> 16) != 0) {
+			val2 = val >> 16;
+			val &= 0xffff;
+		}
+		lock_xmit_path(ppp);
+		lock_recv_path(ppp);
+		if (ppp->vj != 0)
+			slhc_free(ppp->vj);
+		ppp->vj = slhc_init(val2+1, val+1);
+		ppp_recv_unlock(ppp);
+		ppp_xmit_unlock(ppp);
+		err = -ENOMEM;
+		if (ppp->vj == 0) {
+			printk(KERN_ERR "PPP: no memory (VJ compressor)\n");
+			break;
+		}
+		err = 0;
+		break;
+
+	case PPPIOCGNPMODE:
+	case PPPIOCSNPMODE:
+		if (copy_from_user(&npi, (void *) arg, sizeof(npi)))
+			break;
+		err = proto_to_npindex(npi.protocol);
+		if (err < 0)
+			break;
+		i = err;
+		if (cmd == PPPIOCGNPMODE) {
+			err = -EFAULT;
+			npi.mode = ppp->npmode[i];
+			if (copy_to_user((void *) arg, &npi, sizeof(npi)))
+				break;
+		} else {
+			ppp->npmode[i] = npi.mode;
+			/* we may be able to transmit more packets now (??) */
+			mark_bh(NET_BH);
+		}
+		err = 0;
+		break;
+
+	default:
+		err = -ENOTTY;
+	}
+	return err;
+}
+
+static struct file_operations ppp_device_fops = {
+	NULL,		/* seek */
+	ppp_read,
+	ppp_write,
+	NULL,		/* readdir */
+	ppp_poll,
+	ppp_ioctl,
+	NULL,		/* mmap */
+	ppp_open,
+	NULL,		/* flush */
+	ppp_release
+};
+
+#define PPP_MAJOR	108
+
+/* Called at boot time if ppp is compiled into the kernel,
+   or at module load time (from init_module) if compiled as a module. */
+int
+ppp_init(struct device *dev)
+{
+	int err;
+#ifndef MODULE
+	extern struct compressor ppp_deflate, ppp_deflate_draft;
+	extern int ppp_async_init(void);
+#endif
+
+	printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
+	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
+	if (err)
+		printk(KERN_ERR "failed to register PPP device (%d)\n", err);
+#ifndef MODULE
+#ifdef CONFIG_PPP_ASYNC
+	ppp_async_init();
+#endif
+#ifdef CONFIG_PPP_DEFLATE
+	if (ppp_register_compressor(&ppp_deflate) == 0)
+		printk(KERN_INFO "PPP Deflate compression module registered\n");
+	ppp_register_compressor(&ppp_deflate_draft);
+#endif
+#endif /* MODULE */
+
+	return -ENODEV;
+}
+
+/*
+ * Network interface unit routines.
+ */
+static int
+ppp_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct ppp *ppp = (struct ppp *) dev->priv;
+	int npi, proto;
+	unsigned char *pp;
+
+	if (skb == 0)
+		return 0;
+	/* can skb->data ever be 0? */
+
+	npi = ethertype_to_npindex(ntohs(skb->protocol));
+	if (npi < 0)
+		goto outf;
+
+	/* Drop, accept or reject the packet */
+	switch (ppp->npmode[npi]) {
+	case NPMODE_PASS:
+		break;
+	case NPMODE_QUEUE:
+		/* it would be nice to have a way to tell the network
+		   system to queue this one up for later. */
+		goto outf;
+	case NPMODE_DROP:
+	case NPMODE_ERROR:
+		goto outf;
+	}
+
+	/* The transmit side of the ppp interface is serialized by
+	   the XMIT_BUSY bit in ppp->busy. */
+	if (!trylock_xmit_path(ppp)) {
+		dev->tbusy = 1;
+		return 1;
+	}
+	if (ppp->xmit_pending)
+		ppp_push(ppp);
+	if (ppp->xmit_pending) {
+		dev->tbusy = 1;
+		ppp_xmit_unlock(ppp);
+		return 1;
+	}
+	dev->tbusy = 0;
+
+	/* Put the 2-byte PPP protocol number on the front,
+	   making sure there is room for the address and control fields. */
+	if (skb_headroom(skb) < PPP_HDRLEN) {
+		struct sk_buff *ns;
+
+		ns = alloc_skb(skb->len + PPP_HDRLEN, GFP_ATOMIC);
+		if (ns == 0)
+			goto outnbusy;
+		skb_reserve(ns, PPP_HDRLEN);
+		memcpy(skb_put(ns, skb->len), skb->data, skb->len);
+		kfree_skb(skb);
+		skb = ns;
+	}
+	pp = skb_push(skb, 2);
+	proto = npindex_to_proto[npi];
+	pp[0] = proto >> 8;
+	pp[1] = proto;
+
+	ppp_send_frame(ppp, skb);
+	ppp_xmit_unlock(ppp);
+	return 0;
+
+ outnbusy:
+	ppp_xmit_unlock(ppp);
+
+ outf:
+	kfree_skb(skb);
+	return 0;
+}
+
+static struct net_device_stats *
+ppp_net_stats(struct device *dev)
+{
+	struct ppp *ppp = (struct ppp *) dev->priv;
+
+	return &ppp->stats;
+}
+
+static int
+ppp_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ppp *ppp = dev->priv;
+	int err = -EFAULT;
+	void *addr = (void *) ifr->ifr_ifru.ifru_data;
+	struct ppp_stats stats;
+	struct ppp_comp_stats cstats;
+	char *vers;
+
+	switch (cmd) {
+	case SIOCGPPPSTATS:
+		ppp_get_stats(ppp, &stats);
+		if (copy_to_user(addr, &stats, sizeof(stats)))
+			break;
+		err = 0;
+		break;
+
+	case SIOCGPPPCSTATS:
+		memset(&cstats, 0, sizeof(cstats));
+		if (ppp->xc_state != 0)
+			ppp->xcomp->comp_stat(ppp->xc_state, &cstats.c);
+		if (ppp->rc_state != 0)
+			ppp->rcomp->decomp_stat(ppp->rc_state, &cstats.d);
+		if (copy_to_user(addr, &cstats, sizeof(cstats)))
+			break;
+		err = 0;
+		break;
+
+	case SIOCGPPPVER:
+		vers = PPP_VERSION;
+		if (copy_to_user(addr, vers, strlen(vers) + 1))
+			break;
+		err = 0;
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+int
+ppp_net_init(struct device *dev)
+{
+	dev->hard_header_len = PPP_HDRLEN;
+	dev->mtu = PPP_MTU;
+	dev->hard_start_xmit = ppp_start_xmit;
+	dev->get_stats = ppp_net_stats;
+	dev->do_ioctl = ppp_net_ioctl;
+	dev->addr_len = 0;
+	dev->tx_queue_len = 3;
+	dev->type = ARPHRD_PPP;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+
+	dev_init_buffers(dev);
+	return 0;
+}
+
+/*
+ * Transmit-side routines.
+ */
+
+/*
+ * Called to unlock the transmit side of the ppp unit,
+ * making sure that any work queued up gets done.
+ */
+static void
+ppp_xmit_unlock(struct ppp *ppp)
+{
+	struct sk_buff *skb;
+
+	for (;;) {
+		if (test_and_clear_bit(XMIT_WAKEUP, &ppp->busy))
+			ppp_push(ppp);
+		while (ppp->xmit_pending == 0
+		       && (skb = skb_dequeue(&ppp->xq)) != 0)
+			ppp_send_frame(ppp, skb);
+		unlock_xmit_path(ppp);
+		if (!(test_bit(XMIT_WAKEUP, &ppp->busy)
+		      || (ppp->xmit_pending == 0 && skb_peek(&ppp->xq))))
+			break;
+		if (!trylock_xmit_path(ppp))
+			break;
+	}
+}
+
+/*
+ * Compress and send a frame.
+ * The caller should have locked the xmit path,
+ * and xmit_pending should be 0.
+ */
+static void
+ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
+{
+	int proto = PPP_PROTO(skb);
+	struct sk_buff *new_skb;
+	int len;
+	unsigned char *cp;
+
+	++ppp->stats.tx_packets;
+	ppp->stats.tx_bytes += skb->len - 2;
+
+	switch (proto) {
+	case PPP_IP:
+		if (ppp->vj == 0 || (ppp->flags & SC_COMP_TCP) == 0)
+			break;
+		/* try to do VJ TCP header compression */
+		new_skb = alloc_skb(skb->len + 2, GFP_ATOMIC);
+		if (new_skb == 0) {
+			printk(KERN_ERR "PPP: no memory (VJ comp pkt)\n");
+			goto drop;
+		}
+		skb_reserve(new_skb, 2);
+		cp = skb->data + 2;
+		len = slhc_compress(ppp->vj, cp, skb->len - 2,
+				    new_skb->data + 2, &cp,
+				    !(ppp->flags & SC_NO_TCP_CCID));
+		if (cp == skb->data + 2) {
+			/* didn't compress */
+			kfree_skb(new_skb);
+		} else {
+			if (cp[0] & SL_TYPE_COMPRESSED_TCP) {
+				proto = PPP_VJC_COMP;
+				cp[0] &= ~SL_TYPE_COMPRESSED_TCP;
+			} else {
+				proto = PPP_VJC_UNCOMP;
+				cp[0] = skb->data[2];
+			}
+			kfree_skb(skb);
+			skb = new_skb;
+			cp = skb_put(skb, len + 2);
+			cp[0] = 0;
+			cp[1] = proto;
+		}
+		break;
+
+	case PPP_CCP:
+		/* peek at outbound CCP frames */
+		ppp_ccp_peek(ppp, skb, 0);
+		break;
+	}
+
+	/* try to do packet compression */
+	if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
+	    && proto != PPP_LCP && proto != PPP_CCP) {
+		new_skb = alloc_skb(ppp->dev.mtu + PPP_HDRLEN, GFP_ATOMIC);
+		if (new_skb == 0) {
+			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+			goto drop;
+		}
+
+		/* compressor still expects A/C bytes in hdr */
+		len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
+					   new_skb->data, skb->len + 2,
+					   ppp->dev.mtu + PPP_HDRLEN);
+		if (len > 0 && (ppp->flags & SC_CCP_UP)) {
+			kfree_skb(skb);
+			skb = new_skb;
+			skb_put(skb, len);
+			skb_pull(skb, 2);	/* pull off A/C bytes */
+		} else {
+			/* didn't compress, or CCP not up yet */
+			kfree_skb(new_skb);
+		}
+	}
+
+	/*
+	 * If we are waiting for traffic (demand dialling),
+	 * queue it up for pppd to receive.
+	 */
+	if (ppp->flags & SC_LOOP_TRAFFIC) {
+		if (ppp->rq.qlen > PPP_MAX_RQLEN)
+			goto drop;
+		skb_queue_tail(&ppp->rq, skb);
+		wake_up_interruptible(&ppp->rwait);
+		return;
+	}
+
+	ppp->xmit_pending = skb;
+	ppp_push(ppp);
+	return;
+
+ drop:
+	kfree_skb(skb);
+	++ppp->stats.tx_errors;
+}
+
+/*
+ * Try to send the frame in xmit_pending.
+ * The caller should have the xmit path locked.
+ */
+static void
+ppp_push(struct ppp *ppp)
+{
+	struct list_head *list;
+	struct channel *chan;
+	struct sk_buff *skb = ppp->xmit_pending;
+
+	if (skb == 0)
+		return;
+
+	list = &ppp->channels;
+	if (list_empty(list)) {
+		/* nowhere to send the packet, just drop it */
+		ppp->xmit_pending = 0;
+		kfree_skb(skb);
+		return;
+	}
+
+	/* If we are doing multilink, decide which channel gets the
+	   packet, and/or fragment the packet over several links. */
+	/* XXX for now, just take the first channel */
+	list = list->next;
+	chan = list_entry(list, struct channel, list);
+
+	if (chan->chan->ops->start_xmit(chan->chan, skb)) {
+		ppp->xmit_pending = 0;
+		chan->blocked = 0;
+	} else
+		chan->blocked = 1;
+}
+
+/*
+ * Receive-side routines.
+ */
+static inline void
+ppp_do_recv(struct ppp *ppp, struct sk_buff *skb)
+{
+	skb_queue_tail(&ppp->recv_pending, skb);
+	if (trylock_recv_path(ppp))
+		ppp_recv_unlock(ppp);
+}
+
+void
+ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
+{
+	struct channel *pch = chan->ppp;
+
+	if (pch == 0 || skb->len == 0) {
+		kfree_skb(skb);
+		return;
+	}
+	ppp_do_recv(pch->ppp, skb);
+}
+
+/* Put a 0-length skb in the receive queue as an error indication */
+void
+ppp_input_error(struct ppp_channel *chan, int code)
+{
+	struct channel *pch = chan->ppp;
+	struct sk_buff *skb;
+
+	if (pch == 0)
+		return;
+	skb = alloc_skb(0, GFP_ATOMIC);
+	if (skb == 0)
+		return;
+	skb->len = 0;		/* probably unnecessary */
+	skb->cb[0] = code;
+	ppp_do_recv(pch->ppp, skb);
+}
+
+static void
+ppp_recv_unlock(struct ppp *ppp)
+{
+	struct sk_buff *skb;
+
+	for (;;) {
+		while ((skb = skb_dequeue(&ppp->recv_pending)) != 0)
+			ppp_receive_frame(ppp, skb);
+		unlock_recv_path(ppp);
+		if (skb_peek(&ppp->recv_pending) == 0)
+			break;
+		if (!trylock_recv_path(ppp))
+			break;
+	}
+}
+
+static void
+ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
+{
+	struct sk_buff *ns;
+	int proto, len, npi;
+
+	if (skb->len == 0) {
+		/* XXX should do something with code in skb->cb[0] */
+		goto err;	/* error indication */
+	}
+
+	if (skb->len < 2) {
+		++ppp->stats.rx_length_errors;
+		goto err;
+	}
+
+	/* Decompress the frame, if compressed. */
+	if (ppp->rc_state != 0 && (ppp->rstate & SC_DECOMP_RUN)
+	    && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
+		skb = ppp_decompress_frame(ppp, skb);
+
+	proto = PPP_PROTO(skb);
+	switch (proto) {
+	case PPP_VJC_COMP:
+		/* decompress VJ compressed packets */
+		if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
+			goto err;
+		if (skb_tailroom(skb) < 124) {
+			/* copy to a new sk_buff with more tailroom */
+			ns = alloc_skb(skb->len + 128, GFP_ATOMIC);
+			if (ns == 0) {
+				printk(KERN_ERR"PPP: no memory (VJ decomp)\n");
+				goto err;
+			}
+			skb_reserve(ns, 2);
+			memcpy(skb_put(ns, skb->len), skb->data, skb->len);
+			kfree_skb(skb);
+			skb = ns;
+		}
+		len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2);
+		if (len <= 0) {
+			printk(KERN_ERR "PPP: VJ decompression error\n");
+			goto err;
+		}
+		len += 2;
+		if (len > skb->len)
+			skb_put(skb, len - skb->len);
+		else if (len < skb->len)
+			skb_trim(skb, len);
+		proto = PPP_IP;
+		break;
+
+	case PPP_VJC_UNCOMP:
+		if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
+			goto err;
+		if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) {
+			printk(KERN_ERR "PPP: VJ uncompressed error\n");
+			goto err;
+		}
+		proto = PPP_IP;
+		break;
+
+	case PPP_CCP:
+		ppp_ccp_peek(ppp, skb, 1);
+		break;
+	}
+
+	++ppp->stats.rx_packets;
+	ppp->stats.rx_bytes += skb->len - 2;
+
+	npi = proto_to_npindex(proto);
+	if (npi < 0) {
+		/* control or unknown frame - pass it to pppd */
+		skb_queue_tail(&ppp->rq, skb);
+		/* limit queue length by dropping old frames */
+		while (ppp->rq.qlen > PPP_MAX_RQLEN) {
+			skb = skb_dequeue(&ppp->rq);
+			if (skb)
+				kfree_skb(skb);
+		}
+		/* wake up any process polling or blocking on read */
+		wake_up_interruptible(&ppp->rwait);
+
+	} else {
+		/* network protocol frame - give it to the kernel */
+		ppp->last_recv = jiffies;
+		if ((ppp->dev.flags & IFF_UP) == 0
+		    || ppp->npmode[npi] != NPMODE_PASS) {
+			kfree_skb(skb);
+		} else {
+			skb_pull(skb, 2);	/* chop off protocol */
+			skb->dev = &ppp->dev;
+			skb->protocol = htons(npindex_to_ethertype[npi]);
+			skb->mac.raw = skb->data;
+			netif_rx(skb);
+		}
+	}
+	return;
+
+ err:
+	++ppp->stats.rx_errors;
+	if (ppp->vj != 0)
+		slhc_toss(ppp->vj);
+	kfree_skb(skb);
+}
+
+static struct sk_buff *
+ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
+{
+	int proto = PPP_PROTO(skb);
+	struct sk_buff *ns;
+	int len;
+
+	if (proto == PPP_COMP) {
+		ns = alloc_skb(ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
+		if (ns == 0) {
+			printk(KERN_ERR "ppp_receive: no memory\n");
+			goto err;
+		}
+		/* the decompressor still expects the A/C bytes in the hdr */
+		len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2,
+				skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN);
+		if (len < 0) {
+			/* Pass the compressed frame to pppd as an
+			   error indication. */
+			if (len == DECOMP_FATALERROR)
+				ppp->rstate |= SC_DC_FERROR;
+			goto err;
+		}
+
+		kfree_skb(skb);
+		skb = ns;
+		skb_put(skb, len);
+		skb_pull(skb, 2);	/* pull off the A/C bytes */
+
+	} else {
+		/* Uncompressed frame - pass to decompressor so it
+		   can update its dictionary if necessary. */
+		if (ppp->rcomp->incomp)
+			ppp->rcomp->incomp(ppp->rc_state, skb->data - 2,
+					   skb->len + 2);
+	}
+
+	return skb;
+
+ err:
+	ppp->rstate |= SC_DC_ERROR;
+	if (ppp->vj != 0)
+		slhc_toss(ppp->vj);
+	++ppp->stats.rx_errors;
+	return skb;
+}
+
+/*
+ * Channel interface.
+ */
+
+/*
+ * Connect a channel to a given PPP unit.
+ * The channel MUST NOT be connected to a PPP unit already.
+ */
+int
+ppp_register_channel(struct ppp_channel *chan, int unit)
+{
+	struct ppp *ppp;
+	struct channel *pch;
+	int ret = -ENXIO;
+
+	spin_lock(&all_ppp_lock);
+	ppp = ppp_find_unit(unit);
+	if (ppp == 0)
+		goto out;
+	pch = kmalloc(sizeof(struct channel), GFP_ATOMIC);
+	ret = -ENOMEM;
+	if (pch == 0)
+		goto out;
+	memset(pch, 0, sizeof(struct channel));
+	pch->ppp = ppp;
+	pch->chan = chan;
+	list_add(&pch->list, &ppp->channels);
+	chan->ppp = pch;
+	++ppp->n_channels;
+	ret = 0;
+ out:
+	spin_unlock(&all_ppp_lock);
+	return ret;
+}
+
+/*
+ * Disconnect a channel from its PPP unit.
+ */
+void
+ppp_unregister_channel(struct ppp_channel *chan)
+{
+	struct channel *pch;
+
+	spin_lock(&all_ppp_lock);
+	if ((pch = chan->ppp) != 0) {
+		chan->ppp = 0;
+		list_del(&pch->list);
+		--pch->ppp->n_channels;
+		kfree(pch);
+	}
+	spin_unlock(&all_ppp_lock);
+}
+
+/*
+ * Callback from a channel when it can accept more to transmit.
+ * This should ideally be called at BH level, not interrupt level.
+ */
+void
+ppp_output_wakeup(struct ppp_channel *chan)
+{
+	struct channel *pch = chan->ppp;
+	struct ppp *ppp;
+
+	if (pch == 0)
+		return;
+	ppp = pch->ppp;
+	pch->blocked = 0;
+	set_bit(XMIT_WAKEUP, &ppp->busy);
+	if (trylock_xmit_path(ppp))
+		ppp_xmit_unlock(ppp);
+	if (ppp->xmit_pending == 0) {
+		ppp->dev.tbusy = 0;
+		mark_bh(NET_BH);
+	}
+}
+
+/*
+ * Compression control.
+ */
+
+/* Process the PPPIOCSCOMPRESS ioctl. */
+static int
+ppp_set_compress(struct ppp *ppp, unsigned long arg)
+{
+	int err;
+	struct compressor *cp;
+	struct ppp_option_data data;
+	unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];
+#ifdef CONFIG_KMOD
+	char modname[32];
+#endif
+
+	err = -EFAULT;
+	if (copy_from_user(&data, (void *) arg, sizeof(data))
+	    || (data.length <= CCP_MAX_OPTION_LENGTH
+		&& copy_from_user(ccp_option, data.ptr, data.length)))
+		goto out;
+	err = -EINVAL;
+	if (data.length > CCP_MAX_OPTION_LENGTH
+	    || ccp_option[1] < 2 || ccp_option[1] > data.length)
+		goto out;
+
+	cp = find_compressor(ccp_option[0]);
+#ifdef CONFIG_KMOD
+	if (cp == 0) {
+		sprintf(modname, "ppp-compress-%d", ccp_option[0]);
+		request_module(modname);
+		cp = find_compressor(ccp_option[0]);
+	}
+#endif /* CONFIG_KMOD */
+	if (cp == 0)
+		goto out;
+
+	err = -ENOBUFS;
+	if (data.transmit) {
+		lock_xmit_path(ppp);
+		ppp->xstate &= ~SC_COMP_RUN;
+		if (ppp->xc_state != 0) {
+			ppp->xcomp->comp_free(ppp->xc_state);
+			ppp->xc_state = 0;
+		}
+
+		ppp->xcomp = cp;
+		ppp->xc_state = cp->comp_alloc(ccp_option, data.length);
+		ppp_xmit_unlock(ppp);
+		if (ppp->xc_state == 0)
+			goto out;
+
+	} else {
+		lock_recv_path(ppp);
+		ppp->rstate &= ~SC_DECOMP_RUN;
+		if (ppp->rc_state != 0) {
+			ppp->rcomp->decomp_free(ppp->rc_state);
+			ppp->rc_state = 0;
+		}
+
+		ppp->rcomp = cp;
+		ppp->rc_state = cp->decomp_alloc(ccp_option, data.length);
+		ppp_recv_unlock(ppp);
+		if (ppp->rc_state == 0)
+			goto out;
+	}
+	err = 0;
+
+ out:
+	return err;
+}
+
+/*
+ * Look at a CCP packet and update our state accordingly.
+ * We assume the caller has the xmit or recv path locked.
+ */
+static void
+ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
+{
+	unsigned char *dp = skb->data + 2;
+	int len;
+
+	if (skb->len < CCP_HDRLEN + 2
+	    || skb->len < (len = CCP_LENGTH(dp)) + 2)
+		return;		/* too short */
+
+	switch (CCP_CODE(dp)) {
+	case CCP_CONFREQ:
+	case CCP_TERMREQ:
+	case CCP_TERMACK:
+		/*
+		 * CCP is going down - disable compression.
+		 */
+		if (inbound)
+			ppp->rstate &= ~SC_DECOMP_RUN;
+		else
+			ppp->xstate &= ~SC_COMP_RUN;
+		break;
+
+	case CCP_CONFACK:
+		if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN)
+			break;
+		dp += CCP_HDRLEN;
+		len -= CCP_HDRLEN;
+		if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp))
+			break;
+		if (inbound) {
+			/* we will start receiving compressed packets */
+			if (ppp->rc_state == 0)
+				break;
+			if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len,
+					ppp->index, 0, ppp->mru, ppp->debug)) {
+				ppp->rstate |= SC_DECOMP_RUN;
+				ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR);
+			}
+		} else {
+			/* we will soon start sending compressed packets */
+			if (ppp->xc_state == 0)
+				break;
+			if (ppp->xcomp->comp_init(ppp->xc_state, dp, len,
+					ppp->index, 0, ppp->debug))
+				ppp->xstate |= SC_COMP_RUN;
+		}
+		break;
+
+	case CCP_RESETACK:
+		/* reset the [de]compressor */
+		if ((ppp->flags & SC_CCP_UP) == 0)
+			break;
+		if (inbound) {
+			if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN)) {
+				ppp->rcomp->decomp_reset(ppp->rc_state);
+				ppp->rstate &= ~SC_DC_ERROR;
+			}
+		} else {
+			if (ppp->xc_state && (ppp->xstate & SC_COMP_RUN))
+				ppp->xcomp->comp_reset(ppp->xc_state);
+		}
+		break;
+	}
+}
+
+/* Free up compression resources. */
+static void
+ppp_ccp_closed(struct ppp *ppp)
+{
+	ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP);
+
+	lock_xmit_path(ppp);
+	ppp->xstate &= ~SC_COMP_RUN;
+	if (ppp->xc_state) {
+		ppp->xcomp->comp_free(ppp->xc_state);
+		ppp->xc_state = 0;
+	}
+	ppp_xmit_unlock(ppp);
+
+	lock_recv_path(ppp);
+	ppp->xstate &= ~SC_DECOMP_RUN;
+	if (ppp->rc_state) {
+		ppp->rcomp->decomp_free(ppp->rc_state);
+		ppp->rc_state = 0;
+	}
+	ppp_recv_unlock(ppp);
+}
+
+/* List of compressors. */
+static LIST_HEAD(compressor_list);
+static spinlock_t compressor_list_lock = SPIN_LOCK_UNLOCKED;
+
+struct compressor_entry {
+	struct list_head list;
+	struct compressor *comp;
+};
+
+static struct compressor_entry *
+find_comp_entry(int proto)
+{
+	struct compressor_entry *ce;
+	struct list_head *list = &compressor_list;
+
+	while ((list = list->next) != &compressor_list) {
+		ce = list_entry(list, struct compressor_entry, list);
+		if (ce->comp->compress_proto == proto)
+			return ce;
+	}
+	return 0;
+}
+
+/* Register a compressor */
+int
+ppp_register_compressor(struct compressor *cp)
+{
+	struct compressor_entry *ce;
+	int ret;
+
+	spin_lock(&compressor_list_lock);
+	ret = -EEXIST;
+	if (find_comp_entry(cp->compress_proto) != 0)
+		goto out;
+	ret = -ENOMEM;
+	ce = kmalloc(sizeof(struct compressor_entry), GFP_KERNEL);
+	if (ce == 0)
+		goto out;
+	ret = 0;
+	ce->comp = cp;
+	list_add(&ce->list, &compressor_list);
+ out:
+	spin_unlock(&compressor_list_lock);
+	return ret;
+}
+
+/* Unregister a compressor */
+void
+ppp_unregister_compressor(struct compressor *cp)
+{
+	struct compressor_entry *ce;
+
+	spin_lock(&compressor_list_lock);
+	ce = find_comp_entry(cp->compress_proto);
+	if (ce != 0 && ce->comp == cp) {
+		list_del(&ce->list);
+		kfree(ce);
+	}
+	spin_unlock(&compressor_list_lock);
+}
+
+/* Find a compressor. */
+static struct compressor *
+find_compressor(int type)
+{
+	struct compressor_entry *ce;
+	struct compressor *cp = 0;
+
+	spin_lock(&compressor_list_lock);
+	ce = find_comp_entry(type);
+	if (ce != 0)
+		cp = ce->comp;
+	spin_unlock(&compressor_list_lock);
+	return cp;
+}
+
+/*
+ * Miscelleneous stuff.
+ */
+
+static void
+ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
+{
+	struct slcompress *vj = ppp->vj;
+
+	memset(st, 0, sizeof(*st));
+	st->p.ppp_ipackets = ppp->stats.rx_packets;
+	st->p.ppp_ierrors = ppp->stats.rx_errors;
+	st->p.ppp_ibytes = ppp->stats.rx_bytes;
+	st->p.ppp_opackets = ppp->stats.tx_packets;
+	st->p.ppp_oerrors = ppp->stats.tx_errors;
+	st->p.ppp_obytes = ppp->stats.tx_bytes;
+	if (vj == 0)
+		return;
+	st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;
+	st->vj.vjs_compressed = vj->sls_o_compressed;
+	st->vj.vjs_searches = vj->sls_o_searches;
+	st->vj.vjs_misses = vj->sls_o_misses;
+	st->vj.vjs_errorin = vj->sls_i_error;
+	st->vj.vjs_tossed = vj->sls_i_tossed;
+	st->vj.vjs_uncompressedin = vj->sls_i_uncompressed;
+	st->vj.vjs_compressedin = vj->sls_i_compressed;
+}
+
+/*
+ * Stuff for handling the list of ppp units and for initialization.
+ */
+
+/*
+ * Create a new ppp unit.  Fails if it can't allocate memory or
+ * if there is already a unit with the requested number.
+ * unit == -1 means allocate a new number.
+ */
+static struct ppp *
+ppp_create_unit(int unit, int *retp)
+{
+	struct ppp *ppp;
+	struct list_head *list;
+	int last_unit = -1;
+	int ret = -EEXIST;
+	int i;
+
+	spin_lock(&all_ppp_lock);
+	list = &all_ppp_units;
+	while ((list = list->next) != &all_ppp_units) {
+		ppp = list_entry(list, struct ppp, list);
+		if ((unit < 0 && ppp->index > last_unit + 1)
+		    || (unit >= 0 && unit < ppp->index))
+			break;
+		if (unit == ppp->index)
+			goto out;	/* unit already exists */
+		last_unit = ppp->index;
+	}
+	if (unit < 0)
+		unit = last_unit + 1;
+
+	/* Create a new ppp structure and link it before `list'. */
+	ret = -ENOMEM;
+	ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL);
+	if (ppp == 0)
+		goto out;
+	memset(ppp, 0, sizeof(struct ppp));
+
+	ppp->index = unit;
+	sprintf(ppp->name, "ppp%d", unit);
+	ppp->mru = PPP_MRU;
+	skb_queue_head_init(&ppp->xq);
+	skb_queue_head_init(&ppp->rq);
+	init_waitqueue_head(&ppp->rwait);
+	ppp->refcnt = 1;
+	for (i = 0; i < NUM_NP; ++i)
+		ppp->npmode[i] = NPMODE_PASS;
+	INIT_LIST_HEAD(&ppp->channels);
+	skb_queue_head_init(&ppp->recv_pending);
+
+	ppp->dev.init = ppp_net_init;
+	ppp->dev.name = ppp->name;
+	ppp->dev.priv = ppp;
+
+	ret = register_netdev(&ppp->dev);
+	if (ret != 0) {
+		printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);
+		kfree(ppp);
+		goto out;
+	}
+
+	list_add(&ppp->list, list->prev);
+ out:
+	spin_unlock(&all_ppp_lock);
+	*retp = ret;
+	if (ret != 0)
+		ppp = 0;
+	return ppp;
+}
+
+/*
+ * Locate an existing ppp unit.
+ * The caller should have locked the all_ppp_lock.
+ */
+static struct ppp *
+ppp_find_unit(int unit)
+{
+	struct ppp *ppp;
+	struct list_head *list;
+
+	list = &all_ppp_units;
+	while ((list = list->next) != &all_ppp_units) {
+		ppp = list_entry(list, struct ppp, list);
+		if (ppp->index == unit)
+			return ppp;
+	}
+	return 0;
+}
+
+/*
+ * Module stuff.
+ */
+#ifdef MODULE
+int
+init_module(void)
+{
+	ppp_init(0);
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	/* should never happen */
+	if (all_ppp_units.next != &all_ppp_units)
+		printk(KERN_ERR "PPP: removing module but units remain!\n");
+	if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
+		printk(KERN_ERR "PPP: failed to unregister PPP device\n");
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/ptifddi.c linux/drivers/net/ptifddi.c
--- v2.3.12/linux/drivers/net/ptifddi.c	Wed Jun  9 14:45:36 1999
+++ linux/drivers/net/ptifddi.c	Mon Aug  9 11:29:37 1999
@@ -1,4 +1,4 @@
-/* $Id: ptifddi.c,v 1.7 1999/06/09 08:19:01 davem Exp $
+/* $Id: ptifddi.c,v 1.8 1999/08/08 01:35:56 davem Exp $
  * ptifddi.c: Network driver for Performance Technologies single-attach
  *            and dual-attach FDDI sbus cards.
  *
@@ -213,7 +213,7 @@
 	pti_load_main_firmware(pp);
 }
 
-__initfunc(int ptifddi_sbus_probe(struct device *dev))
+int __init ptifddi_sbus_probe(struct device *dev)
 {
 	struct linux_sbus *bus;
 	struct linux_sbus_device *sdev = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.3.12/linux/drivers/net/rcpci45.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/net/rcpci45.c	Thu Aug  5 15:07:42 1999
@@ -226,8 +226,7 @@
 	    !((pdev = pci_find_slot(pci_bus, pci_device_fn))))
             break;
 	pci_irq_line = pdev->irq;
-	pci_ioaddr = pdev->base_address[0];
-        pci_ioaddr &= PCI_BASE_ADDRESS_MEM_MASK;
+	pci_ioaddr = pdev->resource[0].start;
 
 #ifdef RCDEBUG
         printk("rc: Found RedCreek PCI adapter\n");
diff -u --recursive --new-file v2.3.12/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c
--- v2.3.12/linux/drivers/net/rrunner.c	Sat Apr 24 17:51:48 1999
+++ linux/drivers/net/rrunner.c	Mon Aug  9 10:23:09 1999
@@ -72,7 +72,7 @@
 
 static int probed __initdata = 0;
 
-__initfunc(int rr_hippi_probe (struct device *dev))
+int __init rr_hippi_probe (struct device *dev)
 {
 	int boards_found = 0;
 	int version_disp;	/* was version info already displayed? */
@@ -152,14 +152,14 @@
 
 		printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "
 		       "at 0x%08lx, irq %i, PCI latency %i\n", dev->name,
-		       pdev->base_address[0], dev->irq, pci_latency);
+		       pdev->resource[0].start, dev->irq, pci_latency);
 
 		/*
 		 * Remap the regs into kernel space.
 		 */
 
 		rrpriv->regs = (struct rr_regs *)
-			ioremap(pdev->base_address[0], 0x1000);
+			ioremap(pdev->resource[0].start, 0x1000);
 
 		if (!rrpriv->regs){
 			printk(KERN_ERR "%s:  Unable to map I/O register, "
@@ -502,7 +502,7 @@
 }
 
 
-__initfunc(static int rr_init(struct device *dev))
+static int __init rr_init(struct device *dev)
 {
 	struct rr_private *rrpriv;
 	struct rr_regs *regs;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.3.12/linux/drivers/net/rtl8139.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/net/rtl8139.c	Thu Aug  5 15:07:42 1999
@@ -353,7 +353,7 @@
 		{
 #if defined(PCI_SUPPORT_VER2)
 			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-			ioaddr = pdev->base_address[0] & ~3;
+			ioaddr = pdev->resource[0].start;
 			irq = pdev->irq;
 #else
 			u32 pci_ioaddr;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v2.3.12/linux/drivers/net/sdla.c	Tue Dec 29 11:32:06 1998
+++ linux/drivers/net/sdla.c	Thu Aug  5 14:34:02 1999
@@ -1624,7 +1624,7 @@
 	return(&flp->stats);
 }
 
-__initfunc(int sdla_init(struct device *dev))
+int __init sdla_init(struct device *dev)
 {
 	struct frad_local *flp;
 
@@ -1666,7 +1666,7 @@
 	return(0);
 }
 
-__initfunc(void sdla_setup(void))
+void __init sdla_setup(void)
 {
 	printk("%s.\n", version);
 	register_frad(devname);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.3.12/linux/drivers/net/shaper.c	Wed Jun  2 11:29:13 1999
+++ linux/drivers/net/shaper.c	Thu Aug  5 14:35:52 1999
@@ -51,14 +51,19 @@
  *		will render your machine defunct. Don't for now shape over
  *		PPP or SLIP therefore!
  *		This will be fixed in BETA4
- */
- 
-/*
- * bh_atomic() SMP races fixes and rewritten the locking code to be SMP safe
- * and irq-mask friendly. NOTE: we can't use start_bh_atomic() in kick_shaper()
- * because it's going to be recalled from an irq handler, and synchronize_bh()
- * is a nono if called from irq context.
+ *
+ * Update History :
+ *
+ *              bh_atomic() SMP races fixes and rewritten the locking code to
+ *              be SMP safe and irq-mask friendly.
+ *              NOTE: we can't use start_bh_atomic() in kick_shaper()
+ *              because it's going to be recalled from an irq handler,
+ *              and synchronize_bh() is a nono if called from irq context.
  *						1999  Andrea Arcangeli
+ *
+ *              Device statistics (tx_pakets, tx_bytes,
+ *              tx_drops: queue_over_time and collisions: max_queue_exceded)
+ *                               1999/06/18 Jordi Murgo <savage@apostols.org>
  */
  
 #include <linux/module.h>
@@ -228,18 +233,20 @@
 		/*
 		 *	Queue over time. Spill packet.
 		 */
-		if(skb->shapeclock-jiffies > SHAPER_LATENCY)
+		if(skb->shapeclock-jiffies > SHAPER_LATENCY) {
 			dev_kfree_skb(skb);
-		else
+			shaper->stats.tx_dropped++;
+		} else
 			skb_queue_tail(&shaper->sendq, skb);
 	}
 #endif 	
- 	if(sh_debug)
+	if(sh_debug)
  		printk("Frame queued.\n");
  	if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN)
  	{
  		ptr=skb_dequeue(&shaper->sendq);
- 		dev_kfree_skb(ptr);
+                dev_kfree_skb(ptr);
+                shaper->stats.collisions++;
  	}
  	shaper_unlock(shaper);
  	return 0;
@@ -262,7 +269,11 @@
 			printk("Kick new frame to %s, %d\n",
 				shaper->dev->name,newskb->priority);
 		dev_queue_xmit(newskb);
-		if(sh_debug)
+
+                shaper->stats.tx_bytes+=newskb->len;
+		shaper->stats.tx_packets++;
+
+                if(sh_debug)
 			printk("Kicked new frame out.\n");
 		dev_kfree_skb(skb);
 	}
@@ -415,7 +426,8 @@
 
 static struct net_device_stats *shaper_get_stats(struct device *dev)
 {
-	return NULL;
+     	struct shaper *sh=dev->priv;
+	return &sh->stats;
 }
 
 static int shaper_header(struct sk_buff *skb, struct device *dev, 
@@ -590,7 +602,7 @@
  *	Add a shaper device to the system
  */
  
-__initfunc(int shaper_probe(struct device *dev))
+int __init shaper_probe(struct device *dev)
 {
 	/*
 	 *	Set up the shaper.
@@ -665,7 +677,9 @@
 
 void cleanup_module(void)
 {
-	/*
+        struct shaper *sh=dev_shape.priv;
+
+        /*
 	 *	No need to check MOD_IN_USE, as sys_delete_module() checks.
 	 *	To be unloadable we must be closed and detached so we don't
 	 *	need to flush things.
@@ -674,10 +688,9 @@
 	unregister_netdev(&dev_shape);
 
 	/*
-	 *	Free up the private structure, or leak memory :-) 
+	 *	Free up the private structure, or leak memory :-)
 	 */
-	 
-	kfree(dev_shape.priv);
+	kfree(sh);
 	dev_shape.priv = NULL;
 }
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.3.12/linux/drivers/net/sk_g16.c	Sun Mar  7 15:47:46 1999
+++ linux/drivers/net/sk_g16.c	Thu Aug  5 14:35:52 1999
@@ -531,7 +531,7 @@
  *                         (detachable devices only).
  */
 
-__initfunc(int SK_init(struct device *dev))
+int __init SK_init(struct device *dev)
 {
 	int ioaddr         = 0;            /* I/O port address used for POS regs */
 	int *port, ports[] = SK_IO_PORTS;  /* SK_G16 supported ports */
@@ -614,7 +614,7 @@
  *     94/06/30  pwe  SK_ADDR now checked and at the correct place
 -*/
 
-__initfunc(int SK_probe(struct device *dev, short ioaddr))
+int __init SK_probe(struct device *dev, short ioaddr)
 {
     int i,j;                /* Counters */
     int sk_addr_flag = 0;   /* SK ADDR correct? 1 - no, 0 - yes */
@@ -1737,7 +1737,7 @@
  *     YY/MM/DD  uid  Description
 -*/
 
-__initfunc(unsigned int SK_rom_addr(void))
+unsigned int __init SK_rom_addr(void)
 {
     int i,j;
     int rom_found = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v2.3.12/linux/drivers/net/skeleton.c	Tue Feb 10 12:56:45 1998
+++ linux/drivers/net/skeleton.c	Thu Aug  5 14:35:52 1999
@@ -127,8 +127,8 @@
 struct netdev_entry netcard_drv =
 {cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist};
 #else
-__initfunc(int
-netcard_probe(struct device *dev))
+int __init 
+netcard_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -155,7 +155,7 @@
  * probes on the ISA bus. A good device probes avoids doing writes, and
  * verifies that the correct device exists and functions.
  */
-__initfunc(static int netcard_probe1(struct device *dev, int ioaddr))
+static int __init netcard_probe1(struct device *dev, int ioaddr)
 {
 	static unsigned version_printed = 0;
 	int i;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sktr.c linux/drivers/net/sktr.c
--- v2.3.12/linux/drivers/net/sktr.c	Wed May 12 13:27:37 1999
+++ linux/drivers/net/sktr.c	Mon Aug  9 10:23:09 1999
@@ -186,7 +186,7 @@
  * If dev->base_addr == 0, probe all likely locations.
  * If dev->base_addr == 1, always return failure.
  */
-__initfunc(int sktr_probe(struct device *dev))
+int __init sktr_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -217,7 +217,7 @@
 /*
  * Detect and setup the PCI SysKonnect TR cards in slot order.
  */
-__initfunc(static int sktr_pci_chk_card(struct device *dev))
+static int __init sktr_pci_chk_card(struct device *dev)
 {
 	static int pci_index = 0;
 	unsigned char pci_bus, pci_device_fn;
@@ -246,7 +246,7 @@
 
 		pdev		= pci_find_slot(pci_bus, pci_device_fn);
 		pci_irq_line 	= pdev->irq;
-		pci_ioaddr 	= pdev->base_address[0];
+		pci_ioaddr 	= pdev->resource[0].start;
 
 		pcibios_read_config_word(pci_bus, pci_device_fn,
 						PCI_COMMAND, &pci_command);
@@ -295,7 +295,7 @@
 /*
  * Detect and setup the ISA SysKonnect TR cards.
  */
-__initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr))
+static int __init sktr_isa_chk_card(struct device *dev, int ioaddr)
 {
 	int i, err;
 	unsigned long flags;
@@ -386,7 +386,7 @@
 	return (0);
 }
 
-__initfunc(static int sktr_probe1(struct device *dev, int ioaddr))
+static int __init sktr_probe1(struct device *dev, int ioaddr)
 {
 	static unsigned version_printed = 0;
 	struct net_local *tp;
@@ -428,7 +428,7 @@
 }
 
 /* Dummy function */
-__initfunc(static int sktr_init_card(struct device *dev))
+static int __init sktr_init_card(struct device *dev)
 {
 	if(sktr_debug > 3)
 		printk("%s: sktr_init_card\n", dev->name);
@@ -440,7 +440,7 @@
  * This function tests if an adapter is really installed at the
  * given I/O address. Return negative if no adapter at IO addr.
  */
-__initfunc(static int sktr_isa_chk_ioaddr(int ioaddr))
+static int __init sktr_isa_chk_ioaddr(int ioaddr)
 {
 	unsigned char old, chk1, chk2;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v2.3.12/linux/drivers/net/slhc.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/slhc.c	Thu Aug  5 14:35:52 1999
@@ -752,8 +752,7 @@
 }
 
 #else /* MODULE */
-
-__initfunc(void slhc_install(void))
+void __init slhc_install(void)
 {
 }
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v2.3.12/linux/drivers/net/slip.c	Wed May 20 18:55:04 1998
+++ linux/drivers/net/slip.c	Thu Aug  5 14:35:52 1999
@@ -1318,7 +1318,7 @@
 #ifdef MODULE
 static int slip_init_ctrl_dev(void)
 #else	/* !MODULE */
-__initfunc(int slip_init_ctrl_dev(struct device *dummy))
+int __init slip_init_ctrl_dev(struct device *dummy)
 #endif	/* !MODULE */
 {
 	int status;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.3.12/linux/drivers/net/smc-mca.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/smc-mca.c	Thu Aug  5 14:35:52 1999
@@ -66,8 +66,7 @@
 #define ULTRA_IO_EXTENT 32
 #define EN0_ERWCNT      0x08  /* Early receive warning count. */
 
-
-__initfunc(int ultramca_probe(struct device *dev))
+int __init ultramca_probe(struct device *dev)
 {
 	unsigned short ioaddr;
 	unsigned char reg4, num_pages;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.3.12/linux/drivers/net/smc-ultra.c	Wed May 26 09:31:50 1999
+++ linux/drivers/net/smc-ultra.c	Thu Aug  5 14:35:52 1999
@@ -106,7 +106,7 @@
 {"ultra", ultra_probe1, NETCARD_IO_EXTENT, netcard_portlist};
 #else
 
-__initfunc(int ultra_probe(struct device *dev))
+int __init ultra_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -128,7 +128,7 @@
 }
 #endif
 
-__initfunc(int ultra_probe1(struct device *dev, int ioaddr))
+int __init ultra_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	int checksum = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/smc-ultra32.c linux/drivers/net/smc-ultra32.c
--- v2.3.12/linux/drivers/net/smc-ultra32.c	Wed Dec 16 13:35:49 1998
+++ linux/drivers/net/smc-ultra32.c	Thu Aug  5 14:35:52 1999
@@ -103,7 +103,7 @@
 	following.
 */
 
-__initfunc(int ultra32_probe(struct device *dev))
+int __init ultra32_probe(struct device *dev)
 {
 	const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
 	int ioaddr, edge, media;
@@ -126,7 +126,7 @@
 	return ENODEV;
 }
 
-__initfunc(int ultra32_probe1(struct device *dev, int ioaddr))
+int __init ultra32_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	int checksum = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.3.12/linux/drivers/net/smc9194.c	Wed Mar 10 16:51:35 1999
+++ linux/drivers/net/smc9194.c	Thu Aug  5 14:35:52 1999
@@ -750,7 +750,7 @@
  |
  ---------------------------------------------------------------------------
 */
-__initfunc(int smc_init(struct device *dev))
+int __init smc_init(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -795,7 +795,7 @@
  . interrupt, so an auto-detect routine can detect it, and find the IRQ,
  ------------------------------------------------------------------------
 */
-__initfunc(int smc_findirq( int ioaddr ))
+int __init smc_findirq( int ioaddr )
 {
 	int	timeout = 20;
 
@@ -877,7 +877,7 @@
  .---------------------------------------------------------------------
  */
 
-__initfunc(static int smc_probe( int ioaddr ))
+static int __init smc_probe( int ioaddr )
 {
 	unsigned int	bank;
 	word	revision_register;
@@ -942,7 +942,7 @@
  . o  GRAB the region
  .-----------------------------------------------------------------
 */
-__initfunc(static int  smc_initcard(struct device *dev, int ioaddr))
+static int __init smc_initcard(struct device *dev, int ioaddr)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sonic.h linux/drivers/net/sonic.h
--- v2.3.12/linux/drivers/net/sonic.h	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/sonic.h	Mon Aug  9 12:32:28 1999
@@ -9,6 +9,9 @@
  * and pad structure members must be exchanged. Also, the structures
  * need to be changed accordingly to the bus size. 
  *
+ * 981229 MSch:	did just that for the 68k Mac port (32 bit, big endian),
+ *		see CONFIG_MACSONIC branch below.
+ *
  */
 
 #ifndef SONIC_H
@@ -213,6 +216,108 @@
 #define	SONIC_END_OF_LINKS	0x0001
 
 
+#ifdef CONFIG_MACSONIC
+/* Big endian like structures on Mac
+ * (680x0)
+ */
+
+typedef struct {
+  u32 rx_bufadr_l;	/* receive buffer ptr */
+  u32 rx_bufadr_h;
+
+  u32 rx_bufsize_l;	/* no. of words in the receive buffer */
+  u32 rx_bufsize_h;
+} sonic_rr_t;
+
+/*
+ * Sonic receive descriptor. Receive descriptors are
+ * kept in a linked list of these structures.
+ */
+
+typedef struct {
+  SREGS_PAD(pad0);
+  u16 rx_status;	/* status after reception of a packet */
+  SREGS_PAD(pad1);
+  u16 rx_pktlen;	/* length of the packet incl. CRC */
+  
+  /*
+   * Pointers to the location in the receive buffer area (RBA)
+   * where the packet resides. A packet is always received into
+   * a contiguous piece of memory.
+   */
+  SREGS_PAD(pad2);
+  u16 rx_pktptr_l;
+  SREGS_PAD(pad3);
+  u16 rx_pktptr_h;
+
+  SREGS_PAD(pad4);
+  u16 rx_seqno;	/* sequence no. */
+
+  SREGS_PAD(pad5);
+  u16 link;		/* link to next RDD (end if EOL bit set) */
+
+  /*
+   * Owner of this descriptor, 0= driver, 1=sonic
+   */
+  
+  SREGS_PAD(pad6);
+  u16 in_use;	
+
+  caddr_t rda_next;		/* pointer to next RD */
+} sonic_rd_t;
+
+
+/*
+ * Describes a Transmit Descriptor
+ */
+typedef struct {
+  SREGS_PAD(pad0);		
+  u16 tx_status;	/* status after transmission of a packet */
+  SREGS_PAD(pad1);		
+  u16 tx_config;	/* transmit configuration for this packet */
+  SREGS_PAD(pad2);		
+  u16 tx_pktsize;	/* size of the packet to be transmitted */
+  SREGS_PAD(pad3);		
+  u16 tx_frag_count;	/* no. of fragments */
+
+  SREGS_PAD(pad4);		
+  u16 tx_frag_ptr_l;
+  SREGS_PAD(pad5);		
+  u16 tx_frag_ptr_h;
+  SREGS_PAD(pad6);		
+  u16 tx_frag_size;
+  
+  SREGS_PAD(pad7);		
+  u16 link;		/* ptr to next descriptor */
+} sonic_td_t;
+
+
+/*
+ * Describes an entry in the CAM Descriptor Area.
+ */
+
+typedef struct {
+  SREGS_PAD(pad0);
+  u16 cam_entry_pointer;
+  SREGS_PAD(pad1);
+  u16 cam_cap0;
+  SREGS_PAD(pad2);
+  u16 cam_cap1;
+  SREGS_PAD(pad3);
+  u16 cam_cap2;
+} sonic_cd_t;
+
+#define CAM_DESCRIPTORS 16
+
+
+typedef struct {
+  sonic_cd_t cam_desc[CAM_DESCRIPTORS];
+  SREGS_PAD(pad);
+  u16 cam_enable;
+} sonic_cda_t;
+
+#else /* original declarations, little endian 32 bit */
+
 /*
  * structure definitions
  */
@@ -311,14 +416,23 @@
   u16 cam_enable;
   SREGS_PAD(pad);
 } sonic_cda_t;
+#endif	/* endianness */ 
 
 /*
  * Some tunables for the buffer areas. Power of 2 is required
  * the current driver uses one receive buffer for each descriptor.
+ *
+ * MSch: use more buffer space for the slow m68k Macs!
  */
+#ifdef CONFIG_MACSONIC
+#define SONIC_NUM_RRS    32             /* number of receive resources */
+#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
+#define SONIC_NUM_TDS    32      /* number of transmit descriptors */
+#else
 #define SONIC_NUM_RRS    16             /* number of receive resources */
 #define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
 #define SONIC_NUM_TDS    16      /* number of transmit descriptors */
+#endif
 #define SONIC_RBSIZE   1520      /* size of one resource buffer */
 
 #define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.3.12/linux/drivers/net/sunbmac.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/sunbmac.c	Thu Aug  5 14:35:52 1999
@@ -1253,7 +1253,7 @@
 	bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE;
 }
 
-__initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_device *qec_sdev))
+static int __init bigmac_ether_init(struct device *dev, struct linux_sbus_device *qec_sdev)
 {
 	static unsigned version_printed = 0;
 	struct bigmac *bp = 0;
@@ -1492,7 +1492,7 @@
 	return res;	/* Return error code. */
 }
 
-__initfunc(int bigmac_probe(struct device *dev))
+int __init bigmac_probe(struct device *dev)
 {
 	struct linux_sbus *bus;
 	struct linux_sbus_device *sdev = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.12/linux/drivers/net/sunhme.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/sunhme.c	Mon Aug  9 11:29:37 1999
@@ -3324,12 +3324,11 @@
 		qp->happy_meals[qfe_slot] = dev;
 	}		
 
-	hpreg_base = pdev->base_address[0];
-	if((hpreg_base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+	hpreg_base = pdev->resource[0].start;
+	if ((pdev->resource[0].flags & IORESOURCE_IOPORT) != 0) {
 		printk("happymeal(PCI): Cannot find proper PCI device base address.\n");
 		return ENODEV;
 	}
-	hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK;
 
 	if (qfe_slot != -1 && prom_getproplen(node, "local-mac-address") == 6)
 		prom_getproperty(node, "local-mac-address", dev->dev_addr, 6);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.3.12/linux/drivers/net/sunhme.h	Mon Mar 15 16:11:30 1999
+++ linux/drivers/net/sunhme.h	Fri Aug  6 11:58:00 1999
@@ -604,107 +604,75 @@
 /* We use this to acquire receive skb's that we can DMA directly into. */
 #define ALIGNED_RX_SKB_ADDR(addr) \
         ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr))
-static inline struct sk_buff *happy_meal_alloc_skb(unsigned int length, int gfp_flags)
-{
-	struct sk_buff *skb;
-
-	skb = alloc_skb(length + 64, gfp_flags);
-	if(skb) {
-		int offset = ALIGNED_RX_SKB_ADDR(skb->data);
-
-		if(offset)
-			skb_reserve(skb, offset);
-	}
-	return skb;
-}
+#define happy_meal_alloc_skb(__length, __gfp_flags) \
+({	struct sk_buff *__skb; \
+	__skb = alloc_skb((__length) + 64, (__gfp_flags)); \
+	if(__skb) { \
+		int __offset = ALIGNED_RX_SKB_ADDR(__skb->data); \
+		if(__offset) \
+			skb_reserve(__skb, __offset); \
+	} \
+	__skb; \
+})
 
 /* Register/DMA access stuff, used to cope with differences between
  * PCI and SBUS happy meals.
  */
-extern inline u32 kva_to_hva(struct happy_meal *hp, char *addr)
-{
-#ifdef CONFIG_PCI
-	if(hp->happy_flags & HFLAG_PCI)
-		return (u32) virt_to_bus((volatile void *)addr);
-	else
-#endif
-	{
-#ifdef __sparc_v9__
-		if (((unsigned long) addr) >= MAX_DMA_ADDRESS) {
-			printk("sunhme: Bogus DMA buffer address "
-			       "[%016lx]\n", ((unsigned long) addr));
-			panic("DMA address too large, tell DaveM");
-		}
-#endif
-		return sbus_dvma_addr(addr);
-	}
-}
-
-extern inline unsigned int hme_read32(struct happy_meal *hp,
-				      volatile unsigned int *reg)
-{
-#ifdef CONFIG_PCI
-	if(hp->happy_flags & HFLAG_PCI)
-		return readl((unsigned long)reg);
-	else
-#endif
-		return *reg;
-}
-
-extern inline void hme_write32(struct happy_meal *hp,
-			       volatile unsigned int *reg,
-			       unsigned int val)
-{
-#ifdef CONFIG_PCI
-	if(hp->happy_flags & HFLAG_PCI)
-		writel(val, (unsigned long)reg);
-	else
+#if defined(CONFIG_PCI)
+#define kva_to_hva(__hp, __addr) \
+({	u32 __ret; \
+	if ((__hp)->happy_flags & HFLAG_PCI) \
+		(__ret) = (u32) virt_to_bus((volatile void *)(__addr)); \
+	else \
+		(__ret) = sbus_dvma_addr(__addr); \
+	__ret; \
+})
+#define hme_read32(__hp, __reg) \
+({	unsigned int __ret; \
+	if ((__hp)->happy_flags & HFLAG_PCI) \
+		__ret = readl((unsigned long)(__reg)); \
+	else \
+		__ret = *(__reg); \
+	__ret; \
+})
+#define hme_write32(__hp, __reg, __val) \
+do {	if ((__hp)->happy_flags & HFLAG_PCI) \
+		writel((__val), (unsigned long)(__reg)); \
+	else \
+		*(__reg) = (__val); \
+} while(0)
+#else
+#define kva_to_hva(__hp, __addr) ((u32)sbus_dvma_addr(__addr))
+#define hme_read32(__hp, __reg)	(*(__reg))
+#define hme_write32(__hp, __reg, __val)	((*(__reg)) = (__val))
 #endif
-		*reg = val;
-}
 
 #ifdef CONFIG_PCI
 #ifdef __sparc_v9__
-extern inline void pcihme_write_rxd(struct happy_meal_rxd *rp,
-				    unsigned int flags,
-				    unsigned int addr)
-{
-	__asm__ __volatile__("
-	stwa	%3, [%0] %2
-	stwa	%4, [%1] %2
-"	: /* no outputs */
-	: "r" (&rp->rx_addr), "r" (&rp->rx_flags),
-	  "i" (ASI_PL), "r" (addr), "r" (flags));
-}
-
-extern inline void pcihme_write_txd(struct happy_meal_txd *tp,
-				    unsigned int flags,
-				    unsigned int addr)
-{
-	__asm__ __volatile__("
-	stwa	%3, [%0] %2
-	stwa	%4, [%1] %2
-"	: /* no outputs */
-	: "r" (&tp->tx_addr), "r" (&tp->tx_flags),
-	  "i" (ASI_PL), "r" (addr), "r" (flags));
-}
+#define pcihme_write_rxd(__rp, __flags, __addr) \
+	__asm__ __volatile__("stwa	%3, [%0] %2\n\t" \
+			     "stwa	%4, [%1] %2" \
+			     : /* no outputs */ \
+			     : "r" (&(__rp)->rx_addr), "r" (&(__rp)->rx_flags), \
+			       "i" (ASI_PL), "r" (__addr), "r" (__flags))
+
+#define pcihme_write_txd(__tp, __flags, __addr) \
+	__asm__ __volatile__("stwa	%3, [%0] %2\n\t" \
+			     "stwa	%4, [%1] %2" \
+			     : /* no outputs */ \
+			     : "r" (&(__tp)->tx_addr), "r" (&(__tp)->tx_flags), \
+			       "i" (ASI_PL), "r" (__addr), "r" (__flags))
 #else
 
-extern inline void pcihme_write_rxd(struct happy_meal_rxd *rp,
-				    unsigned int flags,
-				    unsigned int addr)
-{
-	rp->rx_addr = flip_dword(addr);
-	rp->rx_flags = flip_dword(flags);
-}
+#define pcihme_write_rxd(__rp, __flags, __addr) \
+do {	(__rp)->rx_addr = flip_dword(__addr); \
+	(__rp)->rx_flags = flip_dword(__flags); \
+} while(0)
 	
-extern inline void pcihme_write_txd(struct happy_meal_txd *tp,
-				    unsigned int flags,
-				    unsigned int addr)
-{
-	tp->tx_addr = flip_dword(addr);
-	tp->tx_flags = flip_dword(flags);
-}
+#define pcihme_write_txd(__tp, __flags, __addr) \
+do {	(__tp)->tx_addr = flip_dword(__addr); \
+	(__tp)->tx_flags = flip_dword(__flags); \
+} while(0)
 	
 #endif  /* def __sparc_v9__ */
 #endif  /* def CONFIG_PCI */
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.3.12/linux/drivers/net/sunlance.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/sunlance.c	Mon Aug  9 11:29:37 1999
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.85 1999/03/21 05:22:05 davem Exp $
+/* $Id: sunlance.c,v 1.87 1999/08/08 01:36:14 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -965,10 +965,10 @@
 	mark_bh(NET_BH);
 }
 
-__initfunc(static int 
+static int __init 
 sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev,
 		  struct Linux_SBus_DMA *ledma,
-		  struct linux_sbus_device *lebuffer))
+		  struct linux_sbus_device *lebuffer)
 {
 	static unsigned version_printed = 0;
 	int    i;
@@ -1157,7 +1157,7 @@
 #include <asm/sun4paddr.h>
 
 /* Find all the lance cards on the system and initialize them */
-__initfunc(int sparc_lance_probe (struct device *dev))
+int __init sparc_lance_probe (struct device *dev)
 {
 	static struct linux_sbus_device sdev;
 	static int called = 0;
@@ -1179,7 +1179,7 @@
 #else /* !CONFIG_SUN4 */
 
 /* Find all the lance cards on the system and initialize them */
-__initfunc(int sparc_lance_probe (struct device *dev))
+int __init sparc_lance_probe (struct device *dev)
 {
 	struct linux_sbus *bus;
 	struct linux_sbus_device *sdev = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.3.12/linux/drivers/net/sunqe.c	Mon Mar 15 16:11:30 1999
+++ linux/drivers/net/sunqe.c	Thu Aug  5 14:35:52 1999
@@ -1173,7 +1173,7 @@
 	return res;
 }
 
-__initfunc(int qec_probe(struct device *dev))
+int __init qec_probe(struct device *dev)
 {
 	struct linux_sbus *bus;
 	struct linux_sbus_device *sdev = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.3.12/linux/drivers/net/tlan.c	Mon Apr 12 16:18:33 1999
+++ linux/drivers/net/tlan.c	Thu Aug  5 15:07:42 1999
@@ -554,7 +554,7 @@
 			);
 
 			*pci_irq = pdev->irq;
-			*pci_io_base = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+			*pci_io_base = pdev->resource[0].start;
 			*pci_dfn = pdev->devfn;
 			pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev);
 			pci_read_config_word ( pdev,  PCI_COMMAND, &pci_command);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.3.12/linux/drivers/net/tulip.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/tulip.c	Fri Aug  6 10:41:47 1999
@@ -497,7 +497,7 @@
 			continue;
 		}
 #if LINUX_VERSION_CODE >= 0x20155
-		pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
+		pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start;
 #else
 		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
 								  &pci_ioaddr);
@@ -572,23 +572,8 @@
 
 	dev = init_etherdev(dev, 0);
 
-#if LINUX_VERSION_CODE >= 0x20155
 	irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
-	ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
-#else
-	{
-		u8 pci_irq_line;
-		u32 pci_ioaddr;
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-								 PCI_INTERRUPT_LINE, &pci_irq_line);
-		pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
-								  &pci_ioaddr);
-		irq = pci_irq_line;
-		ioaddr = pci_ioaddr;
-	}
-#endif
-	/* Remove I/O space marker in bit 0. */
-	ioaddr &= ~3;
+	ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start;
 
 	printk(KERN_INFO "%s: %s at %#3lx,",
 		   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
diff -u --recursive --new-file v2.3.12/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.3.12/linux/drivers/net/via-rhine.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/via-rhine.c	Thu Aug  5 15:07:42 1999
@@ -431,9 +431,9 @@
 #if defined(PCI_SUPPORT_VER2)
 			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
 #ifdef VIA_USE_IO
-			pciaddr = pdev->base_address[0];
+			pciaddr = pdev->resource[0].start;
 #else
-			pciaddr = pdev->base_address[1];
+			pciaddr = pdev->resource[1].start;
 #endif
 			irq = pdev->irq;
 #else
diff -u --recursive --new-file v2.3.12/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v2.3.12/linux/drivers/net/wd.c	Thu Dec 17 09:04:49 1998
+++ linux/drivers/net/wd.c	Thu Aug  5 14:35:52 1999
@@ -86,7 +86,7 @@
 {"wd", wd_probe1, WD_IO_EXTENT, wd_portlist};
 #else
 
-__initfunc(int wd_probe(struct device *dev))
+int __init wd_probe(struct device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -108,7 +108,7 @@
 }
 #endif
 
-__initfunc(int wd_probe1(struct device *dev, int ioaddr))
+int __init wd_probe1(struct device *dev, int ioaddr)
 {
 	int i;
 	int checksum = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c
--- v2.3.12/linux/drivers/net/x25_asy.c	Fri Feb 20 18:28:22 1998
+++ linux/drivers/net/x25_asy.c	Thu Aug  5 14:35:52 1999
@@ -818,7 +818,7 @@
 #ifdef MODULE
 static int x25_asy_init_ctrl_dev(void)
 #else	/* !MODULE */
-__initfunc(int x25_asy_init_ctrl_dev(struct device *dummy))
+int __init x25_asy_init_ctrl_dev(struct device *dummy)
 #endif	/* !MODULE */
 {
 	int status;
diff -u --recursive --new-file v2.3.12/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.3.12/linux/drivers/net/yellowfin.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/net/yellowfin.c	Thu Aug  5 15:07:42 1999
@@ -377,23 +377,10 @@
 			continue;
 
 		{
-#if LINUX_VERSION_CODE >= 0x20155  ||  PCI_SUPPORT_1
 			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-			ioaddr = pdev->base_address[0];
+			ioaddr = pdev->resource[0].start;
 			irq = pdev->irq;
-#else
-			u32 pci_ioaddr;
-			u8 pci_irq_line;
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_INTERRUPT_LINE, &pci_irq_line);
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-			ioaddr = pci_ioaddr;
-			irq = pci_irq_line;
-#endif
 		}
-		/* Remove I/O space marker in bit 0. */
-		ioaddr &= ~3;
 
 		if (yellowfin_debug > 2)
 			printk(KERN_INFO "Found %s at I/O %#lx, IRQ %d.\n",
diff -u --recursive --new-file v2.3.12/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v2.3.12/linux/drivers/net/znet.c	Thu Jan 14 10:31:41 1999
+++ linux/drivers/net/znet.c	Thu Aug  5 14:35:52 1999
@@ -200,7 +200,7 @@
    BIOS area.  We just scan for the signature, and pull the vital parameters
    out of the structure. */
 
-__initfunc(int znet_probe(struct device *dev))
+int __init znet_probe(struct device *dev)
 {
 	int i;
 	struct netidblk *netinfo;
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/Config.in linux/drivers/parport/Config.in
--- v2.3.12/linux/drivers/parport/Config.in	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/Config.in	Tue Aug  3 15:30:44 1999
@@ -11,6 +11,11 @@
   if [ "$CONFIG_PARPORT_PC" != "n" ]; then
     bool '   Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
   fi
+  if [ "$CONFIG_PARPORT_PC" = "y" ]; then
+    # Don't bother with this if parport_pc is a module; it only affects
+    # the presence or not of some __init's, which are no-ops for modules.
+    bool '   Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA
+  fi
   if [ "$CONFIG_ARM" = "y" ]; then
     dep_tristate '   Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
   fi
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/Makefile linux/drivers/parport/Makefile
--- v2.3.12/linux/drivers/parport/Makefile	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/Makefile	Mon Aug  2 11:16:02 1999
@@ -33,7 +33,7 @@
     LX_OBJS += parport_pc.o
   else
     ifeq ($(CONFIG_PARPORT_PC),m)
-      M_OBJS += parport_pc.o
+      MX_OBJS += parport_pc.o
     endif
   endif
   ifeq ($(CONFIG_PARPORT_AMIGA),y)
@@ -71,10 +71,7 @@
     M_OBJS += parport.o
   endif
   ifeq ($(CONFIG_PARPORT_PC),m)
-    M_OBJS += parport_pc.o
-  endif
-  ifeq ($(CONFIG_PARPORT_AX),m)
-    M_OBJS += parport_ax.o
+    MX_OBJS += parport_pc.o
   endif
   ifeq ($(CONFIG_PARPORT_AMIGA),m)
     M_OBJS += parport_amiga.o
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- v2.3.12/linux/drivers/parport/ieee1284.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/ieee1284.c	Fri Aug  6 15:25:47 1999
@@ -310,13 +310,9 @@
 
 	/* Event 6: nAck goes high */
 	if (parport_wait_peripheral (port,
-				     PARPORT_STATUS_ACK
-				     | PARPORT_STATUS_PAPEROUT,
+				     PARPORT_STATUS_ACK,
 				     PARPORT_STATUS_ACK)) {
-		if (parport_read_status (port) & PARPORT_STATUS_ACK)
-			printk (KERN_DEBUG
-				"%s: working around buggy peripheral: tell "
-				"Tim what make it is\n", port->name);
+		/* This shouldn't really happen with a compliant device. */
 		DPRINTK (KERN_DEBUG
 			 "%s: Mode 0x%02x not supported? (0x%02x)\n",
 			 port->name, mode, port->ops->read_status (port));
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.3.12/linux/drivers/parport/ieee1284_ops.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/ieee1284_ops.c	Fri Aug  6 15:25:47 1999
@@ -43,6 +43,7 @@
 				      const void *buffer, size_t len,
 				      int flags)
 {
+	int no_irq;
 	ssize_t count = 0;
 	const unsigned char *addr = buffer;
 	unsigned char byte;
@@ -54,6 +55,7 @@
 		parport_enable_irq (port);
 
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+	no_irq = polling (dev);
 	while (count < len) {
 		long expire = jiffies + dev->timeout;
 		long wait = (HZ + 99) / 100;
@@ -97,7 +99,7 @@
                            first time around the loop, don't let go of
                            the port.  This way, we find out if we have
                            our interrupt handler called. */
-			if (count && polling (dev)) {
+			if (count && no_irq) {
 				parport_release (dev);
 				current->state = TASK_INTERRUPTIBLE;
 				schedule_timeout (wait);
@@ -129,14 +131,30 @@
 		parport_write_control (port, ctl);
 		udelay (1); /* hold */
 
-		/* Wait until it's received (up to 20us). */
-		for (i = 0; i < 20; i++) {
+		if (no_irq)
+			/* Assume the peripheral received it. */
+			goto done;
+
+		/* Wait until it's received, up to 500us (this ought to be
+		 * tuneable). */
+		for (i = 500; i; i--) {
 			if (!down_trylock (&port->physport->ieee1284.irq) ||
 			    !(parport_read_status (port) & PARPORT_STATUS_ACK))
-				break;
+				goto done;
 			udelay (1);
 		}
 
+		/* Two choices:
+		 * 1. Assume that the peripheral got the data and just
+		 *    hasn't acknowledged it yet.
+		 * 2. Assume that the peripheral never saw the strobe pulse.
+		 *
+		 * We can't know for sure, so let's be conservative.
+		 */
+		DPRINTK (KERN_DEBUG "%s: no ack", port->name);
+		break;
+
+	done:
 		count++;
 
                 /* Let another process run if it needs to. */
@@ -344,14 +362,14 @@
 	/* Event 38: Set nAutoFd low */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_AUTOFD,
-			      PARPORT_CONTROL_AUTOFD);
+			      0);
 	parport_data_reverse (port);
 	udelay (5);
 
 	/* Event 39: Set nInit low to initiate bus reversal */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_INIT,
-			      PARPORT_CONTROL_INIT);
+			      0);
 
 	/* Event 40: PError goes low */
 	retval = parport_wait_peripheral (port,
@@ -373,9 +391,10 @@
 
 	/* Event 47: Set nInit high */
 	parport_frob_control (port,
-			      PARPORT_CONTROL_INIT,
-			      PARPORT_CONTROL_INIT);
-	parport_data_reverse (port);
+			      PARPORT_CONTROL_INIT
+			      | PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_INIT
+			      | PARPORT_CONTROL_AUTOFD);
 
 	/* Event 49: PError goes high */
 	retval = parport_wait_peripheral (port,
@@ -404,7 +423,6 @@
 #else
 	const unsigned char *buf = buffer;
 	size_t written;
-	int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
 	int retry;
 
 	port = port->physport;
@@ -416,7 +434,11 @@
 	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
 	/* HostAck high (data, not command) */
-	parport_write_control (port, ctl);
+	parport_frob_control (port,
+			      PARPORT_CONTROL_AUTOFD
+			      | PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
 	for (written = 0; written < len; written++, buf++) {
 		long expire = jiffies + port->cad->timeout;
 		unsigned char byte;
@@ -424,7 +446,8 @@
 		byte = *buf;
 	try_again:
 		parport_write_data (port, byte);
-		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
 		udelay (5);
 		for (retry = 0; retry < 100; retry++) {
 			if (!parport_wait_peripheral (port,
@@ -432,7 +455,9 @@
 				goto success;
 
 			if (signal_pending (current)) {
-				parport_write_control (port, ctl);
+				parport_frob_control (port,
+						      PARPORT_CONTROL_STROBE,
+						      0);
 				break;
 			}
 		}
@@ -440,15 +465,16 @@
 		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
 		DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
 
-		parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+		parport_frob_control (port, PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
 		udelay (50);
 		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
 			/* It's buggered. */
-			parport_write_control (port, ctl);
+			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 			break;
 		}
 
-		parport_write_control (port, ctl);
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 		udelay (50);
 		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
 			break;
@@ -459,7 +485,7 @@
 		if (time_after_eq (jiffies, expire)) break;
 		goto try_again;
 	success:
-		parport_write_control (port, ctl);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 		udelay (5);
 		if (parport_wait_peripheral (port,
 					     PARPORT_STATUS_BUSY,
@@ -496,7 +522,10 @@
 	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
 
 	/* Set HostAck low to start accepting data. */
-	parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+	parport_frob_control (port,
+			      PARPORT_CONTROL_AUTOFD
+			      | PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_INIT,
 			      PARPORT_CONTROL_AUTOFD);
 	while (count < len) {
 		long expire = jiffies + dev->timeout;
@@ -505,9 +534,7 @@
 
 		/* Event 43: Peripheral sets nAck low. It can take as
                    long as it wants. */
-		while (parport_wait_peripheral (port,
-						PARPORT_STATUS_ACK,
-						PARPORT_STATUS_ACK)) {
+		while (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
 			/* The peripheral hasn't given us data in
 			   35ms.  If we have data to give back to the
 			   caller, do it now. */
@@ -578,7 +605,8 @@
 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
 
 		/* Event 45: The peripheral has 35ms to set nAck high. */
-		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
+		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK,
+					     PARPORT_STATUS_ACK)) {
 			/* It's gone wrong.  Return what data we have
                            to the caller. */
 			DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
@@ -615,6 +643,7 @@
 	}
 
  out:
+	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
 	return count;
 #endif /* IEEE1284 support */
 }
@@ -629,7 +658,6 @@
 #else
 	const unsigned char *buf = buffer;
 	size_t written;
-	int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
 	int retry;
 
 	port = port->physport;
@@ -641,7 +669,12 @@
 	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 
 	/* HostAck low (command, not data) */
-	parport_write_control (port, ctl);
+	parport_frob_control (port,
+			      PARPORT_CONTROL_AUTOFD
+			      | PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_AUTOFD
+			      | PARPORT_CONTROL_INIT);
 	for (written = 0; written < len; written++, buf++) {
 		long expire = jiffies + port->cad->timeout;
 		unsigned char byte;
@@ -649,7 +682,8 @@
 		byte = *buf;
 	try_again:
 		parport_write_data (port, byte);
-		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
 		udelay (5);
 		for (retry = 0; retry < 100; retry++) {
 			if (!parport_wait_peripheral (port,
@@ -657,7 +691,9 @@
 				goto success;
 
 			if (signal_pending (current)) {
-				parport_write_control (port, ctl);
+				parport_frob_control (port,
+						      PARPORT_CONTROL_STROBE,
+						      0);
 				break;
 			}
 		}
@@ -665,15 +701,16 @@
 		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
 		DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
 
-		parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+		parport_frob_control (port, PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
 		udelay (50);
 		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
 			/* It's buggered. */
-			parport_write_control (port, ctl);
+			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 			break;
 		}
 
-		parport_write_control (port, ctl);
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
 		udelay (50);
 		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
 			break;
@@ -684,7 +721,7 @@
 		if (time_after_eq (jiffies, expire)) break;
 		goto try_again;
 	success:
-		parport_write_control (port, ctl);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 		udelay (5);
 		if (parport_wait_peripheral (port,
 					     PARPORT_STATUS_BUSY,
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/init.c linux/drivers/parport/init.c
--- v2.3.12/linux/drivers/parport/init.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/init.c	Tue Aug  3 15:24:27 1999
@@ -11,7 +11,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/threads.h>
-
+#include <linux/string.h>
 #include <linux/parport.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -28,71 +28,86 @@
 
 static int parport_setup_ptr __initdata = 0;
 
-__initfunc(void parport_setup(char *str, int *ints))
+/*
+ * Acceptable parameters:
+ *
+ * parport=0
+ * parport=auto
+ * parport=0xBASE[,IRQ[,DMA]]
+ *
+ * IRQ/DMA may be numeric or 'auto' or 'none'
+ */
+static int __init parport_setup (char *str)
 {
-	if (ints[0] == 0) {
-		if (str && !strncmp(str, "auto", 4)) {
-			irq[0] = PARPORT_IRQ_AUTO;
-			dma[0] = PARPORT_DMA_AUTO;
-		}
-		else if (str)
-			printk (KERN_ERR "parport: `%s': huh?\n", str);
-		else
-			printk (KERN_ERR "parport: parport=.. what?\n");
-		
-		return;
-	}
-	else if (ints[1] == 0) {
+	char *endptr;
+	char *sep;
+	int val;
+
+	if (!str || !*str || (*str == '0' && !*(str+1))) {
 		/* Disable parport if "parport=0" in cmdline */
-		io[0] = PARPORT_DISABLE; 
-		return;
+		io[0] = PARPORT_DISABLE;
+		return 0;
 	}
 
-	if (parport_setup_ptr < PARPORT_MAX) {
-		char *sep;
-		io[parport_setup_ptr] = ints[1];
-		irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
-		dma[parport_setup_ptr] = PARPORT_DMA_NONE;
-		if (ints[0] > 1) {
-			irq[parport_setup_ptr] = ints[2];
-			if (ints[0] > 2) {
-				dma[parport_setup_ptr] = ints[3];
-				goto done;
-			}
+	if (!strncmp (str, "auto", 4)) {
+		irq[0] = PARPORT_IRQ_AUTO;
+		dma[0] = PARPORT_DMA_AUTO;
+		return 0;
+	}
 
-			if (str == NULL)
-				goto done;
+	val = simple_strtoul (str, &endptr, 0);
+	if (endptr == str) {
+		printk (KERN_WARNING "parport=%s not understood\n", str);
+		return 1;
+	}
 
-			goto dma_from_str;
-		}
-		else if (str == NULL)
-			goto done;
-		else if (!strncmp(str, "auto", 4))
+	if (parport_setup_ptr == PARPORT_MAX) {
+		printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
+		return 1;
+	}
+	
+	io[parport_setup_ptr] = val;
+	irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
+	dma[parport_setup_ptr] = PARPORT_DMA_NONE;
+
+	sep = strchr (str, ',');
+	if (sep++) {
+		if (!strncmp (sep, "auto", 4))
 			irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
-		else if (strncmp(str, "none", 4) != 0) {
-			printk(KERN_ERR "parport: bad irq `%s'\n", str);
-			return;
+		else if (strncmp (sep, "none", 4)) {
+			val = simple_strtoul (sep, &endptr, 0);
+			if (endptr == sep) {
+				printk (KERN_WARNING
+					"parport=%s: irq not understood\n",
+					str);
+				return 1;
+			}
+			irq[parport_setup_ptr] = val;
 		}
+	}
 
-		if ((sep = strchr(str, ',')) == NULL) goto done;
-		str = sep+1;
-	dma_from_str:
-		if (!strncmp(str, "auto", 4))
+	sep = strchr (sep, ',');
+	if (sep++) {
+		if (!strncmp (sep, "auto", 4))
 			dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
-		else if (strncmp(str, "none", 4) != 0) {
-			char *ep;
-			dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
-			if (ep == str) {
-				printk(KERN_ERR "parport: bad dma `%s'\n",
-				       str);
-				return;
+		else if (strncmp (sep, "none", 4)) {
+			val = simple_strtoul (sep, &endptr, 0);
+			if (endptr == sep) {
+				printk (KERN_WARNING
+					"parport=%s: dma not understood\n",
+					str);
+				return 1;
 			}
+			dma[parport_setup_ptr] = val;
 		}
-	done:
-		parport_setup_ptr++;
-	} else
-		printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
+	}
+
+	parport_setup_ptr++;
+	return 0;
 }
+
+__setup ("parport=", parport_setup);
+
 #endif
 
 #ifdef MODULE
@@ -113,7 +128,7 @@
 
 #else
 
-__initfunc(int parport_init(void))
+int __init parport_init (void)
 {
 	if (io[0] == PARPORT_DISABLE) 
 		return 1;
@@ -139,6 +154,9 @@
 #endif
 	return 0;
 }
+
+__initcall (parport_init);
+
 #endif
 
 /* Exported symbols for modules. */
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c
--- v2.3.12/linux/drivers/parport/parport_amiga.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/parport_amiga.c	Mon Aug  9 12:32:28 1999
@@ -25,7 +25,7 @@
 #ifdef DEBUG
 #define DPRINTK printk
 #else
-static inline int DPRINTK() {return 0;}
+#define DPRINTK(format, args...)
 #endif
 
 static struct parport *this_port = NULL;
@@ -48,10 +48,6 @@
 {
 	unsigned char ret = 0;
 
-	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
-		;
-	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
-		;
 	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
 		;
 	if (control & PARPORT_CONTROL_INIT) /* INITP */
@@ -66,7 +62,7 @@
 
 static unsigned char control_amiga_to_pc(unsigned char control)
 {
-	return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+	return PARPORT_CONTROL_SELECT |
 	      PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
 	/* fake value: interrupt enable, select in, no reset,
 	no autolf, no strobe - seems to be closest the wiring diagram */
@@ -127,12 +123,6 @@
 	return ret;
 }
 
-static void amiga_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK("write_status %02x\n",status);
-	ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
-}
-
 static unsigned char amiga_read_status(struct parport *p)
 {
 	unsigned char status;
@@ -142,20 +132,13 @@
 	return status;
 }
 
-static void amiga_change_mode( struct parport *p, int m)
-{
-	/* XXX: This port only has one mode, and I am
-	not sure about the corresponding PC-style mode*/
-}
-
 /* as this ports irq handling is already done, we use a generic funktion */
 static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
-
-static void amiga_init_state(struct parport_state *s)
+static void amiga_init_state(struct pardevice *dev, struct parport_state *s)
 {
 	s->u.amiga.data = 0;
 	s->u.amiga.datadir = 255;
@@ -215,8 +198,6 @@
 	NULL, /* data_forward */
 	NULL, /* data_reverse */
 
-	amiga_interrupt, 
-
 	amiga_init_state,
 	amiga_save_state,
 	amiga_restore_state,
@@ -224,18 +205,18 @@
 	amiga_inc_use_count,
 	amiga_dec_use_count,
 
-	parport_ieee1284_epp_write_data,
-	parport_ieee1284_epp_read_data, /* impossible? */
-	parport_ieee1284_epp_write_addr,
-	parport_ieee1284_epp_read_addr, /* impossible? */
-
-	parport_ieee1284_ecp_write_data,
-	parport_ieee1284_ecp_read_data, /* impossible? */
-	parport_ieee1284_ecp_write_addr,
-
-	parport_ieee1284_write_compat, /* FIXME - need to write amiga one */
-	parport_ieee1284_read_nibble,
-	parport_ieee1284_read_byte, /* impossible? */
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+
+	NULL, /* ecp_write_data */
+	NULL, /* ecp_read_data */
+	NULL, /* ecp_write_addr */
+
+	NULL, /* compat_write_data */
+	NULL, /* nibble_read_data */
+	NULL, /* byte_read_data */
 };
 
 /* ----------- Initialisation code --------------------------------- */
@@ -251,20 +232,17 @@
 					IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
 					&pp_amiga_ops)))
 			return 0;
-		this_port = p;
-		printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
-		/* XXX: set operating mode */
-		parport_proc_register(p);
-		if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0,
-				p->name, p)) {
+		if (!request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p)) {
 			parport_unregister_port (p);
 			return 0;
 		}
 
-		if (parport_probe_hook)
-			(*parport_probe_hook)(p);
+		this_port = p;
+		printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+		/* XXX: set operating mode */
+		parport_proc_register(p);
 
-		parport_announce_port (p);
+		parport_announce_port(p);
 
 		return 1;
 
@@ -285,8 +263,8 @@
 
 void cleanup_module(void)
 {
-	if (p->irq != PARPORT_IRQ_NONE)
-		free_irq(IRQ_AMIGA_CIAA_FLG, p);
+	if (this_port->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_MFP_BUSY, this_port);
 	parport_proc_unregister(this_port);
 	parport_unregister_port(this_port);
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/parport_arc.c linux/drivers/parport/parport_arc.c
--- v2.3.12/linux/drivers/parport/parport_arc.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/parport_arc.c	Thu Aug  5 14:23:14 1999
@@ -96,8 +96,6 @@
 	arc_data_forward,
 	arc_data_reverse,
 
-	arc_interrupt,
-
 	arc_init_state,
 	arc_save_state,
 	arc_restore_state,
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/parport_atari.c linux/drivers/parport/parport_atari.c
--- v2.3.12/linux/drivers/parport/parport_atari.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/parport_atari.c	Mon Aug  9 12:32:28 1999
@@ -92,7 +92,7 @@
 }
 
 static void
-parport_atari_init_state(struct parport_state *s)
+parport_atari_init_state(struct pardevice *d, struct parport_state *s)
 {
 }
 
@@ -140,8 +140,6 @@
 	NULL, /* data_forward - FIXME */
 	NULL, /* data_reverse - FIXME */
 
-	parport_atari_interrupt,
-
 	parport_atari_init_state,
 	parport_atari_save_state,
 	parport_atari_restore_state,
@@ -149,18 +147,18 @@
 	parport_atari_inc_use_count,
 	parport_atari_dec_use_count,
 
-	parport_ieee1284_epp_write_data,
-	parport_ieee1284_epp_read_data,
-	parport_ieee1284_epp_write_addr,
-	parport_ieee1284_epp_read_addr,
-
-	parport_ieee1284_ecp_write_data,
-	parport_ieee1284_ecp_read_data,
-	parport_ieee1284_ecp_write_addr,
-
-	parport_ieee1284_write_compat,
-	parport_ieee1284_read_nibble,
-	parport_ieee1284_read_byte,
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+
+	NULL, /* ecp_write_data */
+	NULL, /* ecp_read_data */
+	NULL, /* ecp_write_addr */
+
+	NULL, /* compat_write_data */
+	NULL, /* nibble_read_data */
+	NULL, /* byte_read_data */
 };
 
 
@@ -221,8 +219,8 @@
 void
 cleanup_module(void)
 {
-	if (p->irq != PARPORT_IRQ_NONE)
-		free_irq(IRQ_MFP_BUSY, p);
+	if (this_port->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_MFP_BUSY, this_port);
 	parport_proc_unregister(this_port);
 	parport_unregister_port(this_port);
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c
--- v2.3.12/linux/drivers/parport/parport_mfc3.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/parport_mfc3.c	Thu Aug  5 14:23:14 1999
@@ -290,8 +290,6 @@
 	NULL, /* data_forward - FIXME */
 	NULL, /* data_reverse - FIXME */
 
-	mfc3_interrupt,
-
 	mfc3_init_state,
 	mfc3_save_state,
 	mfc3_restore_state,
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.12/linux/drivers/parport/parport_pc.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/parport_pc.c	Mon Aug  9 11:37:37 1999
@@ -10,7 +10,6 @@
  *
  * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  * DMA support - Bert De Jonghe <bert@sophis.be>
- * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -34,6 +33,9 @@
  * only in register addresses (eg because your registers are on 32-bit
  * word boundaries) then you can alter the constants in parport_pc.h to
  * accomodate this.
+ *
+ * Note that the ECP registers may not start at offset 0x400 for PCI cards,
+ * but rather will start at port->base_hi.
  */
 
 #include <linux/config.h>
@@ -74,7 +76,7 @@
 	outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
 }
 
-#ifdef CONFIG_PARPORT_1284
+#if defined(CONFIG_PARPORT_1284) || defined(CONFIG_PARPORT_PC_FIFO)
 /* Safely change the mode bits in the ECR */
 static int change_mode(struct parport *p, int m)
 {
@@ -179,7 +181,7 @@
 	return residue;
 }
 
-#endif /* IEEE 1284 support */
+#endif /* IEEE 1284 support or FIFO support */
 
 /*
  * Clear TIMEOUT BIT in EPP MODE
@@ -229,12 +231,16 @@
 unsigned char __frob_control (struct parport *p, unsigned char mask,
 			      unsigned char val)
 {
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
 	struct parport_pc_private *priv = p->physport->private_data;
 	unsigned char ctr = priv->ctr;
 	ctr = (ctr & ~mask) ^ val;
 	ctr &= priv->ctr_writable; /* only write writable bits. */
 	outb (ctr, CONTROL (p));
-	return priv->ctr = ctr; /* update soft copy */
+	return priv->ctr = ctr & wm; /* update soft copy */
 }
 
 void parport_pc_write_control(struct parport *p, unsigned char d)
@@ -939,7 +945,6 @@
 	parport_pc_data_forward,
 	parport_pc_data_reverse,
 
-	parport_pc_interrupt,
 	parport_pc_init_state,
 	parport_pc_save_state,
 	parport_pc_restore_state,
@@ -966,7 +971,7 @@
 /*
  * Checks for port existence, all ports support SPP MODE
  */
-static int __init parport_SPP_supported(struct parport *pb)
+static int __maybe_init parport_SPP_supported(struct parport *pb)
 {
 	unsigned char r, w;
 
@@ -1043,7 +1048,7 @@
  * two bits of ECR aren't writable, so we check by writing ECR and
  * reading it back to see if it's what we expect.
  */
-static int __init parport_ECR_present(struct parport *pb)
+static int __maybe_init parport_ECR_present(struct parport *pb)
 {
 	struct parport_pc_private *priv = pb->private_data;
 	unsigned char r = 0xc;
@@ -1096,7 +1101,7 @@
  * be misdetected here is rather academic. 
  */
 
-static int __init parport_PS2_supported(struct parport *pb)
+static int __maybe_init parport_PS2_supported(struct parport *pb)
 {
 	int ok = 0;
   
@@ -1124,7 +1129,7 @@
 	return ok;
 }
 
-static int __init parport_ECP_supported(struct parport *pb)
+static int __maybe_init parport_ECP_supported(struct parport *pb)
 {
 	int i;
 	int config;
@@ -1235,7 +1240,7 @@
 	return 1;
 }
 
-static int __init parport_ECPPS2_supported(struct parport *pb)
+static int __maybe_init parport_ECPPS2_supported(struct parport *pb)
 {
 	const struct parport_pc_private *priv = pb->private_data;
 	int result;
@@ -1255,7 +1260,7 @@
 
 /* EPP mode detection  */
 
-static int __init parport_EPP_supported(struct parport *pb)
+static int __maybe_init parport_EPP_supported(struct parport *pb)
 {
 	const struct parport_pc_private *priv = pb->private_data;
 
@@ -1290,15 +1295,15 @@
 	pb->modes |= PARPORT_MODE_EPP;
 
 	/* Set up access functions to use EPP hardware. */
-	parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
-	parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
-	parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
-	parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
+	pb->ops->epp_read_data = parport_pc_epp_read_data;
+	pb->ops->epp_write_data = parport_pc_epp_write_data;
+	pb->ops->epp_read_addr = parport_pc_epp_read_addr;
+	pb->ops->epp_write_addr = parport_pc_epp_write_addr;
 
 	return 1;
 }
 
-static int __init parport_ECPEPP_supported(struct parport *pb)
+static int __maybe_init parport_ECPEPP_supported(struct parport *pb)
 {
 	struct parport_pc_private *priv = pb->private_data;
 	int result;
@@ -1317,10 +1322,10 @@
 
 	if (result) {
 		/* Set up access functions to use ECP+EPP hardware. */
-		parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
-		parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
-		parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
-		parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
+		pb->ops->epp_read_data = parport_pc_ecpepp_read_data;
+		pb->ops->epp_write_data = parport_pc_ecpepp_write_data;
+		pb->ops->epp_read_addr = parport_pc_ecpepp_read_addr;
+		pb->ops->epp_write_addr = parport_pc_ecpepp_write_addr;
 	}
 
 	return result;
@@ -1329,18 +1334,18 @@
 #else /* No IEEE 1284 support */
 
 /* Don't bother probing for modes we know we won't use. */
-static int __init parport_PS2_supported(struct parport *pb) { return 0; }
-static int __init parport_ECP_supported(struct parport *pb) { return 0; }
-static int __init parport_EPP_supported(struct parport *pb) { return 0; }
-static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
-static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
+static int __maybe_init parport_PS2_supported(struct parport *pb) { return 0; }
+static int __maybe_init parport_ECP_supported(struct parport *pb) { return 0; }
+static int __maybe_init parport_EPP_supported(struct parport *pb) { return 0; }
+static int __maybe_init parport_ECPEPP_supported(struct parport *pb){return 0;}
+static int __maybe_init parport_ECPPS2_supported(struct parport *pb){return 0;}
 
 #endif /* No IEEE 1284 support */
 
 /* --- IRQ detection -------------------------------------- */
 
 /* Only if supports ECP mode */
-static int __init programmable_irq_support(struct parport *pb)
+static int __maybe_init programmable_irq_support(struct parport *pb)
 {
 	int irq, intrLine;
 	unsigned char oecr = inb (ECONTROL (pb));
@@ -1357,7 +1362,7 @@
 	return irq;
 }
 
-static int __init irq_probe_ECP(struct parport *pb)
+static int __maybe_init irq_probe_ECP(struct parport *pb)
 {
 	int i;
 	unsigned long irqs;
@@ -1386,7 +1391,7 @@
  * This detection seems that only works in National Semiconductors
  * This doesn't work in SMC, LGS, and Winbond 
  */
-static int __init irq_probe_EPP(struct parport *pb)
+static int __maybe_init irq_probe_EPP(struct parport *pb)
 {
 #ifndef ADVANCED_DETECT
 	return PARPORT_IRQ_NONE;
@@ -1426,7 +1431,7 @@
 #endif /* Advanced detection */
 }
 
-static int __init irq_probe_SPP(struct parport *pb)
+static int __maybe_init irq_probe_SPP(struct parport *pb)
 {
 	/* Don't even try to do this. */
 	return PARPORT_IRQ_NONE;
@@ -1439,7 +1444,7 @@
  * When ECP is available we can autoprobe for IRQs.
  * NOTE: If we can autoprobe it, we can register the IRQ.
  */
-static int __init parport_irq_probe(struct parport *pb)
+static int __maybe_init parport_irq_probe(struct parport *pb)
 {
 	const struct parport_pc_private *priv = pb->private_data;
 
@@ -1473,7 +1478,7 @@
 /* --- DMA detection -------------------------------------- */
 
 /* Only if supports ECP mode */
-static int __init programmable_dma_support (struct parport *p)
+static int __maybe_init programmable_dma_support (struct parport *p)
 {
 	unsigned char oecr = inb (ECONTROL (p));
 	int dma;
@@ -1488,7 +1493,7 @@
 	return dma;
 }
 
-static int __init parport_dma_probe (struct parport *p)
+static int __maybe_init parport_dma_probe (struct parport *p)
 {
 	const struct parport_pc_private *priv = p->private_data;
 	if (priv->ecr)
@@ -1499,27 +1504,27 @@
 
 /* --- Initialisation code -------------------------------- */
 
-static int __init probe_one_port(unsigned long int base,
-				 unsigned long int base_hi,
-				 int irq, int dma)
+struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
+						    unsigned long int base_hi,
+						    int irq, int dma)
 {
 	struct parport_pc_private *priv;
 	struct parport_operations *ops;
 	struct parport tmp;
 	struct parport *p = &tmp;
 	int probedirq = PARPORT_IRQ_NONE;
-	if (check_region(base, 3)) return 0;
+	if (check_region(base, 3)) return NULL;
 	priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
 	if (!priv) {
 		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
-		return 0;
+		return NULL;
 	}
 	ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
 	if (!ops) {
 		printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
 			base);
 		kfree (priv);
-		return 0;
+		return NULL;
 	}
 	memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations));
 	priv->ctr = 0xc;
@@ -1531,7 +1536,7 @@
 	p->base_hi = base_hi;
 	p->irq = irq;
 	p->dma = dma;
-	p->modes = PARPORT_MODE_PCSPP;
+	p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
 	p->ops = ops;
 	p->private_data = priv;
 	p->physport = p;
@@ -1550,7 +1555,7 @@
 	if (!parport_SPP_supported (p)) {
 		/* No port. */
 		kfree (priv);
-		return 0;
+		return NULL;
 	}
 
 	parport_PS2_supported (p);
@@ -1559,7 +1564,7 @@
 					PARPORT_DMA_NONE, ops))) {
 		kfree (priv);
 		kfree (ops);
-		return 0;
+		return NULL;
 	}
 
 	p->base_hi = base_hi;
@@ -1591,21 +1596,22 @@
 	}
 	if (p->dma == PARPORT_DMA_AUTO)		
 		p->dma = PARPORT_DMA_NONE;
-	if (p->dma != PARPORT_DMA_NONE) 
-		printk(", dma %d", p->dma);
 
 #ifdef CONFIG_PARPORT_PC_FIFO
 	if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
-		parport_pc_ops.compat_write_data =
-			parport_pc_compat_write_block_pio;
+		p->ops->compat_write_data = parport_pc_compat_write_block_pio;
 #ifdef CONFIG_PARPORT_1284
-		parport_pc_ops.ecp_write_data =
-			parport_pc_ecp_write_block_pio;
+		p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
 #endif /* IEEE 1284 support */
-		if (p->dma != PARPORT_DMA_NONE)
+		if (p->dma != PARPORT_DMA_NONE) {
+			printk(", dma %d", p->dma);
 			p->modes |= PARPORT_MODE_DMA;
-		printk(", using FIFO");
+		}
+		else printk(", using FIFO");
 	}
+	else
+		/* We can't use the DMA channel after all. */
+		p->dma = PARPORT_DMA_NONE;
 #endif /* Allowed to use FIFO/DMA */
 
 	printk(" [");
@@ -1648,7 +1654,8 @@
 					p->name, p->dma);
 				p->dma = PARPORT_DMA_NONE;
 			} else {
-				priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
+				priv->dma_buf =
+					(char *)__get_dma_pages(GFP_KERNEL, 0);
 				if (! priv->dma_buf) {
 					printk (KERN_WARNING "%s: "
 						"cannot get buffer for DMA, "
@@ -1668,7 +1675,7 @@
 		/*
 		 * Put the ECP detected port in PS2 mode.
 		 */
-		outb (0x24, ECONTROL (p));
+		outb (0x34, ECONTROL (p));
 
 	parport_pc_write_data(p, 0);
 	parport_pc_data_forward (p);
@@ -1684,7 +1691,7 @@
 	   know about it. */
 	parport_announce_port (p);
 
-	return 1;
+	return p;
 }
 
 /* Look for PCI parallel port cards. */
@@ -1746,6 +1753,7 @@
 		{ 0, }
 	};
 
+	struct pci_dev *pcidev;
 	int count = 0;
 	int i;
 
@@ -1753,7 +1761,7 @@
 		return 0;
 
 	for (i = 0; cards[i].vendor; i++) {
-		struct pci_dev *pcidev = NULL;
+		pcidev = NULL;
 		while ((pcidev = pci_find_device (cards[i].vendor,
 						  cards[i].device,
 						  pcidev)) != NULL) {
@@ -1761,24 +1769,58 @@
 			for (n = 0; n < cards[i].numports; n++) {
 				unsigned long lo = cards[i].addr[n].lo;
 				unsigned long hi = cards[i].addr[n].hi;
-				unsigned long io_lo = pcidev->base_address[lo];
-				unsigned long io_hi = ((hi < 0) ? 0 :
-						pcidev->base_address[hi]);
-				io_lo &= PCI_BASE_ADDRESS_IO_MASK;
-				io_hi &= PCI_BASE_ADDRESS_IO_MASK;
-				if (irq == PARPORT_IRQ_AUTO)
-					count += probe_one_port (io_lo, io_hi,
-								 pcidev->irq,
-								 dma);
-				else
-					count += probe_one_port (io_lo, io_hi,
-								 irq, dma);
+				unsigned long io_lo, io_hi;
+				io_lo = pcidev->resource[lo].start;
+				io_hi = ((hi < 0) ? 0 :
+					 pcidev->resource[hi].start);
+				if (irq == PARPORT_IRQ_AUTO) {
+					if (parport_pc_probe_port (io_lo,
+								   io_hi,
+								   pcidev->irq,
+								   dma))
+						count++;
+				} else if (parport_pc_probe_port (io_lo, io_hi,
+								  irq, dma))
+					count++;
 			}
 		}
 	}
 
+	/* Look for parallel controllers that we don't know about. */
+	for (pcidev = pci_devices; pcidev; pcidev = pcidev->next) {
+		const int class_noprogif = pcidev->class & ~0xff;
+		if (class_noprogif != (PCI_CLASS_COMMUNICATION_PARALLEL << 8))
+			continue;
+
+		for (i = 0; cards[i].vendor; i++)
+			if ((cards[i].vendor == pcidev->vendor) &&
+			    (cards[i].device == pcidev->device))
+				break;
+		if (cards[i].vendor)
+			/* We know about this one. */
+			continue;
+
+		printk (KERN_INFO
+			"Unknown PCI parallel I/O card (%04x/%04x)\n"
+			"Please send 'lspci' output to "
+			"tim@cyberelk.demon.co.uk\n",
+			pcidev->vendor, pcidev->device);
+	}
+
 	return count;
 }
+
+/* Exported symbols. */
+#ifdef CONFIG_PARPORT_PC_PCMCIA
+
+/* parport_cs needs this in order to dyncamically get us to find ports. */
+EXPORT_SYMBOL (parport_pc_probe_port);
+
+#else
+
+EXPORT_NO_SYMBOLS;
+
+#endif
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
diff -u --recursive --new-file v2.3.12/linux/drivers/parport/share.c linux/drivers/parport/share.c
--- v2.3.12/linux/drivers/parport/share.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/parport/share.c	Thu Aug  5 14:23:14 1999
@@ -48,7 +48,6 @@
 static unsigned char dead_frob_lines (struct parport *p, unsigned char b,
 			     unsigned char c) { return 0; }
 static void dead_onearg (struct parport *p){}
-static void dead_irq (int i, void *p, struct pt_regs *r) { }
 static void dead_initstate (struct pardevice *d, struct parport_state *s) { }
 static void dead_state (struct parport *p, struct parport_state *s) { }
 static void dead_noargs (void) { }
@@ -67,7 +66,6 @@
 	dead_onearg,		/* disable_irq */
 	dead_onearg,		/* data_forward */
 	dead_onearg,		/* data_reverse */
-	dead_irq,
 	dead_initstate,		/* init_state */
 	dead_state,
 	dead_state,
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v2.3.12/linux/drivers/pci/Makefile	Tue Apr 28 22:41:33 1998
+++ linux/drivers/pci/Makefile	Thu Aug  5 18:44:28 1999
@@ -15,7 +15,7 @@
 ifeq ($(CONFIG_MODULES),y)
 O_TARGET = pci_syms.o
 OX_OBJS  = pcisyms.o
-O_OBJS   = pci.o
+O_OBJS   = pci.o names.o
 L_OBJS   := pci_syms.o
 else
 L_OBJS   := pci.o
@@ -23,9 +23,6 @@
 
 ifdef CONFIG_PROC_FS
 L_OBJS   += proc.o
-ifdef CONFIG_PCI_OLD_PROC
-L_OBJS   += oldproc.o
-endif
 endif
 
 ifdef CONFIG_PCI_QUIRKS
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/devlist.h linux/drivers/pci/devlist.h
--- v2.3.12/linux/drivers/pci/devlist.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/devlist.h	Thu Aug  5 18:44:28 1999
@@ -0,0 +1,962 @@
+VENDOR( COMPAQ, "Compaq" )
+	DEVICE( COMPAQ,		COMPAQ_1280,	"QVision 1280/p")
+	DEVICE( COMPAQ,		COMPAQ_SMART2P,	"Smart-2/P RAID Controller")
+	DEVICE( COMPAQ,		COMPAQ_NETEL100,"Netelligent 10/100")
+	DEVICE( COMPAQ,		COMPAQ_NETEL10,	"Netelligent 10")
+	DEVICE( COMPAQ,		COMPAQ_NETFLEX3I,"NetFlex 3")
+	DEVICE( COMPAQ,		COMPAQ_NETEL100D,"Netelligent 10/100 Dual")
+	DEVICE( COMPAQ,		COMPAQ_NETEL100PI,"Netelligent 10/100 ProLiant")
+	DEVICE( COMPAQ,		COMPAQ_NETEL100I,"Netelligent 10/100 Integrated")
+	DEVICE( COMPAQ,		COMPAQ_THUNDER,	"ThunderLAN")
+	DEVICE( COMPAQ,		COMPAQ_NETFLEX3B,"NetFlex 3 BNC")
+ENDVENDOR()
+
+VENDOR( NCR, "NCR" )
+	DEVICE( NCR,		NCR_53C810,	"53c810")
+	DEVICE( NCR,		NCR_53C820,	"53c820")
+	DEVICE( NCR,		NCR_53C825,	"53c825")
+	DEVICE( NCR,		NCR_53C815,	"53c815")
+	DEVICE( NCR,		NCR_53C860,	"53c860")
+	DEVICE( NCR,		NCR_53C896,	"53c896")
+	DEVICE( NCR,		NCR_53C895,	"53c895")
+	DEVICE( NCR,		NCR_53C885,	"53c885")
+	DEVICE( NCR,		NCR_53C875,	"53c875")
+	DEVICE( NCR,		NCR_53C875J,	"53c875J")
+ENDVENDOR()
+
+VENDOR( ATI, "ATI" )
+	DEVICE( ATI,		ATI_68800,      "68800AX")
+	DEVICE( ATI,		ATI_215CT222,   "215CT222")
+	DEVICE( ATI,		ATI_210888CX,   "210888CX")
+	DEVICE( ATI,		ATI_215GB,	"Mach64 GB")
+	DEVICE( ATI,		ATI_215GD,	"Mach64 GD (Rage Pro)")
+	DEVICE( ATI,		ATI_215GI,	"Mach64 GI (Rage Pro)")
+	DEVICE( ATI,		ATI_215GP,	"Mach64 GP (Rage Pro)")
+	DEVICE( ATI,		ATI_215GQ,	"Mach64 GQ (Rage Pro)")
+	DEVICE( ATI,		ATI_215GT,	"Mach64 GT (Rage II)")
+	DEVICE( ATI,		ATI_215GTB,	"Mach64 GTB (Rage II)")
+	DEVICE( ATI,		ATI_210888GX,   "210888GX")
+	DEVICE( ATI,		ATI_215LG,	"Mach64 LG (Rage Pro)")
+	DEVICE( ATI,		ATI_264LT,	"Mach64 LT")
+	DEVICE( ATI,		ATI_264VT,	"Mach64 VT")
+ENDVENDOR()
+
+VENDOR( VLSI, "VLSI" )
+	DEVICE( VLSI,		VLSI_82C592,	"82C592-FC1")
+	DEVICE( VLSI,		VLSI_82C593,	"82C593-FC1")
+	DEVICE( VLSI,		VLSI_82C594,	"82C594-AFC2")
+	DEVICE( VLSI,		VLSI_82C597,	"82C597-AFC2")
+	DEVICE( VLSI,		VLSI_82C541,	"82C541 Lynx")
+	DEVICE( VLSI,		VLSI_82C543,	"82C543 Lynx ISA")
+	DEVICE( VLSI,		VLSI_82C532,	"82C532")
+	DEVICE( VLSI,		VLSI_82C534,	"82C534")
+	DEVICE( VLSI,		VLSI_82C535,	"82C535")
+	DEVICE( VLSI,		VLSI_82C147,	"82C147")
+	DEVICE( VLSI,		VLSI_VAS96011,	"VAS96011 (Golden Gate II)")
+ENDVENDOR()
+
+VENDOR( ADL, "Avance Logic" )
+	DEVICE( ADL,		ADL_2301,	"2301")
+ENDVENDOR()
+
+VENDOR( NS, "NS" )
+	DEVICE( NS,		NS_87415,	"87415")
+	DEVICE( NS,		NS_87410,	"87410")
+ENDVENDOR()
+
+VENDOR( TSENG, "Tseng'Lab" )
+	DEVICE( TSENG,		TSENG_W32P_2,	"ET4000W32P")
+	DEVICE( TSENG,		TSENG_W32P_b,	"ET4000W32P rev B")
+	DEVICE( TSENG,		TSENG_W32P_c,	"ET4000W32P rev C")
+	DEVICE( TSENG,		TSENG_W32P_d,	"ET4000W32P rev D")
+	DEVICE( TSENG,		TSENG_ET6000,	"ET6000")
+ENDVENDOR()
+
+VENDOR( WEITEK, "Weitek" )
+	DEVICE( WEITEK,		WEITEK_P9000,	"P9000")
+	DEVICE( WEITEK,		WEITEK_P9100,	"P9100")
+ENDVENDOR()
+
+VENDOR( DEC, "DEC" )
+	DEVICE( DEC,		DEC_BRD,	"DC21050")
+	DEVICE( DEC,		DEC_TULIP,	"DC21040")
+	DEVICE( DEC,		DEC_TGA,	"TGA")
+	DEVICE( DEC,		DEC_TULIP_FAST,	"DC21140")
+	DEVICE( DEC,		DEC_TGA2,	"TGA2")
+	DEVICE( DEC,		DEC_FDDI,	"DEFPA")
+	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041")
+	DEVICE( DEC,		DEC_21142,	"DC21142")
+	DEVICE( DEC,		DEC_21052,	"DC21052")
+	DEVICE( DEC,		DEC_21150,	"DC21150")
+	DEVICE( DEC,		DEC_21152,	"DC21152")
+	DEVICE( DEC,		DEC_21153,	"DC21153")
+	DEVICE( DEC,		DEC_21154,	"DC21154")
+ENDVENDOR()
+
+VENDOR( CIRRUS, "Cirrus Logic" )
+	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548")
+	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430")
+	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434")
+	DEVICE( CIRRUS,		CIRRUS_5434_8,	"GD 5434")
+	DEVICE( CIRRUS,		CIRRUS_5436,	"GD 5436")
+	DEVICE( CIRRUS,		CIRRUS_5446,	"GD 5446")
+	DEVICE( CIRRUS,		CIRRUS_5480,	"GD 5480")
+	DEVICE( CIRRUS,		CIRRUS_5464,	"GD 5464")
+	DEVICE( CIRRUS,		CIRRUS_5465,	"GD 5465")
+	DEVICE( CIRRUS,		CIRRUS_6729,	"CL 6729")
+	DEVICE( CIRRUS,		CIRRUS_6832,	"PD 6832")
+	DEVICE( CIRRUS,		CIRRUS_7542,	"CL 7542")
+	DEVICE( CIRRUS,		CIRRUS_7543,	"CL 7543")
+	DEVICE( CIRRUS,		CIRRUS_7541,	"CL 7541")
+ENDVENDOR()
+
+VENDOR( IBM, "IBM" )
+	DEVICE( IBM,		IBM_FIRE_CORAL,	"Fire Coral")
+	DEVICE( IBM,		IBM_TR,		"Token Ring")
+	DEVICE( IBM,		IBM_82G2675,	"82G2675")
+	DEVICE( IBM,		IBM_MCA,	"MicroChannel")
+	DEVICE( IBM,		IBM_82351,	"82351")
+	DEVICE( IBM,		IBM_PYTHON,	"Python")
+	DEVICE( IBM,		IBM_SERVERAID,	"ServeRAID")
+	DEVICE( IBM,		IBM_TR_WAKE,	"Wake On LAN Token Ring")
+	DEVICE( IBM,		IBM_MPIC,	"MPIC-2 Interrupt Controller")
+	DEVICE( IBM,		IBM_3780IDSP,	"MWave DSP")
+	DEVICE( IBM,		IBM_MPIC_2,	"MPIC-2 ASIC Interrupt Controller")
+ENDVENDOR()
+
+VENDOR( WD, "Western Digital" )
+	DEVICE( WD,		WD_7197,	"WD 7197")
+ENDVENDOR()
+
+VENDOR( AMD, "AMD" )
+	DEVICE( AMD,		AMD_LANCE,	"79C970")
+	DEVICE( AMD,		AMD_SCSI,	"53C974")
+ENDVENDOR()
+
+VENDOR( TRIDENT, "Trident" )
+	DEVICE( TRIDENT,	TRIDENT_9397,	"Cyber9397")
+	DEVICE( TRIDENT,	TRIDENT_9420,	"TG 9420")
+	DEVICE( TRIDENT,	TRIDENT_9440,	"TG 9440")
+	DEVICE( TRIDENT,	TRIDENT_9660,	"TG 9660 / Cyber9385")
+	DEVICE( TRIDENT,	TRIDENT_9750,	"Image 975")
+ENDVENDOR()
+
+VENDOR( AI, "Acer Incorporated" )
+	DEVICE( AI,		AI_M1435,	"M1435")
+ENDVENDOR()
+
+VENDOR( MATROX, "Matrox" )
+	DEVICE( MATROX,		MATROX_MGA_2,	"Atlas PX2085")
+	DEVICE( MATROX,		MATROX_MIL,	"Millennium")
+	DEVICE( MATROX,		MATROX_MYS,	"Mystique")
+	DEVICE( MATROX,		MATROX_MIL_2,	"Millennium II")
+	DEVICE( MATROX,		MATROX_MIL_2_AGP,"Millennium II AGP")
+	DEVICE( MATROX,         MATROX_G200_PCI,"G200 PCI")
+	DEVICE( MATROX,         MATROX_G200_AGP,"G200 AGP")
+	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression")
+	DEVICE( MATROX,         MATROX_G100_MM, "G100 multi monitor")
+	DEVICE( MATROX,         MATROX_G100_AGP,"G100 AGP")
+ENDVENDOR()
+
+VENDOR( CT, "Chips & Technologies" )
+	DEVICE( CT,		CT_65545,	"65545")
+	DEVICE( CT,		CT_65548,	"65548")
+	DEVICE(	CT,		CT_65550,	"65550")
+	DEVICE( CT,		CT_65554,	"65554")
+	DEVICE( CT,		CT_65555,	"65555")
+ENDVENDOR()
+
+VENDOR( MIRO, "Miro" )
+	DEVICE( MIRO,		MIRO_36050,	"ZR36050")
+ENDVENDOR()
+
+VENDOR( NEC, "NEC" )
+	DEVICE( NEC,		NEC_PCX2,	"PowerVR PCX2")
+ENDVENDOR()
+
+VENDOR( FD, "Future Domain" )
+	DEVICE( FD,		FD_36C70,	"TMC-18C30")
+ENDVENDOR()
+
+VENDOR( SI, "Silicon Integrated Systems" )
+	DEVICE( SI,		SI_5591_AGP,	"5591/5592 AGP")
+	DEVICE( SI,		SI_6202,	"6202")
+	DEVICE( SI,		SI_503,		"85C503")
+	DEVICE( SI,		SI_ACPI,	"ACPI")
+	DEVICE( SI,		SI_5597_VGA,	"5597/5598 VGA")
+	DEVICE( SI,		SI_6205,	"6205")
+	DEVICE( SI,		SI_501,		"85C501")
+	DEVICE( SI,		SI_496,		"85C496")
+	DEVICE( SI,		SI_601,		"85C601")
+	DEVICE( SI,		SI_5107,	"5107")
+	DEVICE( SI,		SI_5511,       	"85C5511")
+	DEVICE( SI,		SI_5513,	"85C5513")
+	DEVICE( SI,		SI_5571,	"5571")
+	DEVICE( SI,		SI_5591,	"5591/5592 Host")
+	DEVICE( SI,		SI_5597,	"5597/5598 Host")
+	DEVICE( SI,		SI_7001,	"7001 USB")
+ENDVENDOR()
+
+VENDOR( HP, "Hewlett Packard" )
+	DEVICE( HP,		HP_J2585A,	"J2585A")
+	DEVICE( HP,		HP_J2585B,	"J2585B (Lassen)")
+ENDVENDOR()
+
+VENDOR( PCTECH, "PCTECH" )
+	DEVICE( PCTECH,		PCTECH_RZ1000,  "RZ1000 (buggy)")
+	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)")
+	DEVICE( PCTECH,		PCTECH_SAMURAI_0,"Samurai 0")
+	DEVICE( PCTECH,		PCTECH_SAMURAI_1,"Samurai 1")
+	DEVICE( PCTECH,		PCTECH_SAMURAI_IDE,"Samurai IDE")
+ENDVENDOR()
+
+VENDOR( DPT, "DPT" )
+	DEVICE( DPT,		DPT,		"SmartCache/Raid")
+ENDVENDOR()
+
+VENDOR( OPTI, "OPTi" )
+	DEVICE( OPTI,		OPTI_92C178,	"92C178")
+	DEVICE( OPTI,		OPTI_82C557,	"82C557 Viper-M")
+	DEVICE( OPTI,		OPTI_82C558,	"82C558 Viper-M ISA+IDE")
+	DEVICE( OPTI,		OPTI_82C621,	"82C621")
+	DEVICE( OPTI,		OPTI_82C700,	"82C700")
+	DEVICE( OPTI,		OPTI_82C701,	"82C701 FireStar Plus")
+	DEVICE( OPTI,		OPTI_82C814,	"82C814 Firebridge 1")
+	DEVICE( OPTI,		OPTI_82C822,	"82C822")
+	DEVICE( OPTI,		OPTI_82C825,	"82C825 Firebridge 2")
+ENDVENDOR()
+
+VENDOR( SGS, "SGS Thomson" )
+	DEVICE( SGS,		SGS_2000,	"STG 2000X")
+	DEVICE( SGS,		SGS_1764,	"STG 1764X")
+ENDVENDOR()
+
+VENDOR( BUSLOGIC, "BusLogic" )
+	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC")
+	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER,    "MultiMaster")
+	DEVICE( BUSLOGIC,	BUSLOGIC_FLASHPOINT,     "FlashPoint")
+ENDVENDOR()
+
+VENDOR( TI, "Texas Instruments" )
+	DEVICE( TI,		TI_TVP4010,	"TVP4010 Permedia")
+	DEVICE( TI,		TI_TVP4020,	"TVP4020 Permedia 2")
+	DEVICE( TI,		TI_PCI1130,	"PCI1130")
+	DEVICE( TI,		TI_PCI1131,	"PCI1131")
+	DEVICE( TI,		TI_PCI1250,	"PCI1250")
+ENDVENDOR()
+
+VENDOR( OAK, "OAK" )
+	DEVICE( OAK,		OAK_OTI107,	"OTI107")
+ENDVENDOR()
+
+VENDOR( WINBOND2, "Winbond" )
+	DEVICE( WINBOND2,	WINBOND2_89C940,"NE2000-PCI")
+ENDVENDOR()
+
+VENDOR( MOTOROLA, "Motorola" )
+	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle")
+	DEVICE( MOTOROLA,	MOTOROLA_MPC106,"MPC106 Grackle")
+	DEVICE( MOTOROLA,	MOTOROLA_RAVEN,	"Raven")
+	DEVICE( MOTOROLA,	MOTOROLA_FALCON,"Falcon")
+	DEVICE( MOTOROLA,	MOTOROLA_CPX8216,"CPX8216")
+ENDVENDOR()
+
+VENDOR( PROMISE, "Promise Technology" )
+	DEVICE( PROMISE,        PROMISE_20246,	"IDE UltraDMA/33")
+	DEVICE(	PROMISE,	PROMISE_20262,	"IDE UltraDMA/66")
+	DEVICE( PROMISE,	PROMISE_5300,	"DC5030")
+ENDVENDOR()
+
+VENDOR( N9, "Number Nine" )
+	DEVICE( N9,		N9_I128,	"Imagine 128")
+	DEVICE( N9,		N9_I128_2,	"Imagine 128v2")
+	DEVICE( N9,		N9_I128_T2R,	"Revolution 3D")
+ENDVENDOR()
+
+VENDOR( UMC, "UMC" )
+	DEVICE( UMC,		UMC_UM8673F,	"UM8673F")
+	DEVICE( UMC,		UMC_UM8891A,	"UM8891A")
+	DEVICE( UMC,		UMC_UM8886BF,	"UM8886BF")
+	DEVICE( UMC,		UMC_UM8886A,	"UM8886A")
+	DEVICE( UMC,		UMC_UM8881F,	"UM8881F")
+	DEVICE( UMC,		UMC_UM8886F,	"UM8886F")
+	DEVICE( UMC,		UMC_UM9017F,	"UM9017F")
+	DEVICE( UMC,		UMC_UM8886N,	"UM8886N")
+	DEVICE( UMC,		UMC_UM8891N,	"UM8891N")
+ENDVENDOR()
+
+VENDOR( X, "X Technology" )
+	DEVICE( X,		X_AGX016,	"ITT AGX016")
+ENDVENDOR()
+
+VENDOR( PICOP, "PicoPower" )
+	DEVICE( PICOP,		PICOP_PT86C52X,	"PT86C52x Vesuvius")
+	DEVICE( PICOP,		PICOP_PT80C524,	"PT80C524 Nile")
+ENDVENDOR()
+
+VENDOR( APPLE, "Apple" )
+	DEVICE( APPLE,		APPLE_BANDIT,	"Bandit")
+	DEVICE( APPLE,		APPLE_GC,	"Grand Central")
+	DEVICE( APPLE,		APPLE_HYDRA,	"Hydra")
+ENDVENDOR()
+
+VENDOR( NEXGEN, "Nexgen" )
+	DEVICE( NEXGEN,		NEXGEN_82C501,	"82C501")
+ENDVENDOR()
+
+VENDOR( QLOGIC, "Q Logic" )
+	DEVICE( QLOGIC,		QLOGIC_ISP1020,	"ISP1020")
+	DEVICE( QLOGIC,		QLOGIC_ISP1022,	"ISP1022")
+ENDVENDOR()
+
+VENDOR( CYRIX, "Cyrix" )
+	DEVICE( CYRIX,		CYRIX_5510,	"5510")
+	DEVICE( CYRIX,		CYRIX_PCI_MASTER,"PCI Master")
+	DEVICE( CYRIX,		CYRIX_5520,	"5520")
+	DEVICE( CYRIX,		CYRIX_5530_LEGACY,"5530 Kahlua Legacy")
+	DEVICE( CYRIX,		CYRIX_5530_SMI,	"5530 Kahlua SMI")
+	DEVICE( CYRIX,		CYRIX_5530_IDE,	"5530 Kahlua IDE")
+	DEVICE( CYRIX,		CYRIX_5530_AUDIO,"5530 Kahlua Audio")
+	DEVICE( CYRIX,		CYRIX_5530_VIDEO,"5530 Kahlua Video")
+ENDVENDOR()
+
+VENDOR( LEADTEK, "Leadtek Research" )
+	DEVICE( LEADTEK,	LEADTEK_805,	"S3 805")
+ENDVENDOR()
+
+VENDOR( CONTAQ, "Contaq" )
+	DEVICE( CONTAQ,		CONTAQ_82C599,	"82C599")
+	DEVICE( CONTAQ,		CONTAQ_82C693,	"82C693")
+ENDVENDOR()
+
+VENDOR( FOREX, "Forex" )
+ENDVENDOR()
+
+VENDOR( OLICOM, "Olicom" )
+	DEVICE( OLICOM,		OLICOM_OC3136,	"OC-3136/3137")
+	DEVICE( OLICOM,		OLICOM_OC2315,	"OC-2315")
+	DEVICE( OLICOM,		OLICOM_OC2325,	"OC-2325")
+	DEVICE( OLICOM,		OLICOM_OC2183,	"OC-2183/2185")
+	DEVICE( OLICOM,		OLICOM_OC2326,	"OC-2326")
+	DEVICE( OLICOM,		OLICOM_OC6151,	"OC-6151/6152")
+ENDVENDOR()
+
+VENDOR( SUN, "Sun Microsystems" )
+	DEVICE( SUN,		SUN_EBUS,	"PCI-EBus Bridge")
+	DEVICE( SUN,		SUN_HAPPYMEAL,	"Happy Meal Ethernet")
+	DEVICE( SUN,		SUN_SIMBA,	"Advanced PCI Bridge")
+	DEVICE( SUN,		SUN_PBM,	"PCI Bus Module")
+	DEVICE( SUN,		SUN_SABRE,	"Ultra IIi PCI")
+ENDVENDOR()
+
+VENDOR( CMD, "CMD" )
+	DEVICE( CMD,		CMD_640,	"640 (buggy)")
+	DEVICE( CMD,		CMD_643,	"643")
+	DEVICE( CMD,		CMD_646,	"646")
+	DEVICE( CMD,		CMD_670,	"670")
+ENDVENDOR()
+
+VENDOR( VISION, "Vision" )
+	DEVICE( VISION,		VISION_QD8500,	"QD-8500")
+	DEVICE( VISION,		VISION_QD8580,	"QD-8580")
+ENDVENDOR()
+
+VENDOR( BROOKTREE, "Brooktree" )
+	DEVICE( BROOKTREE,	BROOKTREE_848,	"Bt848")
+	DEVICE( BROOKTREE,	BROOKTREE_849A,	"Bt849")
+	DEVICE( BROOKTREE,      BROOKTREE_878_1,"Bt878 2nd Contr. (?)")
+	DEVICE( BROOKTREE,      BROOKTREE_878,  "Bt878")
+	DEVICE( BROOKTREE,	BROOKTREE_8474,	"Bt8474")
+ENDVENDOR()
+
+VENDOR( SIERRA, "Sierra" )
+	DEVICE( SIERRA,		SIERRA_STB,	"STB Horizon 64")
+ENDVENDOR()
+
+VENDOR( SGI, "Silicon Graphics Inc" )
+	DEVICE( SGI,		SGI_IOC3,	"IOC3")
+ENDVENDOR()
+
+VENDOR( ACC, "ACC MICROELECTRONICS" )
+	DEVICE( ACC,		ACC_2056,	"2056")
+ENDVENDOR()
+
+VENDOR( WINBOND, "Winbond" )
+	DEVICE( WINBOND,	WINBOND_83769,	"W83769F")
+	DEVICE( WINBOND,	WINBOND_82C105,	"SL82C105")
+	DEVICE( WINBOND,	WINBOND_83C553,	"W83C553")
+ENDVENDOR()
+
+VENDOR( DATABOOK, "Databook" )
+	DEVICE( DATABOOK,      	DATABOOK_87144,	"DB87144")
+ENDVENDOR()
+
+VENDOR( PLX, "PLX" )
+	DEVICE(	PLX,		PLX_9050,	"PCI9050 I2O")
+	DEVICE( PLX,		PLX_9080,	"PCI9080 I2O")
+ENDVENDOR()
+
+VENDOR( MADGE, "Madge Networks" )
+	DEVICE( MADGE,		MADGE_MK2,	"Smart 16/4 BM Mk2 Ringnode")
+	DEVICE( MADGE,		MADGE_C155S,	"Collage 155 Server")
+ENDVENDOR()
+
+VENDOR( 3COM, "3Com" )
+	DEVICE( 3COM,		3COM_3C339,	"3C339 TokenRing")
+	DEVICE( 3COM,		3COM_3C590,	"3C590 10bT")
+	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX")
+	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4")
+	DEVICE( 3COM,		3COM_3C595MII,	"3C595 100b-MII")
+	DEVICE( 3COM,		3COM_3C900TPO,	"3C900 10bTPO")
+	DEVICE( 3COM,		3COM_3C900COMBO,"3C900 10b Combo")
+	DEVICE( 3COM,		3COM_3C905TX,	"3C905 100bTX")
+	DEVICE( 3COM,		3COM_3C905T4,	"3C905 100bT4")
+	DEVICE( 3COM,		3COM_3C905B_TX,	"3C905B 100bTX")
+ENDVENDOR()
+
+VENDOR( SMC, "SMC" )
+	DEVICE( SMC,		SMC_EPIC100,	"9432 TX")
+ENDVENDOR()
+
+VENDOR( AL, "Acer Labs" )
+	DEVICE( AL,		AL_M1445,	"M1445")
+	DEVICE( AL,		AL_M1449,	"M1449")
+	DEVICE( AL,		AL_M1451,	"M1451")
+	DEVICE( AL,		AL_M1461,	"M1461")
+	DEVICE( AL,		AL_M1489,	"M1489")
+	DEVICE( AL,		AL_M1511,	"M1511")
+	DEVICE( AL,		AL_M1513,	"M1513")
+	DEVICE( AL,		AL_M1521,	"M1521")
+	DEVICE( AL,		AL_M1523,	"M1523")
+	DEVICE( AL,		AL_M1531,	"M1531 Aladdin IV")
+	DEVICE( AL,		AL_M1533,	"M1533 Aladdin IV")
+	DEVICE(	AL,		AL_M1541,	"M1541 Aladdin V")
+	DEVICE(	AL,		AL_M1543,	"M1543 Aladdin V")
+	DEVICE( AL,		AL_M3307,	"M3307 MPEG-1 decoder")
+	DEVICE( AL,		AL_M4803,	"M4803")
+	DEVICE( AL,		AL_M5219,	"M5219")
+	DEVICE( AL,		AL_M5229,	"M5229 TXpro")
+	DEVICE( AL,		AL_M5237,	"M5237 USB")
+	DEVICE(	AL,		AL_M5243,	"M5243 AGP")
+	DEVICE(	AL,		AL_M7101,	"M7101 PMU")
+ENDVENDOR()
+
+VENDOR( MITSUBISHI, "Mitsubishi" )
+ENDVENDOR()
+
+VENDOR( SURECOM, "Surecom" )
+	DEVICE( SURECOM,	SURECOM_NE34,	"NE-34PCI LAN")
+ENDVENDOR()
+
+VENDOR( NEOMAGIC, "Neomagic" )
+	DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070")
+	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V")
+	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV")
+	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160")
+	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+")
+ENDVENDOR()
+
+VENDOR( ASP, "Advanced System Products" )
+	DEVICE( ASP,		ASP_ABP940,	"ABP940")
+	DEVICE( ASP,		ASP_ABP940U,	"ABP940U")
+	DEVICE( ASP,		ASP_ABP940UW,	"ABP940UW")
+ENDVENDOR()
+
+VENDOR( MACRONIX, "Macronix" )
+	DEVICE( MACRONIX,	MACRONIX_MX98713,"MX98713")
+	DEVICE( MACRONIX,	MACRONIX_MX987x5,"MX98715 / MX98725")
+ENDVENDOR()
+
+VENDOR( CERN, "CERN" )
+	DEVICE( CERN,		CERN_SPSB_PMC,	"STAR/RD24 SCI-PCI (PMC)")
+	DEVICE( CERN,		CERN_SPSB_PCI,	"STAR/RD24 SCI-PCI (PMC)")
+	DEVICE( CERN,		CERN_HIPPI_DST,	"HIPPI destination")
+	DEVICE( CERN,		CERN_HIPPI_SRC,	"HIPPI source")
+ENDVENDOR()
+
+VENDOR( NVIDIA, "NVidia" )
+ENDVENDOR()
+
+VENDOR( IMS, "IMS" )
+	DEVICE( IMS,		IMS_8849,	"8849")
+ENDVENDOR()
+
+VENDOR( TEKRAM2, "Tekram" )
+	DEVICE( TEKRAM2,	TEKRAM2_690c,	"DC690c")
+ENDVENDOR()
+
+VENDOR( TUNDRA, "Tundra" )
+	DEVICE( TUNDRA,		TUNDRA_CA91C042,"CA91C042 Universe")
+ENDVENDOR()
+
+VENDOR( AMCC, "AMCC" )
+	DEVICE( AMCC,		AMCC_MYRINET,	"Myrinet PCI (M2-PCI-32)")
+	DEVICE( AMCC,		AMCC_PARASTATION,"ParaStation Interface")
+	DEVICE( AMCC,		AMCC_S5933,	"S5933 PCI44")
+	DEVICE( AMCC,		AMCC_S5933_HEPC3,"S5933 Traquair HEPC3")
+ENDVENDOR()
+
+VENDOR( INTERG, "Intergraphics" )
+	DEVICE( INTERG,		INTERG_1680,	"IGA-1680")
+	DEVICE( INTERG,         INTERG_1682,    "IGA-1682")
+ENDVENDOR()
+
+VENDOR( REALTEK, "Realtek" )
+	DEVICE( REALTEK,	REALTEK_8029,	"8029")
+	DEVICE( REALTEK,	REALTEK_8129,	"8129")
+	DEVICE( REALTEK,	REALTEK_8139,	"8139")
+ENDVENDOR()
+
+VENDOR( TRUEVISION, "Truevision" )
+	DEVICE( TRUEVISION,	TRUEVISION_T1000,"TARGA 1000")
+ENDVENDOR()
+
+VENDOR( INIT, "Initio Corp" )
+	DEVICE( INIT,		INIT_320P,	"320 P")
+	DEVICE( INIT,		INIT_360P,	"360 P")
+ENDVENDOR()
+
+VENDOR( TTI, "Triones Technologies, Inc." )
+	DEVICE(	TTI,		TTI_HPT343,	"HPT343")
+ENDVENDOR()
+
+VENDOR( VIA, "VIA Technologies" )
+	DEVICE( VIA,		VIA_82C505,	"VT 82C505")
+	DEVICE( VIA,		VIA_82C561,	"VT 82C561")
+	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo IDE")
+	DEVICE( VIA,		VIA_82C576,	"VT 82C576 3V")
+	DEVICE( VIA,		VIA_82C585,	"VT 82C585 Apollo VP1/VPX")
+	DEVICE( VIA,		VIA_82C586_0,	"VT 82C586 Apollo ISA")
+	DEVICE( VIA,		VIA_82C595,	"VT 82C595 Apollo VP2")
+	DEVICE( VIA,		VIA_82C597_0,	"VT 82C597 Apollo VP3")
+	DEVICE( VIA,		VIA_82C598_0,	"VT 82C598 Apollo MVP3")
+	DEVICE( VIA,		VIA_82C926,	"VT 82C926 Amazon")
+	DEVICE( VIA,		VIA_82C416,	"VT 82C416MV")
+	DEVICE( VIA,		VIA_82C595_97,	"VT 82C595 Apollo VP2/97")
+	DEVICE( VIA,		VIA_82C586_2,	"VT 82C586 Apollo USB")
+	DEVICE( VIA,		VIA_82C586_3,	"VT 82C586B Apollo ACPI")
+	DEVICE( VIA,		VIA_86C100A,	"VT 86C100A")
+	DEVICE( VIA,		VIA_82C597_1,	"VT 82C597 Apollo VP3 AGP")
+	DEVICE( VIA,		VIA_82C598_1,	"VT 82C598 Apollo MVP3 AGP")
+ENDVENDOR()
+
+VENDOR( SMC2, "SMC" )
+	DEVICE( SMC2,		SMC2_1211TX,	"1211 TX")
+ENDVENDOR()
+
+VENDOR( VORTEX, "VORTEX" )
+	DEVICE( VORTEX,		VORTEX_GDT60x0,	"GDT 60x0")
+	DEVICE( VORTEX,		VORTEX_GDT6000B,"GDT 6000b")
+	DEVICE( VORTEX,		VORTEX_GDT6x10,	"GDT 6110/6510")
+	DEVICE( VORTEX,		VORTEX_GDT6x20,	"GDT 6120/6520")
+	DEVICE( VORTEX,		VORTEX_GDT6530,	"GDT 6530")
+	DEVICE( VORTEX,		VORTEX_GDT6550,	"GDT 6550")
+	DEVICE( VORTEX,		VORTEX_GDT6x17,	"GDT 6117/6517")
+	DEVICE( VORTEX,		VORTEX_GDT6x27,	"GDT 6127/6527")
+	DEVICE( VORTEX,		VORTEX_GDT6537,	"GDT 6537")
+	DEVICE( VORTEX,		VORTEX_GDT6557,	"GDT 6557")
+	DEVICE( VORTEX,		VORTEX_GDT6x15,	"GDT 6115/6515")
+	DEVICE( VORTEX,		VORTEX_GDT6x25,	"GDT 6125/6525")
+	DEVICE( VORTEX,		VORTEX_GDT6535,	"GDT 6535")
+	DEVICE( VORTEX,		VORTEX_GDT6555,	"GDT 6555")
+	DEVICE( VORTEX,		VORTEX_GDT6x17RP,"GDT 6117RP/6517RP")
+	DEVICE( VORTEX,		VORTEX_GDT6x27RP,"GDT 6127RP/6527RP")
+	DEVICE( VORTEX,		VORTEX_GDT6537RP,"GDT 6537RP")
+	DEVICE( VORTEX,		VORTEX_GDT6557RP,"GDT 6557RP")
+	DEVICE( VORTEX,		VORTEX_GDT6x11RP,"GDT 6111RP/6511RP")
+	DEVICE( VORTEX,		VORTEX_GDT6x21RP,"GDT 6121RP/6521RP")
+	DEVICE( VORTEX,		VORTEX_GDT6x17RP1,"GDT 6117RP1/6517RP1")
+	DEVICE( VORTEX,		VORTEX_GDT6x27RP1,"GDT 6127RP1/6527RP1")
+	DEVICE( VORTEX,		VORTEX_GDT6537RP1,"GDT 6537RP1")
+	DEVICE( VORTEX,		VORTEX_GDT6557RP1,"GDT 6557RP1")
+	DEVICE( VORTEX,		VORTEX_GDT6x11RP1,"GDT 6111RP1/6511RP1")
+	DEVICE( VORTEX,		VORTEX_GDT6x21RP1,"GDT 6121RP1/6521RP1")
+	DEVICE( VORTEX,		VORTEX_GDT6x17RP2,"GDT 6117RP2/6517RP2")
+	DEVICE( VORTEX,		VORTEX_GDT6x27RP2,"GDT 6127RP2/6527RP2")
+	DEVICE( VORTEX,		VORTEX_GDT6537RP2,"GDT 6537RP2")
+	DEVICE( VORTEX,		VORTEX_GDT6557RP2,"GDT 6557RP2")
+	DEVICE( VORTEX,		VORTEX_GDT6x11RP2,"GDT 6111RP2/6511RP2")
+	DEVICE( VORTEX,		VORTEX_GDT6x21RP2,"GDT 6121RP2/6521RP2")
+ENDVENDOR()
+
+VENDOR( EF, "Efficient Networks" )
+	DEVICE( EF,		EF_ATM_FPGA,   	"155P-MF1 (FPGA)")
+	DEVICE( EF,		EF_ATM_ASIC,    "155P-MF1 (ASIC)")
+ENDVENDOR()
+
+VENDOR( FORE, "Fore Systems" )
+	DEVICE( FORE,		FORE_PCA200PC,  "PCA-200PC")
+	DEVICE( FORE,		FORE_PCA200E,	 "PCA-200E")
+ENDVENDOR()
+
+VENDOR( IMAGINGTECH, "Imaging Technology" )
+	DEVICE( IMAGINGTECH,	IMAGINGTECH_ICPCI, "MVC IC-PCI")
+ENDVENDOR()
+
+VENDOR( PHILIPS, "Philips" )
+	DEVICE( PHILIPS,	PHILIPS_SAA7145,"SAA7145")
+	DEVICE( PHILIPS,	PHILIPS_SAA7146,"SAA7146")
+ENDVENDOR()
+
+VENDOR( CYCLONE, "Cyclone" )
+	DEVICE( CYCLONE,	CYCLONE_SDK,	"SDK")
+ENDVENDOR()
+
+VENDOR( ALLIANCE, "Alliance" )
+	DEVICE( ALLIANCE,	ALLIANCE_PROMOTIO, "Promotion-6410")
+	DEVICE( ALLIANCE,	ALLIANCE_PROVIDEO, "Provideo")
+	DEVICE( ALLIANCE,	ALLIANCE_AT24,	"AT24")
+	DEVICE( ALLIANCE,	ALLIANCE_AT3D,	"AT3D")
+ENDVENDOR()
+
+VENDOR( VMIC, "VMIC" )
+	DEVICE( VMIC,		VMIC_VME,	"VMIVME-7587")
+ENDVENDOR()
+
+VENDOR( DIGI, "Digi Intl." )
+	DEVICE( DIGI,		DIGI_EPC,	"AccelPort EPC")
+	DEVICE( DIGI,		DIGI_RIGHTSWITCH, "RightSwitch SE-6")
+	DEVICE( DIGI,		DIGI_XEM,	"AccelPort Xem")
+	DEVICE( DIGI,		DIGI_XR,	"AccelPort Xr")
+	DEVICE( DIGI,		DIGI_CX,	"AccelPort C/X")
+	DEVICE( DIGI,		DIGI_XRJ,	"AccelPort Xr/J")
+	DEVICE( DIGI,		DIGI_EPCJ,	"AccelPort EPC/J")
+	DEVICE( DIGI,		DIGI_XR_920,	"AccelPort Xr 920")
+ENDVENDOR()
+
+VENDOR( MUTECH, "Mutech" )
+	DEVICE( MUTECH,		MUTECH_MV1000,	"MV-1000")
+ENDVENDOR()
+
+VENDOR( RENDITION, "Rendition" )
+	DEVICE( RENDITION,	RENDITION_VERITE,"Verite 1000")
+	DEVICE( RENDITION,	RENDITION_VERITE2100,"Verite 2100")
+ENDVENDOR()
+
+VENDOR( TOSHIBA, "Toshiba" )
+	DEVICE( TOSHIBA,	TOSHIBA_601,	"Laptop")
+	DEVICE( TOSHIBA,	TOSHIBA_TOPIC95,"ToPIC95")
+	DEVICE( TOSHIBA,	TOSHIBA_TOPIC97,"ToPIC97")
+ENDVENDOR()
+
+VENDOR( RICOH, "Ricoh" )
+	DEVICE( RICOH,		RICOH_RL5C466,	"RL5C466")
+ENDVENDOR()
+
+VENDOR( ARTOP, "Artop Electronics" )
+	DEVICE(	ARTOP,		ARTOP_ATP8400,	"ATP8400")
+	DEVICE( ARTOP,		ARTOP_ATP850UF,	"ATP850UF")
+ENDVENDOR()
+
+VENDOR( ZEITNET, "ZeitNet" )
+	DEVICE( ZEITNET,	ZEITNET_1221,	"1221")
+	DEVICE( ZEITNET,	ZEITNET_1225,	"1225")
+ENDVENDOR()
+
+VENDOR( OMEGA, "Omega Micro" )
+	DEVICE( OMEGA,		OMEGA_82C092G,	"82C092G")
+ENDVENDOR()
+
+VENDOR( LITEON, "LiteOn" )
+	DEVICE( LITEON,		LITEON_LNE100TX,"LNE100TX")
+ENDVENDOR()
+
+VENDOR( NP, "Network Peripherals" )
+	DEVICE( NP,		NP_PCI_FDDI,	"NP-PCI")
+ENDVENDOR()
+
+VENDOR( ATT, "Lucent Microelectronics" )
+	DEVICE( ATT,		ATT_L56XMF,	"L56xMF")
+ENDVENDOR()
+
+VENDOR( SPECIALIX, "Specialix" )
+	DEVICE( SPECIALIX,	SPECIALIX_IO8,	"IO8+/PCI")
+	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host")
+	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host")
+ENDVENDOR()
+
+VENDOR( AURAVISION, "Auravision" )
+	DEVICE( AURAVISION,	AURAVISION_VXP524,"VXP524")
+ENDVENDOR()
+
+VENDOR( IKON, "Ikon" )
+	DEVICE( IKON,		IKON_10115,	"10115 Greensheet")
+	DEVICE( IKON,		IKON_10117,	"10117 Greensheet")
+ENDVENDOR()
+
+VENDOR( ZORAN, "Zoran" )
+	DEVICE( ZORAN,		ZORAN_36057,	"ZR36057")
+	DEVICE( ZORAN,		ZORAN_36120,	"ZR36120")
+ENDVENDOR()
+
+VENDOR( KINETIC, "Kinetic" )
+	DEVICE( KINETIC,	KINETIC_2915,	"2915 CAMAC")
+ENDVENDOR()
+
+VENDOR( COMPEX, "Compex" )
+	DEVICE( COMPEX,		COMPEX_ENET100VG4, "Readylink ENET100-VG4")
+	DEVICE( COMPEX,		COMPEX_RL2000,	"ReadyLink 2000")
+ENDVENDOR()
+
+VENDOR( RP, "Comtrol" )
+	DEVICE( RP,             RP32INTF,       "RocketPort 32 Intf")
+	DEVICE( RP,             RP8INTF,        "RocketPort 8 Intf")
+	DEVICE( RP,             RP16INTF,       "RocketPort 16 Intf")
+	DEVICE( RP, 		RP4QUAD,	"Rocketport 4 Quad")
+	DEVICE( RP,             RP8OCTA,        "RocketPort 8 Oct")
+	DEVICE( RP,             RP8J,	        "RocketPort 8 J")
+	DEVICE( RP,             RPP4,	        "RocketPort Plus 4 Quad")
+	DEVICE( RP,             RPP8,	        "RocketPort Plus 8 Oct")
+	DEVICE( RP,             RP8M,	        "RocketModem 8 J")
+ENDVENDOR()
+
+VENDOR( CYCLADES, "Cyclades" )
+	DEVICE( CYCLADES,	CYCLOM_Y_Lo,	"Cyclom-Y below 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_Y_Hi,	"Cyclom-Y above 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_4Y_Lo,	"Cyclom-4Y below 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_4Y_Hi,	"Cyclom-4Y above 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_8Y_Lo,	"Cyclom-8Y below 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_8Y_Hi,	"Cyclom-8Y above 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_Z_Lo,	"Cyclades-Z below 1Mbyte")
+	DEVICE( CYCLADES,	CYCLOM_Z_Hi,	"Cyclades-Z above 1Mbyte")
+ENDVENDOR()
+
+VENDOR( ESSENTIAL, "Essential Communications" )
+	DEVICE( ESSENTIAL,	ESSENTIAL_ROADRUNNER,"Roadrunner serial HIPPI")
+ENDVENDOR()
+
+VENDOR( O2, "O2 Micro" )
+	DEVICE( O2,		O2_6832,	"6832")
+ENDVENDOR()
+
+VENDOR( 3DFX, "3Dfx" )
+	DEVICE( 3DFX,		3DFX_VOODOO,	"Voodoo")
+	DEVICE( 3DFX,		3DFX_VOODOO2,	"Voodoo2")
+	DEVICE( 3DFX,           3DFX_BANSHEE,   "Banshee")
+	DEVICE( 3DFX,           3DFX_VOODOO3,   "Voodoo3")
+ENDVENDOR()
+
+VENDOR( SIGMADES, "Sigma Designs" )
+	DEVICE( SIGMADES,	SIGMADES_6425,	"REALmagic64/GX")
+ENDVENDOR()
+
+VENDOR( AVM, "AVM" )
+	DEVICE( AVM,		AVM_A1,		"A1 (Fritz)")
+ENDVENDOR()
+
+VENDOR( CCUBE, "C-Cube" )
+ENDVENDOR()
+
+VENDOR( DIPIX, "Dipix" )
+ENDVENDOR()
+
+VENDOR( STALLION, "Stallion" )
+	DEVICE( STALLION,	STALLION_ECHPCI832,"EasyConnection 8/32")
+	DEVICE( STALLION,	STALLION_ECHPCI864,"EasyConnection 8/64")
+	DEVICE( STALLION,	STALLION_EIOPCI,"EasyIO")
+ENDVENDOR()
+
+VENDOR( OPTIBASE, "Optibase" )
+	DEVICE( OPTIBASE,	OPTIBASE_FORGE,	"MPEG Forge")
+	DEVICE( OPTIBASE,	OPTIBASE_FUSION,"MPEG Fusion")
+	DEVICE( OPTIBASE,	OPTIBASE_VPLEX,	"VideoPlex")
+	DEVICE( OPTIBASE,	OPTIBASE_VPLEXCC,"VideoPlex CC")
+	DEVICE( OPTIBASE,	OPTIBASE_VQUEST,"VideoQuest")
+ENDVENDOR()
+
+VENDOR( SATSAGEM, "SatSagem" )
+	DEVICE( SATSAGEM,	SATSAGEM_PCR2101,"PCR2101 DVB receiver")
+	DEVICE( SATSAGEM,	SATSAGEM_TELSATTURBO,"Telsat Turbo DVB")
+ENDVENDOR()
+
+VENDOR( HUGHES, "Hughes" )
+	DEVICE( HUGHES,		HUGHES_DIRECPC,	"DirecPC")
+ENDVENDOR()
+
+VENDOR( ENSONIQ, "Ensoniq" )
+	DEVICE( ENSONIQ,	ENSONIQ_ES1371,	"ES1371")
+	DEVICE( ENSONIQ,	ENSONIQ_AUDIOPCI,"AudioPCI")
+ENDVENDOR()
+
+VENDOR( ALTEON, "Alteon" )
+	DEVICE( ALTEON,		ALTEON_ACENIC,  "AceNIC")
+ENDVENDOR()
+
+VENDOR( PICTUREL, "Picture Elements" )
+	DEVICE( PICTUREL,	PICTUREL_PCIVST,"PCIVST")
+ENDVENDOR()
+
+VENDOR( NVIDIA_SGS, "NVidia/SGS Thomson" )
+	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128")
+ENDVENDOR()
+
+VENDOR( CBOARDS, "ComputerBoards" )
+	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16")
+ENDVENDOR()
+
+VENDOR( MOTOROLA_OOPS, "Motorola" )
+	DEVICE( MOTOROLA_OOPS,	MOTOROLA_FALCON,"Falcon")
+ENDVENDOR()
+
+VENDOR( SYMPHONY, "Symphony" )
+	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101")
+ENDVENDOR()
+
+VENDOR( TEKRAM, "Tekram" )
+	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290")
+ENDVENDOR()
+
+VENDOR( 3DLABS, "3Dlabs" )
+	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX")
+	DEVICE( 3DLABS,		3DLABS_500TX,	"GLINT 500TX")
+	DEVICE( 3DLABS,		3DLABS_DELTA,	"GLINT Delta")
+	DEVICE( 3DLABS,		3DLABS_PERMEDIA,"PERMEDIA")
+	DEVICE( 3DLABS,		3DLABS_MX,	"GLINT MX")
+ENDVENDOR()
+
+VENDOR( AVANCE, "Avance" )
+	DEVICE( AVANCE,		AVANCE_ALG2064,	"ALG2064i")
+	DEVICE( AVANCE,		AVANCE_2302,	"ALG-2302")
+ENDVENDOR()
+
+VENDOR( NETVIN, "NetVin" )
+	DEVICE( NETVIN,		NETVIN_NV5000SC,"NV5000")
+ENDVENDOR()
+
+VENDOR( S3, "S3 Inc." )
+	DEVICE( S3,		S3_PLATO_PXS,	"PLATO/PX (system)")
+	DEVICE( S3,		S3_ViRGE,	"ViRGE")
+	DEVICE( S3,		S3_TRIO,	"Trio32/Trio64")
+	DEVICE( S3,		S3_AURORA64VP,	"Aurora64V+")
+	DEVICE( S3,		S3_TRIO64UVP,	"Trio64UV+")
+	DEVICE( S3,		S3_ViRGE_VX,	"ViRGE/VX")
+	DEVICE( S3,		S3_868,	        "Vision 868")
+	DEVICE( S3,		S3_928,		"Vision 928-P")
+	DEVICE( S3,		S3_864_1,	"Vision 864-P")
+	DEVICE( S3,		S3_864_2,	"Vision 864-P")
+	DEVICE( S3,		S3_964_1,	"Vision 964-P")
+	DEVICE( S3,		S3_964_2,	"Vision 964-P")
+	DEVICE( S3,		S3_968,		"Vision 968")
+	DEVICE( S3,		S3_TRIO64V2,	"Trio64V2/DX or /GX")
+	DEVICE( S3,		S3_PLATO_PXG,	"PLATO/PX (graphics)")
+	DEVICE( S3,		S3_ViRGE_DXGX,	"ViRGE/DX or /GX")
+	DEVICE( S3,		S3_ViRGE_GX2,	"ViRGE/GX2")
+	DEVICE( S3,		S3_ViRGE_MX,	"ViRGE/MX")
+	DEVICE( S3,		S3_ViRGE_MXP,	"ViRGE/MX+")
+	DEVICE( S3,		S3_ViRGE_MXPMV,	"ViRGE/MX+MV")
+	DEVICE( S3,		S3_SONICVIBES,	"SonicVibes")
+ENDVENDOR()
+
+VENDOR( DCI, "Decision Computer Int." )
+	DEVICE( DCI,		DCI_PCCOM4,	"PC COM PCI Bus 4 port serial Adapter")
+ENDVENDOR()
+
+VENDOR( GENROCO, "Genroco" )
+	DEVICE( GENROCO,	GENROCO_HFP832,	"TURBOstor HFP832")
+ENDVENDOR()
+
+VENDOR( INTEL, "Intel" )
+	DEVICE( INTEL,		INTEL_82375,	"82375EB")
+	DEVICE( INTEL,		INTEL_82424,	"82424ZX Saturn")
+	DEVICE( INTEL,		INTEL_82378,	"82378IB")
+	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries")
+	DEVICE( INTEL,		INTEL_82434,	"82434LX Mercury/Neptune")
+	DEVICE( INTEL,		INTEL_82092AA_0,"82092AA PCMCIA bridge")
+	DEVICE( INTEL,		INTEL_82092AA_1,"82092AA EIDE")
+	DEVICE( INTEL,		INTEL_7116,	"SAA7116")
+	DEVICE( INTEL,		INTEL_82596,	"82596")
+	DEVICE( INTEL,		INTEL_82865,	"82865")
+	DEVICE( INTEL,		INTEL_82557,	"EtherExpress Pro100")
+	DEVICE( INTEL,		INTEL_82437,	"82437")
+	DEVICE( INTEL,		INTEL_82371FB_0,"82371FB PIIX ISA")
+	DEVICE( INTEL,		INTEL_82371FB_1,"82371FB PIIX IDE")
+	DEVICE( INTEL,		INTEL_82371MX,	"430MX - 82371MX MPIIX")
+	DEVICE( INTEL,		INTEL_82437MX,	"430MX - 82437MX MTSC")
+	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma")
+	DEVICE( INTEL,		INTEL_82380FB,	"82380FB Mobile")
+	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II")
+	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB PIIX3 ISA")
+	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB PIIX3 IDE")
+	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB PIIX3 USB")
+	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II")
+	DEVICE( INTEL,		INTEL_82439TX,	"82439TX")
+	DEVICE( INTEL,		INTEL_82371AB_0,"82371AB PIIX4 ISA")
+	DEVICE( INTEL,		INTEL_82371AB,	"82371AB PIIX4 IDE")
+	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4 USB")
+	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 ACPI")
+	DEVICE( INTEL,		INTEL_82443LX_0,"440LX - 82443LX PAC Host")
+	DEVICE( INTEL,		INTEL_82443LX_1,"440LX - 82443LX PAC AGP")
+	DEVICE( INTEL,		INTEL_82443BX_0,"440BX - 82443BX Host")
+	DEVICE( INTEL,		INTEL_82443BX_1,"440BX - 82443BX AGP")
+	DEVICE( INTEL,		INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)")
+	DEVICE( INTEL,		INTEL_P6,	"Orion P6")
+	DEVICE( INTEL,		INTEL_82450GX,	"82450GX Orion P6")
+ENDVENDOR()
+
+VENDOR( KTI, "KTI" )
+	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2")
+ENDVENDOR()
+
+VENDOR( ADAPTEC, "Adaptec" )
+	DEVICE( ADAPTEC,	ADAPTEC_7810,	"AIC-7810 RAID")
+	DEVICE( ADAPTEC,	ADAPTEC_7821,	"AIC-7860")
+	DEVICE( ADAPTEC,	ADAPTEC_38602,	"AIC-7860")
+	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850")
+	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855")
+	DEVICE( ADAPTEC,	ADAPTEC_5800,	"AIC-5800")
+	DEVICE( ADAPTEC,	ADAPTEC_3860,	"AIC-7860")
+	DEVICE( ADAPTEC,	ADAPTEC_7860,	"AIC-7860")
+	DEVICE( ADAPTEC,	ADAPTEC_7861,	"AIC-7861")
+	DEVICE( ADAPTEC,	ADAPTEC_7870,	"AIC-7870")
+	DEVICE( ADAPTEC,	ADAPTEC_7871,	"AIC-7871")
+	DEVICE( ADAPTEC,	ADAPTEC_7872,	"AIC-7872")
+	DEVICE( ADAPTEC,	ADAPTEC_7873,	"AIC-7873")
+	DEVICE( ADAPTEC,	ADAPTEC_7874,	"AIC-7874")
+	DEVICE( ADAPTEC,	ADAPTEC_7895,	"AIC-7895U")
+	DEVICE( ADAPTEC,	ADAPTEC_7880,	"AIC-7880U")
+	DEVICE( ADAPTEC,	ADAPTEC_7881,	"AIC-7881U")
+	DEVICE( ADAPTEC,	ADAPTEC_7882,	"AIC-7882U")
+	DEVICE( ADAPTEC,	ADAPTEC_7883,	"AIC-7883U")
+	DEVICE( ADAPTEC,	ADAPTEC_7884,	"AIC-7884U")
+	DEVICE( ADAPTEC,	ADAPTEC_7885,	"AIC-7885U")
+	DEVICE( ADAPTEC,	ADAPTEC_7886,	"AIC-7886U")
+	DEVICE( ADAPTEC,	ADAPTEC_7887,	"AIC-7887U")
+	DEVICE( ADAPTEC,	ADAPTEC_7888,	"AIC-7888U")
+	DEVICE( ADAPTEC,	ADAPTEC_1030,	"ABA-1030 DVB receiver")
+ENDVENDOR()
+
+VENDOR( ADAPTEC2, "Adaptec" )
+	DEVICE( ADAPTEC2,	ADAPTEC2_2940U2,"AHA-2940U2")
+	DEVICE( ADAPTEC2,	ADAPTEC2_2930U2,"AHA-2930U2")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7890B,	"AIC-7890/1")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7890,	"AIC-7890/1")
+	DEVICE( ADAPTEC2,	ADAPTEC2_3940U2,"AHA-3940U2")
+	DEVICE( ADAPTEC2,	ADAPTEC2_3950U2D,"AHA-3950U2D")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7896,	"AIC-7896/7")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892A,	"AIC-7892")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892B,	"AIC-7892")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892D,	"AIC-7892")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7892P,	"AIC-7892")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899A,	"AIC-7899")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899B,	"AIC-7899")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899D,	"AIC-7899")
+	DEVICE( ADAPTEC2,	ADAPTEC2_7899P,	"AIC-7899")
+ENDVENDOR()
+
+VENDOR( ATRONICS, "Atronics" )
+	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL")
+ENDVENDOR()
+
+VENDOR( TIGERJET, "TigerJet" )
+	DEVICE( TIGERJET,	TIGERJET_300,	"Tiger300 ISDN")
+ENDVENDOR()
+
+VENDOR( ARK, "ARK" )
+	DEVICE( ARK,		ARK_STING,	"Stingray")
+	DEVICE( ARK,		ARK_STINGARK,	"Stingray ARK 2000PV")
+	DEVICE( ARK,		ARK_2000MT,	"2000MT")
+ENDVENDOR()
+
+#undef VENDOR
+#undef ENDVENDOR
+#undef DEVICE
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/names.c linux/drivers/pci/names.c
--- v2.3.12/linux/drivers/pci/names.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/names.c	Fri Aug  6 11:16:54 1999
@@ -0,0 +1,98 @@
+/*
+ *	$Id: oldproc.c,v 1.24 1998/10/11 15:13:04 mj Exp $
+ *
+ *	Backward-compatible procfs interface for PCI.
+ *
+ *	Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter,
+ *	David Mosberger-Tang, Martin Mares
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/page.h>
+
+struct pci_device_info {
+	unsigned short device;
+	unsigned short seen;
+	const char *name;
+};
+
+struct pci_vendor_info {
+	unsigned short vendor;
+	unsigned short nr;
+	const char *name;
+	struct pci_device_info *devices;
+};
+
+/*
+ * This is ridiculous, but we want the strings in
+ * the .init section so that they don't take up
+ * real memory.. Parse the same file multiple times
+ * to get all the info.
+ */
+#define VENDOR( vendor, name )		static const char __vendorstr_##vendor[] __initdata = name;
+#define ENDVENDOR()
+#define DEVICE( vendor, device, name ) 	static const char __devicestr_##vendor##device[] __initdata = name;
+#include "devlist.h"
+
+
+#define VENDOR( vendor, name )		static struct pci_device_info __devices_##vendor[] __initdata = {
+#define ENDVENDOR()			};
+#define DEVICE( vendor, device, name )	{ PCI_DEVICE_ID_##device, 0, __devicestr_##vendor##device },
+#include "devlist.h"
+
+static const struct pci_vendor_info __initdata pci_vendor_list[] = {
+#define VENDOR( vendor, name )		{ PCI_VENDOR_ID_##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor },
+#define ENDVENDOR()
+#define DEVICE( vendor, device, name )
+#include "devlist.h"
+};
+
+#define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info))
+
+void __init pci_namedevice(struct pci_dev *dev)
+{
+	const struct pci_vendor_info *vendor_p = pci_vendor_list;
+	int i = VENDORS;
+	
+	do {
+		if (vendor_p->vendor == dev->vendor)
+			goto match_vendor;
+		vendor_p++;
+	} while (--i);
+
+	/* Coulding find either the vendor nor the device */
+	sprintf(dev->name, "PCI<%d:%04x> %04x:%04x", dev->bus->number, dev->devfn, dev->vendor, dev->device);
+	return;
+
+	match_vendor: {
+		struct pci_device_info *device_p = vendor_p->devices;
+		int i = vendor_p->nr;
+
+		while (i > 0) {
+			if (device_p->device == dev->device)
+				goto match_device;
+			device_p++;
+			i--;
+		}
+
+		/* Ok, found the vendor, but unknown device */
+		sprintf(dev->name, "PCI<%d:%04x> %04x:%04x (%s)", dev->bus->number, dev->devfn, dev->vendor, dev->device, vendor_p->name);
+		return;
+
+		/* Full match */
+		match_device: {
+			char *n = dev->name + sprintf(dev->name, "%s %s", vendor_p->name, device_p->name);
+			int nr = device_p->seen + 1;
+			device_p->seen = nr;
+			if (nr > 1)
+				sprintf(n, " (#%d)", nr);
+		}
+	}
+}
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.3.12/linux/drivers/pci/oldproc.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/pci/oldproc.c	Wed Dec 31 16:00:00 1969
@@ -1,1041 +0,0 @@
-/*
- *	$Id: oldproc.c,v 1.24 1998/10/11 15:13:04 mj Exp $
- *
- *	Backward-compatible procfs interface for PCI.
- *
- *	Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter,
- *	David Mosberger-Tang, Martin Mares
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <asm/page.h>
-
-#ifdef CONFIG_PROC_FS
-
-struct pci_dev_info {
-	unsigned short	vendor;		/* vendor id */
-	unsigned short	device;		/* device id */
-
-	const char	*name;		/* device name */
-};
-
-#define DEVICE(vid,did,name) \
-  {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name)}
-
-/*
- * Sorted in ascending order by vendor and device.
- * Use binary search for lookup. If you add a device make sure
- * it is sequential by both vendor and device id.
- */
-struct pci_dev_info dev_info[] = {
-	DEVICE( COMPAQ,		COMPAQ_1280,	"QVision 1280/p"),
-	DEVICE( COMPAQ,		COMPAQ_SMART2P,	"Smart-2/P RAID Controller"),
-	DEVICE( COMPAQ,		COMPAQ_NETEL100,"Netelligent 10/100"),
-	DEVICE( COMPAQ,		COMPAQ_NETEL10,	"Netelligent 10"),
-	DEVICE( COMPAQ,		COMPAQ_NETFLEX3I,"NetFlex 3"),
-	DEVICE( COMPAQ,		COMPAQ_NETEL100D,"Netelligent 10/100 Dual"),
-	DEVICE( COMPAQ,		COMPAQ_NETEL100PI,"Netelligent 10/100 ProLiant"),
-	DEVICE( COMPAQ,		COMPAQ_NETEL100I,"Netelligent 10/100 Integrated"),
-	DEVICE( COMPAQ,		COMPAQ_THUNDER,	"ThunderLAN"),
-	DEVICE( COMPAQ,		COMPAQ_NETFLEX3B,"NetFlex 3 BNC"),
-	DEVICE( NCR,		NCR_53C810,	"53c810"),
-	DEVICE( NCR,		NCR_53C820,	"53c820"),
-	DEVICE( NCR,		NCR_53C825,	"53c825"),
-	DEVICE( NCR,		NCR_53C815,	"53c815"),
-	DEVICE( NCR,		NCR_53C860,	"53c860"),
-	DEVICE( NCR,		NCR_53C896,	"53c896"),
-	DEVICE( NCR,		NCR_53C895,	"53c895"),
-	DEVICE( NCR,		NCR_53C885,	"53c885"),
-	DEVICE( NCR,		NCR_53C875,	"53c875"),
-	DEVICE( NCR,		NCR_53C875J,	"53c875J"),
-	DEVICE( ATI,		ATI_68800,      "68800AX"),
-	DEVICE( ATI,		ATI_215CT222,   "215CT222"),
-	DEVICE( ATI,		ATI_210888CX,   "210888CX"),
-	DEVICE( ATI,		ATI_215GB,	"Mach64 GB"),
-	DEVICE( ATI,		ATI_215GD,	"Mach64 GD (Rage Pro)"),
-	DEVICE( ATI,		ATI_215GI,	"Mach64 GI (Rage Pro)"),
-	DEVICE( ATI,		ATI_215GP,	"Mach64 GP (Rage Pro)"),
-	DEVICE( ATI,		ATI_215GQ,	"Mach64 GQ (Rage Pro)"),
-	DEVICE( ATI,		ATI_215GT,	"Mach64 GT (Rage II)"),
-	DEVICE( ATI,		ATI_215GTB,	"Mach64 GT (Rage II)"),
-	DEVICE( ATI,		ATI_210888GX,   "210888GX"),
-	DEVICE( ATI,		ATI_215LG,	"Mach64 LG (Rage Pro)"),
-	DEVICE( ATI,		ATI_264LT,	"Mach64 LT"),
-	DEVICE( ATI,		ATI_264VT,	"Mach64 VT"),
-	DEVICE( VLSI,		VLSI_82C592,	"82C592-FC1"),
-	DEVICE( VLSI,		VLSI_82C593,	"82C593-FC1"),
-	DEVICE( VLSI,		VLSI_82C594,	"82C594-AFC2"),
-	DEVICE( VLSI,		VLSI_82C597,	"82C597-AFC2"),
-	DEVICE( VLSI,		VLSI_82C541,	"82C541 Lynx"),
-	DEVICE( VLSI,		VLSI_82C543,	"82C543 Lynx ISA"),
-	DEVICE( VLSI,		VLSI_82C532,	"82C532"),
-	DEVICE( VLSI,		VLSI_82C534,	"82C534"),
-	DEVICE( VLSI,		VLSI_82C535,	"82C535"),
-	DEVICE( VLSI,		VLSI_82C147,	"82C147"),
-	DEVICE( VLSI,		VLSI_VAS96011,	"VAS96011 (Golden Gate II)"),
-	DEVICE( ADL,		ADL_2301,	"2301"),
-	DEVICE( NS,		NS_87415,	"87415"),
-	DEVICE( NS,		NS_87410,	"87410"),
-	DEVICE( TSENG,		TSENG_W32P_2,	"ET4000W32P"),
-	DEVICE( TSENG,		TSENG_W32P_b,	"ET4000W32P rev B"),
-	DEVICE( TSENG,		TSENG_W32P_c,	"ET4000W32P rev C"),
-	DEVICE( TSENG,		TSENG_W32P_d,	"ET4000W32P rev D"),
-	DEVICE( TSENG,		TSENG_ET6000,	"ET6000"),
-	DEVICE( WEITEK,		WEITEK_P9000,	"P9000"),
-	DEVICE( WEITEK,		WEITEK_P9100,	"P9100"),
-	DEVICE( DEC,		DEC_BRD,	"DC21050"),
-	DEVICE( DEC,		DEC_TULIP,	"DC21040"),
-	DEVICE( DEC,		DEC_TGA,	"TGA"),
-	DEVICE( DEC,		DEC_TULIP_FAST,	"DC21140"),
-	DEVICE( DEC,		DEC_TGA2,	"TGA2"),
-	DEVICE( DEC,		DEC_FDDI,	"DEFPA"),
-	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
-	DEVICE( DEC,		DEC_21142,	"DC21142"),
-	DEVICE( DEC,		DEC_21052,	"DC21052"),
-	DEVICE( DEC,		DEC_21150,	"DC21150"),
-	DEVICE( DEC,		DEC_21152,	"DC21152"),
-	DEVICE( DEC,		DEC_21153,	"DC21153"),
-	DEVICE( DEC,		DEC_21154,	"DC21154"),
-	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
-	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
-	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
-	DEVICE( CIRRUS,		CIRRUS_5434_8,	"GD 5434"),
-	DEVICE( CIRRUS,		CIRRUS_5436,	"GD 5436"),
-	DEVICE( CIRRUS,		CIRRUS_5446,	"GD 5446"),
-	DEVICE( CIRRUS,		CIRRUS_5480,	"GD 5480"),
-	DEVICE( CIRRUS,		CIRRUS_5464,	"GD 5464"),
-	DEVICE( CIRRUS,		CIRRUS_5465,	"GD 5465"),
-	DEVICE( CIRRUS,		CIRRUS_6729,	"CL 6729"),
-	DEVICE( CIRRUS,		CIRRUS_6832,	"PD 6832"),
-	DEVICE( CIRRUS,		CIRRUS_7542,	"CL 7542"),
-	DEVICE( CIRRUS,		CIRRUS_7543,	"CL 7543"),
-	DEVICE( CIRRUS,		CIRRUS_7541,	"CL 7541"),
-	DEVICE( IBM,		IBM_FIRE_CORAL,	"Fire Coral"),
-	DEVICE( IBM,		IBM_TR,		"Token Ring"),
-	DEVICE( IBM,		IBM_82G2675,	"82G2675"),
-	DEVICE( IBM,		IBM_MCA,	"MicroChannel"),
-	DEVICE( IBM,		IBM_82351,	"82351"),
-	DEVICE( IBM,		IBM_PYTHON,	"Python"),
-	DEVICE( IBM,		IBM_SERVERAID,	"ServeRAID"),
-	DEVICE( IBM,		IBM_TR_WAKE,	"Wake On LAN Token Ring"),
-	DEVICE( IBM,		IBM_MPIC,	"MPIC-2 Interrupt Controller"),
-	DEVICE( IBM,		IBM_3780IDSP,	"MWave DSP"),
-	DEVICE( IBM,		IBM_MPIC_2,	"MPIC-2 ASIC Interrupt Controller"),
-	DEVICE( WD,		WD_7197,	"WD 7197"),
-	DEVICE( AMD,		AMD_LANCE,	"79C970"),
-	DEVICE( AMD,		AMD_SCSI,	"53C974"),
-	DEVICE( TRIDENT,	TRIDENT_9397,	"Cyber9397"),
-	DEVICE( TRIDENT,	TRIDENT_9420,	"TG 9420"),
-	DEVICE( TRIDENT,	TRIDENT_9440,	"TG 9440"),
-	DEVICE( TRIDENT,	TRIDENT_9660,	"TG 9660 / Cyber9385"),
-	DEVICE( TRIDENT,	TRIDENT_9750,	"Image 975"),
-	DEVICE( AI,		AI_M1435,	"M1435"),
-	DEVICE( MATROX,		MATROX_MGA_2,	"Atlas PX2085"),
-	DEVICE( MATROX,		MATROX_MIL,	"Millennium"),
-	DEVICE( MATROX,		MATROX_MYS,	"Mystique"),
-	DEVICE( MATROX,		MATROX_MIL_2,	"Millennium II"),
-	DEVICE( MATROX,		MATROX_MIL_2_AGP,"Millennium II AGP"),
-	DEVICE( MATROX,         MATROX_G200_PCI,"Matrox G200 PCI"),
-	DEVICE( MATROX,         MATROX_G200_AGP,"Matrox G200 AGP"),
-	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression"),
-	DEVICE( MATROX,         MATROX_G100_MM, "Matrox G100 multi monitor"),
-	DEVICE( MATROX,         MATROX_G100_AGP,"Matrox G100 AGP"),
-	DEVICE( CT,		CT_65545,	"65545"),
-	DEVICE( CT,		CT_65548,	"65548"),
-	DEVICE(	CT,		CT_65550,	"65550"),
-	DEVICE( CT,		CT_65554,	"65554"),
-	DEVICE( CT,		CT_65555,	"65555"),
-	DEVICE( MIRO,		MIRO_36050,	"ZR36050"),
-	DEVICE( NEC,		NEC_PCX2,	"PowerVR PCX2"),
-	DEVICE( FD,		FD_36C70,	"TMC-18C30"),
-	DEVICE( SI,		SI_5591_AGP,	"5591/5592 AGP"),
-	DEVICE( SI,		SI_6202,	"6202"),
-	DEVICE( SI,		SI_503,		"85C503"),
-	DEVICE( SI,		SI_ACPI,	"ACPI"),
-	DEVICE( SI,		SI_5597_VGA,	"5597/5598 VGA"),
-	DEVICE( SI,		SI_6205,	"6205"),
-	DEVICE( SI,		SI_501,		"85C501"),
-	DEVICE( SI,		SI_496,		"85C496"),
-	DEVICE( SI,		SI_601,		"85C601"),
-	DEVICE( SI,		SI_5107,	"5107"),
-	DEVICE( SI,		SI_5511,       	"85C5511"),
-	DEVICE( SI,		SI_5513,	"85C5513"),
-	DEVICE( SI,		SI_5571,	"5571"),
-	DEVICE( SI,		SI_5591,	"5591/5592 Host"),
-	DEVICE( SI,		SI_5597,	"5597/5598 Host"),
-	DEVICE( SI,		SI_7001,	"7001 USB"),
-	DEVICE( HP,		HP_J2585A,	"J2585A"),
-	DEVICE( HP,		HP_J2585B,	"J2585B (Lassen)"),
-	DEVICE( PCTECH,		PCTECH_RZ1000,  "RZ1000 (buggy)"),
-	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)"),
-	DEVICE( PCTECH,		PCTECH_SAMURAI_0,"Samurai 0"),
-	DEVICE( PCTECH,		PCTECH_SAMURAI_1,"Samurai 1"),
-	DEVICE( PCTECH,		PCTECH_SAMURAI_IDE,"Samurai IDE"),
-	DEVICE( DPT,		DPT,		"SmartCache/Raid"),
-	DEVICE( OPTI,		OPTI_92C178,	"92C178"),
-	DEVICE( OPTI,		OPTI_82C557,	"82C557 Viper-M"),
-	DEVICE( OPTI,		OPTI_82C558,	"82C558 Viper-M ISA+IDE"),
-	DEVICE( OPTI,		OPTI_82C621,	"82C621"),
-	DEVICE( OPTI,		OPTI_82C700,	"82C700"),
-	DEVICE( OPTI,		OPTI_82C701,	"82C701 FireStar Plus"),
-	DEVICE( OPTI,		OPTI_82C814,	"82C814 Firebridge 1"),
-	DEVICE( OPTI,		OPTI_82C822,	"82C822"),
-	DEVICE( OPTI,		OPTI_82C825,	"82C825 Firebridge 2"),
-	DEVICE( SGS,		SGS_2000,	"STG 2000X"),
-	DEVICE( SGS,		SGS_1764,	"STG 1764X"),
-	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"),
-	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER,    "MultiMaster"),
-	DEVICE( BUSLOGIC,	BUSLOGIC_FLASHPOINT,     "FlashPoint"),
-	DEVICE( TI,		TI_TVP4010,	"TVP4010 Permedia"),
-	DEVICE( TI,		TI_TVP4020,	"TVP4020 Permedia 2"),
-	DEVICE( TI,		TI_PCI1130,	"PCI1130"),
-	DEVICE( TI,		TI_PCI1131,	"PCI1131"),
-	DEVICE( TI,		TI_PCI1250,	"PCI1250"),
-	DEVICE( OAK,		OAK_OTI107,	"OTI107"),
-	DEVICE( WINBOND2,	WINBOND2_89C940,"NE2000-PCI"),
-	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle"),
-	DEVICE( MOTOROLA,	MOTOROLA_MPC106,"MPC106 Grackle"),
-	DEVICE( MOTOROLA,	MOTOROLA_RAVEN,	"Raven"),
-	DEVICE( MOTOROLA,	MOTOROLA_FALCON,"Falcon"),
-	DEVICE( MOTOROLA,	MOTOROLA_CPX8216,"CPX8216"),
-	DEVICE( PROMISE,        PROMISE_20246,	"IDE UltraDMA/33"),
-	DEVICE(	PROMISE,	PROMISE_20262,	"IDE UltraDMA/66"),
-	DEVICE( PROMISE,	PROMISE_5300,	"DC5030"),
-	DEVICE( N9,		N9_I128,	"Imagine 128"),
-	DEVICE( N9,		N9_I128_2,	"Imagine 128v2"),
-	DEVICE( N9,		N9_I128_T2R,	"Revolution 3D"),
-	DEVICE( UMC,		UMC_UM8673F,	"UM8673F"),
-	DEVICE( UMC,		UMC_UM8891A,	"UM8891A"),
-	DEVICE( UMC,		UMC_UM8886BF,	"UM8886BF"),
-	DEVICE( UMC,		UMC_UM8886A,	"UM8886A"),
-	DEVICE( UMC,		UMC_UM8881F,	"UM8881F"),
-	DEVICE( UMC,		UMC_UM8886F,	"UM8886F"),
-	DEVICE( UMC,		UMC_UM9017F,	"UM9017F"),
-	DEVICE( UMC,		UMC_UM8886N,	"UM8886N"),
-	DEVICE( UMC,		UMC_UM8891N,	"UM8891N"),
-	DEVICE( X,		X_AGX016,	"ITT AGX016"),
-	DEVICE( PICOP,		PICOP_PT86C52X,	"PT86C52x Vesuvius"),
-	DEVICE( PICOP,		PICOP_PT80C524,	"PT80C524 Nile"),
-	DEVICE( APPLE,		APPLE_BANDIT,	"Bandit"),
-	DEVICE( APPLE,		APPLE_GC,	"Grand Central"),
-	DEVICE( APPLE,		APPLE_HYDRA,	"Hydra"),
-	DEVICE( NEXGEN,		NEXGEN_82C501,	"82C501"),
-	DEVICE( QLOGIC,		QLOGIC_ISP1020,	"ISP1020"),
-	DEVICE( QLOGIC,		QLOGIC_ISP1022,	"ISP1022"),
-	DEVICE( CYRIX,		CYRIX_5510,	"5510"),
-	DEVICE( CYRIX,		CYRIX_PCI_MASTER,"PCI Master"),
-	DEVICE( CYRIX,		CYRIX_5520,	"5520"),
-	DEVICE( CYRIX,		CYRIX_5530_LEGACY,"5530 Kahlua Legacy"),
-	DEVICE( CYRIX,		CYRIX_5530_SMI,	"5530 Kahlua SMI"),
-	DEVICE( CYRIX,		CYRIX_5530_IDE,	"5530 Kahlua IDE"),
-	DEVICE( CYRIX,		CYRIX_5530_AUDIO,"5530 Kahlua Audio"),
-	DEVICE( CYRIX,		CYRIX_5530_VIDEO,"5530 Kahlua Video"),
-	DEVICE( LEADTEK,	LEADTEK_805,	"S3 805"),
-	DEVICE( CONTAQ,		CONTAQ_82C599,	"82C599"),
-	DEVICE( CONTAQ,		CONTAQ_82C693,	"82C693"),
-	DEVICE( OLICOM,		OLICOM_OC3136,	"OC-3136/3137"),
-	DEVICE( OLICOM,		OLICOM_OC2315,	"OC-2315"),
-	DEVICE( OLICOM,		OLICOM_OC2325,	"OC-2325"),
-	DEVICE( OLICOM,		OLICOM_OC2183,	"OC-2183/2185"),
-	DEVICE( OLICOM,		OLICOM_OC2326,	"OC-2326"),
-	DEVICE( OLICOM,		OLICOM_OC6151,	"OC-6151/6152"),
-	DEVICE( SUN,		SUN_EBUS,	"PCI-EBus Bridge"),
-	DEVICE( SUN,		SUN_HAPPYMEAL,	"Happy Meal Ethernet"),
-	DEVICE( SUN,		SUN_SIMBA,	"Advanced PCI Bridge"),
-	DEVICE( SUN,		SUN_PBM,	"PCI Bus Module"),
-	DEVICE( SUN,		SUN_SABRE,	"Ultra IIi PCI"),
-	DEVICE( CMD,		CMD_640,	"640 (buggy)"),
-	DEVICE( CMD,		CMD_643,	"643"),
-	DEVICE( CMD,		CMD_646,	"646"),
-	DEVICE( CMD,		CMD_670,	"670"),
-	DEVICE( VISION,		VISION_QD8500,	"QD-8500"),
-	DEVICE( VISION,		VISION_QD8580,	"QD-8580"),
-	DEVICE( BROOKTREE,	BROOKTREE_848,	"Bt848"),
-	DEVICE( BROOKTREE,	BROOKTREE_849A,	"Bt849"),
-	DEVICE( BROOKTREE,      BROOKTREE_878_1,"Bt878 2nd Contr. (?)"),
-	DEVICE( BROOKTREE,      BROOKTREE_878,  "Bt878"),
-	DEVICE( BROOKTREE,	BROOKTREE_8474,	"Bt8474"),
-	DEVICE( SIERRA,		SIERRA_STB,	"STB Horizon 64"),
-	DEVICE( SGI,		SGI_IOC3,	"IOC3"),
-	DEVICE( ACC,		ACC_2056,	"2056"),
-	DEVICE( WINBOND,	WINBOND_83769,	"W83769F"),
-	DEVICE( WINBOND,	WINBOND_82C105,	"SL82C105"),
-	DEVICE( WINBOND,	WINBOND_83C553,	"W83C553"),
-	DEVICE( DATABOOK,      	DATABOOK_87144,	"DB87144"),
-	DEVICE(	PLX,		PLX_9050,	"PCI9050 I2O"),
-	DEVICE( PLX,		PLX_9080,	"PCI9080 I2O"),
-	DEVICE( MADGE,		MADGE_MK2,	"Smart 16/4 BM Mk2 Ringnode"),
-	DEVICE( MADGE,		MADGE_C155S,	"Collage 155 Server"),
-	DEVICE( 3COM,		3COM_3C339,	"3C339 TokenRing"),
-	DEVICE( 3COM,		3COM_3C590,	"3C590 10bT"),
-	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX"),
-	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4"),
-	DEVICE( 3COM,		3COM_3C595MII,	"3C595 100b-MII"),
-	DEVICE( 3COM,		3COM_3C900TPO,	"3C900 10bTPO"),
-	DEVICE( 3COM,		3COM_3C900COMBO,"3C900 10b Combo"),
-	DEVICE( 3COM,		3COM_3C905TX,	"3C905 100bTX"),
-	DEVICE( 3COM,		3COM_3C905T4,	"3C905 100bT4"),
-	DEVICE( 3COM,		3COM_3C905B_TX,	"3C905B 100bTX"),
-	DEVICE( SMC,		SMC_EPIC100,	"9432 TX"),
-	DEVICE( AL,		AL_M1445,	"M1445"),
-	DEVICE( AL,		AL_M1449,	"M1449"),
-	DEVICE( AL,		AL_M1451,	"M1451"),
-	DEVICE( AL,		AL_M1461,	"M1461"),
-	DEVICE( AL,		AL_M1489,	"M1489"),
-	DEVICE( AL,		AL_M1511,	"M1511"),
-	DEVICE( AL,		AL_M1513,	"M1513"),
-	DEVICE( AL,		AL_M1521,	"M1521"),
-	DEVICE( AL,		AL_M1523,	"M1523"),
-	DEVICE( AL,		AL_M1531,	"M1531 Aladdin IV"),
-	DEVICE( AL,		AL_M1533,	"M1533 Aladdin IV"),
-	DEVICE(	AL,		AL_M1541,	"M1541 Aladdin V"),
-	DEVICE(	AL,		AL_M1543,	"M1543 Aladdin V"),
-	DEVICE( AL,		AL_M3307,	"M3307 MPEG-1 decoder"),
-	DEVICE( AL,		AL_M4803,	"M4803"),
-	DEVICE( AL,		AL_M5219,	"M5219"),
-	DEVICE( AL,		AL_M5229,	"M5229 TXpro"),
-	DEVICE( AL,		AL_M5237,	"M5237 USB"),
-	DEVICE(	AL,		AL_M5243,	"M5243 AGP"),
-	DEVICE(	AL,		AL_M7101,	"M7101 PMU"),
-	DEVICE( SURECOM,	SURECOM_NE34,	"NE-34PCI LAN"),
-	DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070"),
-	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"),
-	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"),
-	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"),
-	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+"),
-	DEVICE( ASP,		ASP_ABP940,	"ABP940"),
-	DEVICE( ASP,		ASP_ABP940U,	"ABP940U"),
-	DEVICE( ASP,		ASP_ABP940UW,	"ABP940UW"),
-	DEVICE( MACRONIX,	MACRONIX_MX98713,"MX98713"),
-	DEVICE( MACRONIX,	MACRONIX_MX987x5,"MX98715 / MX98725"),
-	DEVICE( CERN,		CERN_SPSB_PMC,	"STAR/RD24 SCI-PCI (PMC)"),
-	DEVICE( CERN,		CERN_SPSB_PCI,	"STAR/RD24 SCI-PCI (PMC)"),
-	DEVICE( CERN,		CERN_HIPPI_DST,	"HIPPI destination"),
-	DEVICE( CERN,		CERN_HIPPI_SRC,	"HIPPI source"),
-	DEVICE( IMS,		IMS_8849,	"8849"),
-	DEVICE( TEKRAM2,	TEKRAM2_690c,	"DC690c"),
-	DEVICE( TUNDRA,		TUNDRA_CA91C042,"CA91C042 Universe"),
-	DEVICE( AMCC,		AMCC_MYRINET,	"Myrinet PCI (M2-PCI-32)"),
-	DEVICE( AMCC,		AMCC_PARASTATION,"ParaStation Interface"),
-	DEVICE( AMCC,		AMCC_S5933,	"S5933 PCI44"),
-	DEVICE( AMCC,		AMCC_S5933_HEPC3,"S5933 Traquair HEPC3"),
-	DEVICE( INTERG,		INTERG_1680,	"IGA-1680"),
-	DEVICE( INTERG,         INTERG_1682,    "IGA-1682"),
-	DEVICE( REALTEK,	REALTEK_8029,	"8029"),
-	DEVICE( REALTEK,	REALTEK_8129,	"8129"),
-	DEVICE( REALTEK,	REALTEK_8139,	"8139"),
-	DEVICE( TRUEVISION,	TRUEVISION_T1000,"TARGA 1000"),
-	DEVICE( INIT,		INIT_320P,	"320 P"),
-	DEVICE( INIT,		INIT_360P,	"360 P"),
-	DEVICE(	TTI,		TTI_HPT343,	"HPT343"),
-	DEVICE( VIA,		VIA_82C505,	"VT 82C505"),
-	DEVICE( VIA,		VIA_82C561,	"VT 82C561"),
-	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo IDE"),
-	DEVICE( VIA,		VIA_82C576,	"VT 82C576 3V"),
-	DEVICE( VIA,		VIA_82C585,	"VT 82C585 Apollo VP1/VPX"),
-	DEVICE( VIA,		VIA_82C586_0,	"VT 82C586 Apollo ISA"),
-	DEVICE( VIA,		VIA_82C595,	"VT 82C595 Apollo VP2"),
-	DEVICE( VIA,		VIA_82C597_0,	"VT 82C597 Apollo VP3"),
-	DEVICE( VIA,		VIA_82C598_0,	"VT 82C598 Apollo MVP3"),
-	DEVICE( VIA,		VIA_82C926,	"VT 82C926 Amazon"),
-	DEVICE( VIA,		VIA_82C416,	"VT 82C416MV"),
-	DEVICE( VIA,		VIA_82C595_97,	"VT 82C595 Apollo VP2/97"),
-	DEVICE( VIA,		VIA_82C586_2,	"VT 82C586 Apollo USB"),
-	DEVICE( VIA,		VIA_82C586_3,	"VT 82C586B Apollo ACPI"),
-	DEVICE( VIA,		VIA_86C100A,	"VT 86C100A"),
-	DEVICE( VIA,		VIA_82C597_1,	"VT 82C597 Apollo VP3 AGP"),
-	DEVICE( VIA,		VIA_82C598_1,	"VT 82C598 Apollo MVP3 AGP"),
-	DEVICE( SMC2,		SMC2_1211TX,	"1211 TX"),
-	DEVICE( VORTEX,		VORTEX_GDT60x0,	"GDT 60x0"),
-	DEVICE( VORTEX,		VORTEX_GDT6000B,"GDT 6000b"),
-	DEVICE( VORTEX,		VORTEX_GDT6x10,	"GDT 6110/6510"),
-	DEVICE( VORTEX,		VORTEX_GDT6x20,	"GDT 6120/6520"),
-	DEVICE( VORTEX,		VORTEX_GDT6530,	"GDT 6530"),
-	DEVICE( VORTEX,		VORTEX_GDT6550,	"GDT 6550"),
-	DEVICE( VORTEX,		VORTEX_GDT6x17,	"GDT 6117/6517"),
-	DEVICE( VORTEX,		VORTEX_GDT6x27,	"GDT 6127/6527"),
-	DEVICE( VORTEX,		VORTEX_GDT6537,	"GDT 6537"),
-	DEVICE( VORTEX,		VORTEX_GDT6557,	"GDT 6557"),
-	DEVICE( VORTEX,		VORTEX_GDT6x15,	"GDT 6115/6515"),
-	DEVICE( VORTEX,		VORTEX_GDT6x25,	"GDT 6125/6525"),
-	DEVICE( VORTEX,		VORTEX_GDT6535,	"GDT 6535"),
-	DEVICE( VORTEX,		VORTEX_GDT6555,	"GDT 6555"),
-	DEVICE( VORTEX,		VORTEX_GDT6x17RP,"GDT 6117RP/6517RP"),
-	DEVICE( VORTEX,		VORTEX_GDT6x27RP,"GDT 6127RP/6527RP"),
-	DEVICE( VORTEX,		VORTEX_GDT6537RP,"GDT 6537RP"),
-	DEVICE( VORTEX,		VORTEX_GDT6557RP,"GDT 6557RP"),
-	DEVICE( VORTEX,		VORTEX_GDT6x11RP,"GDT 6111RP/6511RP"),
-	DEVICE( VORTEX,		VORTEX_GDT6x21RP,"GDT 6121RP/6521RP"),
-	DEVICE( VORTEX,		VORTEX_GDT6x17RP1,"GDT 6117RP1/6517RP1"),
-	DEVICE( VORTEX,		VORTEX_GDT6x27RP1,"GDT 6127RP1/6527RP1"),
-	DEVICE( VORTEX,		VORTEX_GDT6537RP1,"GDT 6537RP1"),
-	DEVICE( VORTEX,		VORTEX_GDT6557RP1,"GDT 6557RP1"),
-	DEVICE( VORTEX,		VORTEX_GDT6x11RP1,"GDT 6111RP1/6511RP1"),
-	DEVICE( VORTEX,		VORTEX_GDT6x21RP1,"GDT 6121RP1/6521RP1"),
-	DEVICE( VORTEX,		VORTEX_GDT6x17RP2,"GDT 6117RP2/6517RP2"),
-	DEVICE( VORTEX,		VORTEX_GDT6x27RP2,"GDT 6127RP2/6527RP2"),
-	DEVICE( VORTEX,		VORTEX_GDT6537RP2,"GDT 6537RP2"),
-	DEVICE( VORTEX,		VORTEX_GDT6557RP2,"GDT 6557RP2"),
-	DEVICE( VORTEX,		VORTEX_GDT6x11RP2,"GDT 6111RP2/6511RP2"),
-	DEVICE( VORTEX,		VORTEX_GDT6x21RP2,"GDT 6121RP2/6521RP2"),
-	DEVICE( EF,		EF_ATM_FPGA,   	"155P-MF1 (FPGA)"),
-	DEVICE( EF,		EF_ATM_ASIC,    "155P-MF1 (ASIC)"),
-	DEVICE( FORE,		FORE_PCA200PC,  "PCA-200PC"),
-	DEVICE( FORE,		FORE_PCA200E,	 "PCA-200E"),
-	DEVICE( IMAGINGTECH,	IMAGINGTECH_ICPCI, "MVC IC-PCI"),
-	DEVICE( PHILIPS,	PHILIPS_SAA7145,"SAA7145"),
-	DEVICE( PHILIPS,	PHILIPS_SAA7146,"SAA7146"),
-	DEVICE( CYCLONE,	CYCLONE_SDK,	"SDK"),
-	DEVICE( ALLIANCE,	ALLIANCE_PROMOTIO, "Promotion-6410"),
-	DEVICE( ALLIANCE,	ALLIANCE_PROVIDEO, "Provideo"),
-	DEVICE( ALLIANCE,	ALLIANCE_AT24,	"AT24"),
-	DEVICE( ALLIANCE,	ALLIANCE_AT3D,	"AT3D"),
-	DEVICE( VMIC,		VMIC_VME,	"VMIVME-7587"),
-	DEVICE( DIGI,		DIGI_EPC,	"AccelPort EPC"),
- 	DEVICE( DIGI,		DIGI_RIGHTSWITCH, "RightSwitch SE-6"),
-	DEVICE( DIGI,		DIGI_XEM,	"AccelPort Xem"),
-	DEVICE( DIGI,		DIGI_XR,	"AccelPort Xr"),
-	DEVICE( DIGI,		DIGI_CX,	"AccelPort C/X"),
-	DEVICE( DIGI,		DIGI_XRJ,	"AccelPort Xr/J"),
-	DEVICE( DIGI,		DIGI_EPCJ,	"AccelPort EPC/J"),
-	DEVICE( DIGI,		DIGI_XR_920,	"AccelPort Xr 920"),
-	DEVICE( MUTECH,		MUTECH_MV1000,	"MV-1000"),
-	DEVICE( RENDITION,	RENDITION_VERITE,"Verite 1000"),
-	DEVICE( RENDITION,	RENDITION_VERITE2100,"Verite 2100"),
-	DEVICE( TOSHIBA,	TOSHIBA_601,	"Laptop"),
-	DEVICE( TOSHIBA,	TOSHIBA_TOPIC95,"ToPIC95"),
-	DEVICE( TOSHIBA,	TOSHIBA_TOPIC97,"ToPIC97"),
-	DEVICE( RICOH,		RICOH_RL5C466,	"RL5C466"),
-	DEVICE(	ARTOP,		ARTOP_ATP8400,	"ATP8400"),
-	DEVICE( ARTOP,		ARTOP_ATP850UF,	"ATP850UF"),
-	DEVICE( ZEITNET,	ZEITNET_1221,	"1221"),
-	DEVICE( ZEITNET,	ZEITNET_1225,	"1225"),
-	DEVICE( OMEGA,		OMEGA_82C092G,	"82C092G"),
-	DEVICE( LITEON,		LITEON_LNE100TX,"LNE100TX"),
-	DEVICE( NP,		NP_PCI_FDDI,	"NP-PCI"),       
-	DEVICE( ATT,		ATT_L56XMF,	"L56xMF"),
-	DEVICE( SPECIALIX,	SPECIALIX_IO8,	"IO8+/PCI"),
-	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
-	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
-	DEVICE( AURAVISION,	AURAVISION_VXP524,"VXP524"),
-	DEVICE( IKON,		IKON_10115,	"10115 Greensheet"),
-	DEVICE( IKON,		IKON_10117,	"10117 Greensheet"),
-	DEVICE( ZORAN,		ZORAN_36057,	"ZR36057"),
-	DEVICE( ZORAN,		ZORAN_36120,	"ZR36120"),
-	DEVICE( KINETIC,	KINETIC_2915,	"2915 CAMAC"),
-	DEVICE( COMPEX,		COMPEX_ENET100VG4, "Readylink ENET100-VG4"),
-	DEVICE( COMPEX,		COMPEX_RL2000,	"ReadyLink 2000"),
-	DEVICE( RP,             RP32INTF,       "RocketPort 32 Intf"),
-	DEVICE( RP,             RP8INTF,        "RocketPort 8 Intf"),
-	DEVICE( RP,             RP16INTF,       "RocketPort 16 Intf"),
-	DEVICE( RP, 		RP4QUAD,	"Rocketport 4 Quad"),
-	DEVICE( RP,             RP8OCTA,        "RocketPort 8 Oct"),
-	DEVICE( RP,             RP8J,	        "RocketPort 8 J"),
-	DEVICE( RP,             RPP4,	        "RocketPort Plus 4 Quad"),
-	DEVICE( RP,             RPP8,	        "RocketPort Plus 8 Oct"),
-	DEVICE( RP,             RP8M,	        "RocketModem 8 J"),
-	DEVICE( CYCLADES,	CYCLOM_Y_Lo,	"Cyclom-Y below 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_Y_Hi,	"Cyclom-Y above 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_4Y_Lo,	"Cyclom-4Y below 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_4Y_Hi,	"Cyclom-4Y above 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_8Y_Lo,	"Cyclom-8Y below 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_8Y_Hi,	"Cyclom-8Y above 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_Z_Lo,	"Cyclades-Z below 1Mbyte"),
-	DEVICE( CYCLADES,	CYCLOM_Z_Hi,	"Cyclades-Z above 1Mbyte"),
-	DEVICE( ESSENTIAL,	ESSENTIAL_ROADRUNNER,"Roadrunner serial HIPPI"),
-	DEVICE( O2,		O2_6832,	"6832"),
-	DEVICE( 3DFX,		3DFX_VOODOO,	"Voodoo"),
-	DEVICE( 3DFX,		3DFX_VOODOO2,	"Voodoo2"),
-	DEVICE( 3DFX,           3DFX_BANSHEE,   "Banshee"),
-	DEVICE( SIGMADES,	SIGMADES_6425,	"REALmagic64/GX"),
-	DEVICE( AVM,		AVM_A1,		"A1 (Fritz)"),
-	DEVICE( STALLION,	STALLION_ECHPCI832,"EasyConnection 8/32"),
-	DEVICE( STALLION,	STALLION_ECHPCI864,"EasyConnection 8/64"),
-	DEVICE( STALLION,	STALLION_EIOPCI,"EasyIO"),
-	DEVICE( OPTIBASE,	OPTIBASE_FORGE,	"MPEG Forge"),
-	DEVICE( OPTIBASE,	OPTIBASE_FUSION,"MPEG Fusion"),
-	DEVICE( OPTIBASE,	OPTIBASE_VPLEX,	"VideoPlex"),
-	DEVICE( OPTIBASE,	OPTIBASE_VPLEXCC,"VideoPlex CC"),
-	DEVICE( OPTIBASE,	OPTIBASE_VQUEST,"VideoQuest"),
-	DEVICE( SATSAGEM,	SATSAGEM_PCR2101,"PCR2101 DVB receiver"),
-	DEVICE( SATSAGEM,	SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"),
-	DEVICE( HUGHES,		HUGHES_DIRECPC,	"DirecPC"),
-	DEVICE( ENSONIQ,	ENSONIQ_ES1371,	"ES1371"),
-	DEVICE( ENSONIQ,	ENSONIQ_AUDIOPCI,"AudioPCI"),
-	DEVICE( ALTEON,		ALTEON_ACENIC,  "AceNIC"),
-	DEVICE( PICTUREL,	PICTUREL_PCIVST,"PCIVST"),
-	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128"),
-	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
-	DEVICE( MOTOROLA_OOPS,	MOTOROLA_FALCON,"Falcon"),
-	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
-	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
-	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
-	DEVICE( 3DLABS,		3DLABS_500TX,	"GLINT 500TX"),
-	DEVICE( 3DLABS,		3DLABS_DELTA,	"GLINT Delta"),
-	DEVICE( 3DLABS,		3DLABS_PERMEDIA,"PERMEDIA"),
-	DEVICE( 3DLABS,		3DLABS_MX,	"GLINT MX"),
-	DEVICE( AVANCE,		AVANCE_ALG2064,	"ALG2064i"),
-	DEVICE( AVANCE,		AVANCE_2302,	"ALG-2302"),
-	DEVICE( NETVIN,		NETVIN_NV5000SC,"NV5000"),
-	DEVICE( S3,		S3_PLATO_PXS,	"PLATO/PX (system)"),
-	DEVICE( S3,		S3_ViRGE,	"ViRGE"),
-	DEVICE( S3,		S3_TRIO,	"Trio32/Trio64"),
-	DEVICE( S3,		S3_AURORA64VP,	"Aurora64V+"),
-	DEVICE( S3,		S3_TRIO64UVP,	"Trio64UV+"),
-	DEVICE( S3,		S3_ViRGE_VX,	"ViRGE/VX"),
-	DEVICE( S3,		S3_868,	        "Vision 868"),
-	DEVICE( S3,		S3_928,		"Vision 928-P"),
-	DEVICE( S3,		S3_864_1,	"Vision 864-P"),
-	DEVICE( S3,		S3_864_2,	"Vision 864-P"),
-	DEVICE( S3,		S3_964_1,	"Vision 964-P"),
-	DEVICE( S3,		S3_964_2,	"Vision 964-P"),
-	DEVICE( S3,		S3_968,		"Vision 968"),
-	DEVICE( S3,		S3_TRIO64V2,	"Trio64V2/DX or /GX"),
-	DEVICE( S3,		S3_PLATO_PXG,	"PLATO/PX (graphics)"),
-	DEVICE( S3,		S3_ViRGE_DXGX,	"ViRGE/DX or /GX"),
-	DEVICE( S3,		S3_ViRGE_GX2,	"ViRGE/GX2"),
-	DEVICE( S3,		S3_ViRGE_MX,	"ViRGE/MX"),
-	DEVICE( S3,		S3_ViRGE_MXP,	"ViRGE/MX+"),
-	DEVICE( S3,		S3_ViRGE_MXPMV,	"ViRGE/MX+MV"),
-	DEVICE( S3,		S3_SONICVIBES,	"SonicVibes"),
-	DEVICE( DCI,		DCI_PCCOM4,	"PC COM PCI Bus 4 port serial Adapter"),
-	DEVICE( GENROCO,	GENROCO_HFP832,	"TURBOstor HFP832"),
-	DEVICE( INTEL,		INTEL_82375,	"82375EB"),
-	DEVICE( INTEL,		INTEL_82424,	"82424ZX Saturn"),
-	DEVICE( INTEL,		INTEL_82378,	"82378IB"),
-	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries"),
-	DEVICE( INTEL,		INTEL_82434,	"82434LX Mercury/Neptune"),
-	DEVICE( INTEL,		INTEL_82092AA_0,"82092AA PCMCIA bridge"),
-	DEVICE( INTEL,		INTEL_82092AA_1,"82092AA EIDE"),
-	DEVICE( INTEL,		INTEL_7116,	"SAA7116"),
-	DEVICE( INTEL,		INTEL_82596,	"82596"),
-	DEVICE( INTEL,		INTEL_82865,	"82865"),
-	DEVICE( INTEL,		INTEL_82557,	"82557"),
-	DEVICE( INTEL,		INTEL_82437,	"82437"),
-	DEVICE( INTEL,		INTEL_82371FB_0,"82371FB PIIX ISA"),
-	DEVICE( INTEL,		INTEL_82371FB_1,"82371FB PIIX IDE"),
-	DEVICE( INTEL,		INTEL_82371MX,	"430MX - 82371MX MPIIX"),
-	DEVICE( INTEL,		INTEL_82437MX,	"430MX - 82437MX MTSC"),
-	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
-	DEVICE( INTEL,		INTEL_82380FB,	"82380FB Mobile"),
-	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
-	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB PIIX3 ISA"),
-	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB PIIX3 IDE"),
-	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB PIIX3 USB"),
-	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II"),
-	DEVICE( INTEL,		INTEL_82439TX,	"82439TX"),
-	DEVICE( INTEL,		INTEL_82371AB_0,"82371AB PIIX4 ISA"),
-	DEVICE( INTEL,		INTEL_82371AB,	"82371AB PIIX4 IDE"),
-	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4 USB"),
-	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 ACPI"),
-	DEVICE( INTEL,		INTEL_82443LX_0,"440LX - 82443LX PAC Host"),
-	DEVICE( INTEL,		INTEL_82443LX_1,"440LX - 82443LX PAC AGP"),
-	DEVICE( INTEL,		INTEL_82443BX_0,"440BX - 82443BX Host"),
-	DEVICE( INTEL,		INTEL_82443BX_1,"440BX - 82443BX AGP"),
-	DEVICE( INTEL,		INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)"),
-	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
- 	DEVICE( INTEL,		INTEL_82450GX,	"82450GX Orion P6"),
-	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
-	DEVICE( ADAPTEC,	ADAPTEC_7810,	"AIC-7810 RAID"),
-	DEVICE( ADAPTEC,	ADAPTEC_7821,	"AIC-7860"),
-	DEVICE( ADAPTEC,	ADAPTEC_38602,	"AIC-7860"),
-	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850"),
-	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855"),
-	DEVICE( ADAPTEC,	ADAPTEC_5800,	"AIC-5800"),
-	DEVICE( ADAPTEC,	ADAPTEC_3860,	"AIC-7860"),
-	DEVICE( ADAPTEC,	ADAPTEC_7860,	"AIC-7860"),
-	DEVICE( ADAPTEC,	ADAPTEC_7861,	"AIC-7861"),
-	DEVICE( ADAPTEC,	ADAPTEC_7870,	"AIC-7870"),
-	DEVICE( ADAPTEC,	ADAPTEC_7871,	"AIC-7871"),
-	DEVICE( ADAPTEC,	ADAPTEC_7872,	"AIC-7872"),
-	DEVICE( ADAPTEC,	ADAPTEC_7873,	"AIC-7873"),
-	DEVICE( ADAPTEC,	ADAPTEC_7874,	"AIC-7874"),
-	DEVICE( ADAPTEC,	ADAPTEC_7895,	"AIC-7895U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7880,	"AIC-7880U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7881,	"AIC-7881U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7882,	"AIC-7882U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7883,	"AIC-7883U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7884,	"AIC-7884U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7885,	"AIC-7885U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7886,	"AIC-7886U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7887,	"AIC-7887U"),
-	DEVICE( ADAPTEC,	ADAPTEC_7888,	"AIC-7888U"),
-	DEVICE( ADAPTEC,	ADAPTEC_1030,	"ABA-1030 DVB receiver"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_2940U2,"AHA-2940U2"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_2930U2,"AHA-2930U2"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7890B,	"AIC-7890/1"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7890,	"AIC-7890/1"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_3940U2,"AHA-3940U2"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_3950U2D,"AHA-3950U2D"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7896,	"AIC-7896/7"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7892A,	"AIC-7892"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7892B,	"AIC-7892"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7892D,	"AIC-7892"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7892P,	"AIC-7892"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7899A,	"AIC-7899"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7899B,	"AIC-7899"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7899D,	"AIC-7899"),
-	DEVICE( ADAPTEC2,	ADAPTEC2_7899P,	"AIC-7899"),
-  	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL"),
-	DEVICE( TIGERJET,	TIGERJET_300,	"Tiger300 ISDN"),
-	DEVICE( ARK,		ARK_STING,	"Stingray"),
-	DEVICE( ARK,		ARK_STINGARK,	"Stingray ARK 2000PV"),
-	DEVICE( ARK,		ARK_2000MT,	"2000MT")
-};
-
-
-/*
- * device_info[] is sorted so we can use binary search
- */
-static struct pci_dev_info *pci_lookup_dev(unsigned int vendor, unsigned int dev)
-{
-	int min = 0,
-	    max = sizeof(dev_info)/sizeof(dev_info[0]) - 1;
-
-	for ( ; ; )
-	{
-	    int i = (min + max) >> 1;
-	    long order;
-
-	    order = dev_info[i].vendor - (long) vendor;
-	    if (!order)
-		order = dev_info[i].device - (long) dev;
-	
-	    if (order < 0)
-	    {
-		    min = i + 1;
-		    if ( min > max )
-		       return 0;
-		    continue;
-	    }
-
-	    if (order > 0)
-	    {
-		    max = i - 1;
-		    if ( min > max )
-		       return 0;
-		    continue;
-	    }
-  	   
-	    return & dev_info[ i ];
-	}
-}
-
-static const char *pci_strclass (unsigned int class)
-{
-	switch (class >> 8) {
-	      case PCI_CLASS_NOT_DEFINED:		return "Non-VGA device";
-	      case PCI_CLASS_NOT_DEFINED_VGA:		return "VGA compatible device";
-
-	      case PCI_CLASS_STORAGE_SCSI:		return "SCSI storage controller";
-	      case PCI_CLASS_STORAGE_IDE:		return "IDE interface";
-	      case PCI_CLASS_STORAGE_FLOPPY:		return "Floppy disk controller";
-	      case PCI_CLASS_STORAGE_IPI:		return "IPI bus controller";
-	      case PCI_CLASS_STORAGE_RAID:		return "RAID bus controller";
-	      case PCI_CLASS_STORAGE_OTHER:		return "Unknown mass storage controller";
-
-	      case PCI_CLASS_NETWORK_ETHERNET:		return "Ethernet controller";
-	      case PCI_CLASS_NETWORK_TOKEN_RING:	return "Token ring network controller";
-	      case PCI_CLASS_NETWORK_FDDI:		return "FDDI network controller";
-	      case PCI_CLASS_NETWORK_ATM:		return "ATM network controller";
-	      case PCI_CLASS_NETWORK_OTHER:		return "Network controller";
-
-	      case PCI_CLASS_DISPLAY_VGA:		return "VGA compatible controller";
-	      case PCI_CLASS_DISPLAY_XGA:		return "XGA compatible controller";
-	      case PCI_CLASS_DISPLAY_OTHER:		return "Display controller";
-
-	      case PCI_CLASS_MULTIMEDIA_VIDEO:		return "Multimedia video controller";
-	      case PCI_CLASS_MULTIMEDIA_AUDIO:		return "Multimedia audio controller";
-	      case PCI_CLASS_MULTIMEDIA_OTHER:		return "Multimedia controller";
-
-	      case PCI_CLASS_MEMORY_RAM:		return "RAM memory";
-	      case PCI_CLASS_MEMORY_FLASH:		return "FLASH memory";
-	      case PCI_CLASS_MEMORY_OTHER:		return "Memory";
-
-	      case PCI_CLASS_BRIDGE_HOST:		return "Host bridge";
-	      case PCI_CLASS_BRIDGE_ISA:		return "ISA bridge";
-	      case PCI_CLASS_BRIDGE_EISA:		return "EISA bridge";
-	      case PCI_CLASS_BRIDGE_MC:			return "MicroChannel bridge";
-	      case PCI_CLASS_BRIDGE_PCI:		return "PCI bridge";
-	      case PCI_CLASS_BRIDGE_PCMCIA:		return "PCMCIA bridge";
-	      case PCI_CLASS_BRIDGE_NUBUS:		return "NuBus bridge";
-	      case PCI_CLASS_BRIDGE_CARDBUS:		return "CardBus bridge";
-	      case PCI_CLASS_BRIDGE_OTHER:		return "Bridge";
-
-	      case PCI_CLASS_COMMUNICATION_SERIAL:	return "Serial controller";
-	      case PCI_CLASS_COMMUNICATION_PARALLEL:	return "Parallel controller";
-	      case PCI_CLASS_COMMUNICATION_OTHER:	return "Communication controller";
-
-	      case PCI_CLASS_SYSTEM_PIC:		return "PIC";
-	      case PCI_CLASS_SYSTEM_DMA:		return "DMA controller";
-	      case PCI_CLASS_SYSTEM_TIMER:		return "Timer";
-	      case PCI_CLASS_SYSTEM_RTC:		return "RTC";
-	      case PCI_CLASS_SYSTEM_OTHER:		return "System peripheral";
-
-	      case PCI_CLASS_INPUT_KEYBOARD:		return "Keyboard controller";
-	      case PCI_CLASS_INPUT_PEN:			return "Digitizer Pen";
-	      case PCI_CLASS_INPUT_MOUSE:		return "Mouse controller";
-	      case PCI_CLASS_INPUT_OTHER:		return "Input device controller";
-
-	      case PCI_CLASS_DOCKING_GENERIC:		return "Generic Docking Station";
-	      case PCI_CLASS_DOCKING_OTHER:		return "Docking Station";
-
-	      case PCI_CLASS_PROCESSOR_386:		return "386";
-	      case PCI_CLASS_PROCESSOR_486:		return "486";
-	      case PCI_CLASS_PROCESSOR_PENTIUM:		return "Pentium";
-	      case PCI_CLASS_PROCESSOR_ALPHA:		return "Alpha";
-	      case PCI_CLASS_PROCESSOR_POWERPC:		return "Power PC";
-	      case PCI_CLASS_PROCESSOR_CO:		return "Co-processor";
-
-	      case PCI_CLASS_SERIAL_FIREWIRE:		return "FireWire (IEEE 1394)";
-	      case PCI_CLASS_SERIAL_ACCESS:		return "ACCESS Bus";
-	      case PCI_CLASS_SERIAL_SSA:		return "SSA";
-	      case PCI_CLASS_SERIAL_USB:		return "USB Controller";
-	      case PCI_CLASS_SERIAL_FIBER:		return "Fiber Channel";
-
-	      case PCI_CLASS_HOT_SWAP_CONTROLLER:	return "Hot Swap Controller";
-
-	      default:					return "Unknown class";
-	}
-}
-
-
-static const char *pci_strvendor(unsigned int vendor)
-{
-	switch (vendor) {
-	      case PCI_VENDOR_ID_COMPAQ:	return "Compaq";
-	      case PCI_VENDOR_ID_NCR:		return "NCR";
-	      case PCI_VENDOR_ID_ATI:		return "ATI";
-	      case PCI_VENDOR_ID_VLSI:		return "VLSI";
-	      case PCI_VENDOR_ID_ADL:		return "Avance Logic";
-	      case PCI_VENDOR_ID_NS:		return "NS";
-	      case PCI_VENDOR_ID_TSENG:		return "Tseng'Lab";
-	      case PCI_VENDOR_ID_WEITEK:	return "Weitek";
-	      case PCI_VENDOR_ID_DEC:		return "DEC";
-	      case PCI_VENDOR_ID_CIRRUS:	return "Cirrus Logic";
-	      case PCI_VENDOR_ID_IBM:		return "IBM";
-	      case PCI_VENDOR_ID_WD:		return "Western Digital";
-	      case PCI_VENDOR_ID_AMD:		return "AMD";
-	      case PCI_VENDOR_ID_TRIDENT:	return "Trident";
-	      case PCI_VENDOR_ID_AI:		return "Acer Incorporated";
-	      case PCI_VENDOR_ID_MATROX:	return "Matrox";
-	      case PCI_VENDOR_ID_CT:		return "Chips & Technologies";
-	      case PCI_VENDOR_ID_MIRO:		return "Miro";
-	      case PCI_VENDOR_ID_NEC:		return "NEC";
-	      case PCI_VENDOR_ID_FD:		return "Future Domain";
-	      case PCI_VENDOR_ID_SI:		return "Silicon Integrated Systems";
-	      case PCI_VENDOR_ID_HP:		return "Hewlett Packard";
-	      case PCI_VENDOR_ID_PCTECH:	return "PCTECH";
-	      case PCI_VENDOR_ID_DPT:		return "DPT";
-	      case PCI_VENDOR_ID_OPTI:		return "OPTi";
-	      case PCI_VENDOR_ID_SGS:		return "SGS Thomson";
-	      case PCI_VENDOR_ID_BUSLOGIC:	return "BusLogic";
-	      case PCI_VENDOR_ID_TI:		return "Texas Instruments";
-	      case PCI_VENDOR_ID_OAK: 		return "OAK";
-	      case PCI_VENDOR_ID_WINBOND2:	return "Winbond";
-	      case PCI_VENDOR_ID_MOTOROLA:	return "Motorola";
-	      case PCI_VENDOR_ID_MOTOROLA_OOPS:	return "Motorola";
-	      case PCI_VENDOR_ID_PROMISE:	return "Promise Technology";
-	      case PCI_VENDOR_ID_N9:		return "Number Nine";
-	      case PCI_VENDOR_ID_UMC:		return "UMC";
-	      case PCI_VENDOR_ID_X:		return "X TECHNOLOGY";
-	      case PCI_VENDOR_ID_PICOP:		return "PicoPower";
-	      case PCI_VENDOR_ID_APPLE:		return "Apple";
-	      case PCI_VENDOR_ID_NEXGEN:	return "Nexgen";
-	      case PCI_VENDOR_ID_QLOGIC:	return "Q Logic";
-	      case PCI_VENDOR_ID_CYRIX:		return "Cyrix";
-	      case PCI_VENDOR_ID_LEADTEK:	return "Leadtek Research";
-	      case PCI_VENDOR_ID_CONTAQ:	return "Contaq";
-	      case PCI_VENDOR_ID_FOREX:		return "Forex";
-	      case PCI_VENDOR_ID_OLICOM:	return "Olicom";
-	      case PCI_VENDOR_ID_SUN:		return "Sun Microsystems";
-	      case PCI_VENDOR_ID_CMD:		return "CMD";
-	      case PCI_VENDOR_ID_VISION:	return "Vision";
-	      case PCI_VENDOR_ID_BROOKTREE:	return "Brooktree";
-	      case PCI_VENDOR_ID_SIERRA:	return "Sierra";
-	      case PCI_VENDOR_ID_ACC:		return "ACC MICROELECTRONICS";
-	      case PCI_VENDOR_ID_WINBOND:	return "Winbond";
-	      case PCI_VENDOR_ID_DATABOOK:	return "Databook";
-	      case PCI_VENDOR_ID_PLX:		return "PLX";
-	      case PCI_VENDOR_ID_MADGE:		return "Madge Networks";
-	      case PCI_VENDOR_ID_3COM:		return "3Com";
-	      case PCI_VENDOR_ID_SMC:		return "SMC";
-	      case PCI_VENDOR_ID_AL:		return "Acer Labs";
-	      case PCI_VENDOR_ID_MITSUBISHI:	return "Mitsubishi";
-	      case PCI_VENDOR_ID_SURECOM:	return "Surecom";
-	      case PCI_VENDOR_ID_NEOMAGIC:	return "Neomagic";
-	      case PCI_VENDOR_ID_ASP:		return "Advanced System Products";
-	      case PCI_VENDOR_ID_MACRONIX:	return "Macronix";
-	      case PCI_VENDOR_ID_CERN:		return "CERN";
-	      case PCI_VENDOR_ID_NVIDIA:	return "NVidia";
-	      case PCI_VENDOR_ID_IMS:		return "IMS";
-	      case PCI_VENDOR_ID_TEKRAM2:	return "Tekram";
-	      case PCI_VENDOR_ID_TUNDRA:	return "Tundra";
-	      case PCI_VENDOR_ID_AMCC:		return "AMCC";
-	      case PCI_VENDOR_ID_INTERG:	return "Intergraphics";
-	      case PCI_VENDOR_ID_REALTEK:	return "Realtek";
-	      case PCI_VENDOR_ID_TRUEVISION:	return "Truevision";
-	      case PCI_VENDOR_ID_INIT:		return "Initio Corp";
-	      case PCI_VENDOR_ID_TTI:		return "Triones Technologies, Inc.";
-	      case PCI_VENDOR_ID_VIA:		return "VIA Technologies";
-	      case PCI_VENDOR_ID_SMC2:		return "SMC";
-	      case PCI_VENDOR_ID_VORTEX:	return "VORTEX";
-	      case PCI_VENDOR_ID_EF:		return "Efficient Networks";
-	      case PCI_VENDOR_ID_FORE:		return "Fore Systems";
-	      case PCI_VENDOR_ID_IMAGINGTECH:	return "Imaging Technology";
-	      case PCI_VENDOR_ID_PHILIPS:	return "Philips";
-	      case PCI_VENDOR_ID_CYCLONE:	return "Cyclone";
-	      case PCI_VENDOR_ID_ALLIANCE:	return "Alliance";
-	      case PCI_VENDOR_ID_VMIC:		return "VMIC";
-	      case PCI_VENDOR_ID_DIGI:		return "Digi Intl.";
-	      case PCI_VENDOR_ID_MUTECH:	return "Mutech";
-	      case PCI_VENDOR_ID_RENDITION:	return "Rendition";
-	      case PCI_VENDOR_ID_TOSHIBA:	return "Toshiba";
-	      case PCI_VENDOR_ID_RICOH:		return "Ricoh";
-	      case PCI_VENDOR_ID_ARTOP:		return "Artop Electronics";
-	      case PCI_VENDOR_ID_ZEITNET:	return "ZeitNet";
-	      case PCI_VENDOR_ID_OMEGA:		return "Omega Micro";
-	      case PCI_VENDOR_ID_LITEON:	return "LiteOn";
-	      case PCI_VENDOR_ID_NP:		return "Network Peripherals";
-	      case PCI_VENDOR_ID_ATT:		return "Lucent (ex-AT&T) Microelectronics";
-	      case PCI_VENDOR_ID_SPECIALIX:	return "Specialix";
-	      case PCI_VENDOR_ID_AURAVISION:	return "Auravision";
-	      case PCI_VENDOR_ID_IKON:		return "Ikon";
-	      case PCI_VENDOR_ID_ZORAN:		return "Zoran";
-	      case PCI_VENDOR_ID_KINETIC:	return "Kinetic";
-	      case PCI_VENDOR_ID_COMPEX:	return "Compex";
-	      case PCI_VENDOR_ID_RP:		return "Comtrol";
-	      case PCI_VENDOR_ID_CYCLADES:	return "Cyclades";
-	      case PCI_VENDOR_ID_ESSENTIAL:	return "Essential Communications";
-	      case PCI_VENDOR_ID_O2:		return "O2 Micro";
-	      case PCI_VENDOR_ID_3DFX:		return "3Dfx";
-	      case PCI_VENDOR_ID_SIGMADES:	return "Sigma Designs";
-	      case PCI_VENDOR_ID_AVM:		return "AVM";
-	      case PCI_VENDOR_ID_CCUBE:		return "C-Cube";
-	      case PCI_VENDOR_ID_DIPIX:		return "Dipix";
-	      case PCI_VENDOR_ID_STALLION:	return "Stallion Technologies";
-	      case PCI_VENDOR_ID_OPTIBASE:	return "Optibase";
-	      case PCI_VENDOR_ID_SATSAGEM:	return "SatSagem";
-	      case PCI_VENDOR_ID_HUGHES:	return "Hughes";
-	      case PCI_VENDOR_ID_ENSONIQ:	return "Ensoniq";
-	      case PCI_VENDOR_ID_ALTEON:	return "Alteon";
-	      case PCI_VENDOR_ID_PICTUREL:	return "Picture Elements";
-	      case PCI_VENDOR_ID_NVIDIA_SGS:	return "NVidia/SGS Thomson";
-	      case PCI_VENDOR_ID_CBOARDS:	return "ComputerBoards";
-	      case PCI_VENDOR_ID_SYMPHONY:	return "Symphony";
-	      case PCI_VENDOR_ID_TEKRAM:	return "Tekram";
-	      case PCI_VENDOR_ID_3DLABS:	return "3Dlabs";
-	      case PCI_VENDOR_ID_AVANCE:	return "Avance";
-	      case PCI_VENDOR_ID_NETVIN:	return "NetVin";
-	      case PCI_VENDOR_ID_S3:		return "S3 Inc.";
-	      case PCI_VENDOR_ID_DCI:		return "Decision Computer Int.";
-	      case PCI_VENDOR_ID_GENROCO:	return "Genroco";
-	      case PCI_VENDOR_ID_INTEL:		return "Intel";
-	      case PCI_VENDOR_ID_KTI:		return "KTI";
-	      case PCI_VENDOR_ID_ADAPTEC:	return "Adaptec";
-	      case PCI_VENDOR_ID_ADAPTEC2:	return "Adaptec";
-	      case PCI_VENDOR_ID_ATRONICS:	return "Atronics";
-	      case PCI_VENDOR_ID_TIGERJET:	return "TigerJet";
-	      case PCI_VENDOR_ID_ARK:		return "ARK Logic";
-	      default:				return "Unknown vendor";
-	}
-}
-
-
-static const char *pci_strdev(unsigned int vendor, unsigned int device)
-{
-	struct pci_dev_info *info;
-
-	info = 	pci_lookup_dev(vendor, device);
-	return info ? info->name : "Unknown device";
-}
-
-
-/*
- * Convert some of the configuration space registers of the device at
- * address (bus,devfn) into a string (possibly several lines each).
- * The configuration string is stored starting at buf[len].  If the
- * string would exceed the size of the buffer (SIZE), 0 is returned.
- */
-static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
-{
-	unsigned long base;
-	unsigned int class_rev, bus, devfn;
-	unsigned short vendor, device, status;
-	unsigned char bist, latency, min_gnt, max_lat;
-	int reg, len = 0;
-	const char *str;
-
-	bus   = dev->bus->number;
-	devfn = dev->devfn;
-
-	pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev);
-	pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor);
-	pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device);
-	pcibios_read_config_word (bus, devfn, PCI_STATUS, &status);
-	pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist);
-	pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency);
-	pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt);
-	pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat);
-	if (len + 80 > size) {
-		return -1;
-	}
-	len += sprintf(buf + len, "  Bus %2d, device %3d, function %2d:\n",
-		       bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
-	if (len + 80 > size) {
-		return -1;
-	}
-	len += sprintf(buf + len, "    %s: %s %s (rev %d).\n      ",
-		       pci_strclass(class_rev >> 8), pci_strvendor(vendor),
-		       pci_strdev(vendor, device), class_rev & 0xff);
-
-	if (!pci_lookup_dev(vendor, device)) {
-		len += sprintf(buf + len,
-			       "Vendor id=%x. Device id=%x.\n      ",
-			       vendor, device);
-	}
-
-	switch (status & PCI_STATUS_DEVSEL_MASK) {
-	      case PCI_STATUS_DEVSEL_FAST:   str = "Fast devsel.  "; break;
-	      case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel.  "; break;
-	      case PCI_STATUS_DEVSEL_SLOW:   str = "Slow devsel.  "; break;
-	      default:			     str = "Unknown devsel.  ";
-	}
-	if (len + strlen(str) > size) {
-		return -1;
-	}
-	len += sprintf(buf + len, str);
-
-	if (status & PCI_STATUS_FAST_BACK) {
-#		define fast_b2b_capable	"Fast back-to-back capable.  "
-		if (len + strlen(fast_b2b_capable) > size) {
-			return -1;
-		}
-		len += sprintf(buf + len, fast_b2b_capable);
-#		undef fast_b2b_capable
-	}
-
-	if (bist & PCI_BIST_CAPABLE) {
-#		define BIST_capable	"BIST capable.  "
-		if (len + strlen(BIST_capable) > size) {
-			return -1;
-		}
-		len += sprintf(buf + len, BIST_capable);
-#		undef BIST_capable
-	}
-
-	if (dev->irq) {
-		if (len + 40 > size) {
-			return -1;
-		}
-		len += sprintf(buf + len, "IRQ %d.  ", dev->irq);
-	}
-
-	if (dev->master) {
-		if (len + 80 > size) {
-			return -1;
-		}
-		len += sprintf(buf + len, "Master Capable.  ");
-		if (latency)
-		  len += sprintf(buf + len, "Latency=%d.  ", latency);
-		else
-		  len += sprintf(buf + len, "No bursts.  ");
-		if (min_gnt)
-		  len += sprintf(buf + len, "Min Gnt=%d.", min_gnt);
-		if (max_lat)
-		  len += sprintf(buf + len, "Max Lat=%d.", max_lat);
-	}
-
-	for (reg = 0; reg < 6; reg++) {
-		if (len + 40 > size) {
-			return -1;
-		}
-		base = dev->base_address[reg];
-		if (!base)
-			continue;
-
-		if (base & PCI_BASE_ADDRESS_SPACE_IO) {
-			len += sprintf(buf + len,
-				       "\n      I/O at 0x%lx [0x%lx].",
-				       base & PCI_BASE_ADDRESS_IO_MASK,
-				       dev->base_address[reg]);
-		} else {
-			const char *pref, *type = "unknown";
-
-			if (base & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-				pref = "P";
-			} else {
-				pref = "Non-p";
-			}
-			switch (base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
-			      case PCI_BASE_ADDRESS_MEM_TYPE_32:
-				type = "32 bit"; break;
-			      case PCI_BASE_ADDRESS_MEM_TYPE_1M:
-				type = "20 bit"; break;
-			      case PCI_BASE_ADDRESS_MEM_TYPE_64:
-				type = "64 bit"; break;
-			}
-			len += sprintf(buf + len,
-				       "\n      %srefetchable %s memory at "
-				       "0x%lx [0x%lx].", pref, type,
-				       base & PCI_BASE_ADDRESS_MEM_MASK,
-				       dev->base_address[reg]);
-		}
-	}
-
-	len += sprintf(buf + len, "\n");
-	return len;
-}
-
-
-/*
- * Return list of PCI devices as a character string for /proc/pci.
- * BUF is a buffer that is PAGE_SIZE bytes long.
- */
-int get_pci_list(char *buf)
-{
-	int nprinted, len, size;
-	struct pci_dev *dev;
-	static int complained = 0;
-#	define MSG "\nwarning: page-size limit reached!\n"
-
-	if (!complained) {
-		complained++;
-		printk(KERN_INFO "%s uses obsolete /proc/pci interface\n",
-			current->comm);
-	}
-
-	/* reserve same for truncation warning message: */
-	size  = PAGE_SIZE - (strlen(MSG) + 1);
-	len   = sprintf(buf, "PCI devices found:\n");
-
-	for (dev = pci_devices; dev; dev = dev->next) {
-		nprinted = sprint_dev_config(dev, buf + len, size - len);
-		if (nprinted < 0) {
-			return len + sprintf(buf + len, MSG);
-		}
-		len += nprinted;
-	}
-	return len;
-}
-
-static struct proc_dir_entry proc_old_pci = {
-	PROC_PCI, 3, "pci",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, &proc_array_inode_operations
-};
-
-void __init proc_old_pci_init(void)
-{
-	proc_register(&proc_root, &proc_old_pci);
-}
-
-#endif /* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.12/linux/drivers/pci/pci.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/pci/pci.c	Fri Aug  6 11:58:00 1999
@@ -29,8 +29,9 @@
 
 struct pci_bus pci_root;
 struct pci_dev *pci_devices = NULL;
+int pci_reverse __initdata = 0;
+
 static struct pci_dev **pci_last_dev_p = &pci_devices;
-static int pci_reverse __initdata = 0;
 
 struct pci_dev *
 pci_find_slot(unsigned int bus, unsigned int devfn)
@@ -143,25 +144,56 @@
 	unsigned int reg;
 	u32 l;
 
-	for(reg=0; reg<howmany; reg++) {
+	for(reg=0; reg < howmany; reg++) {
+		struct resource *res = dev->resource + reg;
+		unsigned int mask, newval, size;
+
+		res->name = dev->name;
 		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
 		if (l == 0xffffffff)
 			continue;
-		dev->base_address[reg] = l;
+
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), 0xffffffff);
+		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &newval);
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), l);
+
+		mask = PCI_BASE_ADDRESS_MEM_MASK;
+		if (l & PCI_BASE_ADDRESS_SPACE_IO)
+			mask = PCI_BASE_ADDRESS_IO_MASK;
+
+		newval &= mask;
+		if (!newval)
+			continue;
+
+		res->start = l & mask;
+		res->flags = l & ~mask;
+
+		size = 1;
+		do {
+			size <<= 1;
+		} while (!(size & newval));
+
+		/* 64-bit memory? */
 		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
 		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+		    	unsigned int high;
 			reg++;
-			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
-			if (l) {
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &high);
+			if (high) {
 #if BITS_PER_LONG == 64
-				dev->base_address[reg-1] |= ((unsigned long) l) << 32;
+				res->start |= ((unsigned long) high) << 32;
 #else
 				printk("PCI: Unable to handle 64-bit address for device %02x:%02x\n",
 					dev->bus->number, dev->devfn);
-				dev->base_address[reg-1] = 0;
+				res->flags = 0;
+				res->start = 0;
+				res->end = 0;
+				continue;
 #endif
 			}
 		}
+		res->end = res->start + size - 1;
+		request_resource((l & PCI_BASE_ADDRESS_SPACE_IO) ? &ioport_resource : &iomem_resource, res);
 	}
 }
 
@@ -202,6 +234,7 @@
 		dev->devfn  = devfn;
 		dev->vendor = l & 0xffff;
 		dev->device = (l >> 16) & 0xffff;
+		pci_namedevice(dev);
 
 		/* non-destructively determine if device can be a master: */
 		pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd);
@@ -419,13 +452,9 @@
 #ifdef CONFIG_PCI_QUIRKS
 	pci_quirks_init();
 #endif
-
-#ifdef CONFIG_PROC_FS
-	pci_proc_init();
-#endif
 }
 
-void __init pci_setup (char *str, int *ints)
+static int __init pci_setup(char *str)
 {
 	while (str) {
 		char *k = strchr(str, ',');
@@ -438,4 +467,7 @@
 		}
 		str = k;
 	}
+	return 1;
 }
+
+__setup("pci=", pci_setup);
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/proc.c linux/drivers/pci/proc.c
--- v2.3.12/linux/drivers/pci/proc.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/pci/proc.c	Sat Aug  7 12:59:40 1999
@@ -6,12 +6,12 @@
  *	Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
@@ -247,14 +247,15 @@
 			dev->vendor,
 			dev->device,
 			dev->irq);
-		for(i=0; i<6; i++)
+		for(i=0; i<6; i++) {
 			len += sprintf(buf+len,
 #if BITS_PER_LONG == 32
 						"\t%08lx",
 #else
 						"\t%016lx",
 #endif
-					dev->base_address[i]);
+					dev->resource[i].start | (dev->resource[i].flags & 0xf));
+		}
 		len += sprintf(buf+len,
 #if BITS_PER_LONG == 32
 					"\t%08lx",
@@ -321,7 +322,7 @@
 	return 0;
 }
 
-__initfunc(void proc_bus_pci_add(struct pci_bus *bus))
+void __init proc_bus_pci_add(struct pci_bus *bus)
 {
 	while (bus) {
 		struct pci_dev *dev;
@@ -334,15 +335,266 @@
 	}
 }
 
-__initfunc(void pci_proc_init(void))
+static const char *pci_strclass (unsigned int class)
 {
-	if (!pci_present())
-		return;
-	proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus);
-	proc_register(proc_bus_pci_dir, &proc_pci_devices);
-	proc_bus_pci_add(&pci_root);
+	switch (class >> 8) {
+	      case PCI_CLASS_NOT_DEFINED:		return "Non-VGA device";
+	      case PCI_CLASS_NOT_DEFINED_VGA:		return "VGA compatible device";
+
+	      case PCI_CLASS_STORAGE_SCSI:		return "SCSI storage controller";
+	      case PCI_CLASS_STORAGE_IDE:		return "IDE interface";
+	      case PCI_CLASS_STORAGE_FLOPPY:		return "Floppy disk controller";
+	      case PCI_CLASS_STORAGE_IPI:		return "IPI bus controller";
+	      case PCI_CLASS_STORAGE_RAID:		return "RAID bus controller";
+	      case PCI_CLASS_STORAGE_OTHER:		return "Unknown mass storage controller";
+
+	      case PCI_CLASS_NETWORK_ETHERNET:		return "Ethernet controller";
+	      case PCI_CLASS_NETWORK_TOKEN_RING:	return "Token ring network controller";
+	      case PCI_CLASS_NETWORK_FDDI:		return "FDDI network controller";
+	      case PCI_CLASS_NETWORK_ATM:		return "ATM network controller";
+	      case PCI_CLASS_NETWORK_OTHER:		return "Network controller";
+
+	      case PCI_CLASS_DISPLAY_VGA:		return "VGA compatible controller";
+	      case PCI_CLASS_DISPLAY_XGA:		return "XGA compatible controller";
+	      case PCI_CLASS_DISPLAY_OTHER:		return "Display controller";
+
+	      case PCI_CLASS_MULTIMEDIA_VIDEO:		return "Multimedia video controller";
+	      case PCI_CLASS_MULTIMEDIA_AUDIO:		return "Multimedia audio controller";
+	      case PCI_CLASS_MULTIMEDIA_OTHER:		return "Multimedia controller";
+
+	      case PCI_CLASS_MEMORY_RAM:		return "RAM memory";
+	      case PCI_CLASS_MEMORY_FLASH:		return "FLASH memory";
+	      case PCI_CLASS_MEMORY_OTHER:		return "Memory";
+
+	      case PCI_CLASS_BRIDGE_HOST:		return "Host bridge";
+	      case PCI_CLASS_BRIDGE_ISA:		return "ISA bridge";
+	      case PCI_CLASS_BRIDGE_EISA:		return "EISA bridge";
+	      case PCI_CLASS_BRIDGE_MC:			return "MicroChannel bridge";
+	      case PCI_CLASS_BRIDGE_PCI:		return "PCI bridge";
+	      case PCI_CLASS_BRIDGE_PCMCIA:		return "PCMCIA bridge";
+	      case PCI_CLASS_BRIDGE_NUBUS:		return "NuBus bridge";
+	      case PCI_CLASS_BRIDGE_CARDBUS:		return "CardBus bridge";
+	      case PCI_CLASS_BRIDGE_OTHER:		return "Bridge";
+
+	      case PCI_CLASS_COMMUNICATION_SERIAL:	return "Serial controller";
+	      case PCI_CLASS_COMMUNICATION_PARALLEL:	return "Parallel controller";
+	      case PCI_CLASS_COMMUNICATION_OTHER:	return "Communication controller";
+
+	      case PCI_CLASS_SYSTEM_PIC:		return "PIC";
+	      case PCI_CLASS_SYSTEM_DMA:		return "DMA controller";
+	      case PCI_CLASS_SYSTEM_TIMER:		return "Timer";
+	      case PCI_CLASS_SYSTEM_RTC:		return "RTC";
+	      case PCI_CLASS_SYSTEM_OTHER:		return "System peripheral";
+
+	      case PCI_CLASS_INPUT_KEYBOARD:		return "Keyboard controller";
+	      case PCI_CLASS_INPUT_PEN:			return "Digitizer Pen";
+	      case PCI_CLASS_INPUT_MOUSE:		return "Mouse controller";
+	      case PCI_CLASS_INPUT_OTHER:		return "Input device controller";
+
+	      case PCI_CLASS_DOCKING_GENERIC:		return "Generic Docking Station";
+	      case PCI_CLASS_DOCKING_OTHER:		return "Docking Station";
+
+	      case PCI_CLASS_PROCESSOR_386:		return "386";
+	      case PCI_CLASS_PROCESSOR_486:		return "486";
+	      case PCI_CLASS_PROCESSOR_PENTIUM:		return "Pentium";
+	      case PCI_CLASS_PROCESSOR_ALPHA:		return "Alpha";
+	      case PCI_CLASS_PROCESSOR_POWERPC:		return "Power PC";
+	      case PCI_CLASS_PROCESSOR_CO:		return "Co-processor";
+
+	      case PCI_CLASS_SERIAL_FIREWIRE:		return "FireWire (IEEE 1394)";
+	      case PCI_CLASS_SERIAL_ACCESS:		return "ACCESS Bus";
+	      case PCI_CLASS_SERIAL_SSA:		return "SSA";
+	      case PCI_CLASS_SERIAL_USB:		return "USB Controller";
+	      case PCI_CLASS_SERIAL_FIBER:		return "Fiber Channel";
 
-#ifdef CONFIG_PCI_OLD_PROC
-	proc_old_pci_init();
-#endif
+	      case PCI_CLASS_HOT_SWAP_CONTROLLER:	return "Hot Swap Controller";
+
+	      default:					return "Unknown class";
+	}
+}
+
+/*
+ * Convert some of the configuration space registers of the device at
+ * address (bus,devfn) into a string (possibly several lines each).
+ * The configuration string is stored starting at buf[len].  If the
+ * string would exceed the size of the buffer (SIZE), 0 is returned.
+ */
+static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
+{
+	unsigned int class_rev, bus, devfn;
+	unsigned short vendor, device, status;
+	unsigned char bist, latency, min_gnt, max_lat;
+	int reg, len = 0;
+	const char *str;
+
+	bus   = dev->bus->number;
+	devfn = dev->devfn;
+
+	pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev);
+	pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor);
+	pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device);
+	pcibios_read_config_word (bus, devfn, PCI_STATUS, &status);
+	pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist);
+	pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency);
+	pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt);
+	pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat);
+	if (len + 80 > size) {
+		return -1;
+	}
+	len += sprintf(buf + len, "  Bus %2d, device %3d, function %2d:\n",
+		       bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+	if (len + 80 > size) {
+		return -1;
+	}
+	len += sprintf(buf + len, "    %s: %s (rev %d).\n      ",
+		       pci_strclass(class_rev >> 8),
+		       dev->name,
+		       class_rev & 0xff);
+
+	switch (status & PCI_STATUS_DEVSEL_MASK) {
+	      case PCI_STATUS_DEVSEL_FAST:   str = "Fast devsel.  "; break;
+	      case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel.  "; break;
+	      case PCI_STATUS_DEVSEL_SLOW:   str = "Slow devsel.  "; break;
+	      default:			     str = "Unknown devsel.  ";
+	}
+	if (len + strlen(str) > size) {
+		return -1;
+	}
+	len += sprintf(buf + len, str);
+
+	if (status & PCI_STATUS_FAST_BACK) {
+#		define fast_b2b_capable	"Fast back-to-back capable.  "
+		if (len + strlen(fast_b2b_capable) > size) {
+			return -1;
+		}
+		len += sprintf(buf + len, fast_b2b_capable);
+#		undef fast_b2b_capable
+	}
+
+	if (bist & PCI_BIST_CAPABLE) {
+#		define BIST_capable	"BIST capable.  "
+		if (len + strlen(BIST_capable) > size) {
+			return -1;
+		}
+		len += sprintf(buf + len, BIST_capable);
+#		undef BIST_capable
+	}
+
+	if (dev->irq) {
+		if (len + 40 > size) {
+			return -1;
+		}
+		len += sprintf(buf + len, "IRQ %d.  ", dev->irq);
+	}
+
+	if (dev->master) {
+		if (len + 80 > size) {
+			return -1;
+		}
+		len += sprintf(buf + len, "Master Capable.  ");
+		if (latency)
+		  len += sprintf(buf + len, "Latency=%d.  ", latency);
+		else
+		  len += sprintf(buf + len, "No bursts.  ");
+		if (min_gnt)
+		  len += sprintf(buf + len, "Min Gnt=%d.", min_gnt);
+		if (max_lat)
+		  len += sprintf(buf + len, "Max Lat=%d.", max_lat);
+	}
+
+	for (reg = 0; reg < 6; reg++) {
+		struct resource *res = dev->resource + reg;
+		unsigned long base, end, flags;
+
+		if (len + 40 > size) {
+			return -1;
+		}
+		base = res->start;
+		end = res->end;
+		flags = res->flags;
+		if (!end)
+			continue;
+
+		if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
+			len += sprintf(buf + len,
+				       "\n      I/O at 0x%lx [0x%lx].",
+				       base, end);
+		} else {
+			const char *pref, *type = "unknown";
+
+			if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				pref = "P";
+			} else {
+				pref = "Non-p";
+			}
+			switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+			      case PCI_BASE_ADDRESS_MEM_TYPE_32:
+				type = "32 bit"; break;
+			      case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+				type = "20 bit"; break;
+			      case PCI_BASE_ADDRESS_MEM_TYPE_64:
+				type = "64 bit"; break;
+			}
+			len += sprintf(buf + len,
+				       "\n      %srefetchable %s memory at "
+				       "0x%lx [0x%lx].", pref, type,
+				       base,
+				       end);
+		}
+	}
+
+	len += sprintf(buf + len, "\n");
+	return len;
+}
+
+
+/*
+ * Return list of PCI devices as a character string for /proc/pci.
+ * BUF is a buffer that is PAGE_SIZE bytes long.
+ */
+int get_pci_list(char *buf)
+{
+	int nprinted, len, size;
+	struct pci_dev *dev;
+	static int complained = 0;
+#	define MSG "\nwarning: page-size limit reached!\n"
+
+	if (!complained) {
+		complained++;
+		printk(KERN_INFO "%s uses obsolete /proc/pci interface\n",
+			current->comm);
+	}
+
+	/* reserve same for truncation warning message: */
+	size  = PAGE_SIZE - (strlen(MSG) + 1);
+	len   = sprintf(buf, "PCI devices found:\n");
+
+	for (dev = pci_devices; dev; dev = dev->next) {
+		nprinted = sprint_dev_config(dev, buf + len, size - len);
+		if (nprinted < 0) {
+			return len + sprintf(buf + len, MSG);
+		}
+		len += nprinted;
+	}
+	return len;
 }
+
+static struct proc_dir_entry proc_old_pci = {
+	PROC_PCI, 3, "pci",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations
+};
+
+static int __init pci_proc_init(void)
+{
+	if (pci_present()) {
+		proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus);
+		proc_register(proc_bus_pci_dir, &proc_pci_devices);
+		proc_bus_pci_add(&pci_root);
+		proc_register(&proc_root, &proc_old_pci);
+	}
+	return 0;
+}
+
+__initcall(pci_proc_init);
diff -u --recursive --new-file v2.3.12/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.3.12/linux/drivers/pci/quirks.c	Thu Jan  7 09:21:53 1999
+++ linux/drivers/pci/quirks.c	Thu Aug  5 18:44:28 1999
@@ -76,7 +76,7 @@
 	{0x0	,0x0	,0x0	},
 };
 
-__initfunc(static void quirk_bridge(struct pci_dev *dev, int pos))
+static void __init quirk_bridge(struct pci_dev *dev, int pos)
 {
 	struct bridge_mapping_type *bmap;
 	unsigned char val;
@@ -108,7 +108,7 @@
 
 /* Deal with broken BIOS'es that neglect to enable passive release,
    which can cause problems in combination with the 82441FX/PPro MTRRs */
-__initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg))
+static void __init quirk_passive_release(struct pci_dev *dev, int arg)
 {
 	struct pci_dev *d = NULL;
 	unsigned char dlc;
@@ -135,7 +135,7 @@
 
 int isa_dma_bridge_buggy = 0;		/* Exported */
     
-__initfunc(static void quirk_isa_dma_hangs(struct pci_dev *dev, int arg))
+static void __init quirk_isa_dma_hangs(struct pci_dev *dev, int arg)
 {
 	if(!isa_dma_bridge_buggy)
 	{
@@ -204,7 +204,7 @@
 	{ PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs,	0x00 },
 };
 
-__initfunc(void pci_quirks_init(void))
+void __init pci_quirks_init(void)
 {
 	struct pci_dev *d;
 	int i;
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.3.12/linux/drivers/sbus/audio/audio.c	Wed May 12 08:41:15 1999
+++ linux/drivers/sbus/audio/audio.c	Fri Aug  6 11:58:00 1999
@@ -313,7 +313,7 @@
     kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
 
     /* Stop the lowlevel driver from outputing. */
-    /* drv->ops->stop_output(drv); Should not be necessary  -- DJB 5/25/98 */
+    drv->ops->stop_output(drv); 
     drv->output_active = 0;
 		  
     /* Wake up any waiting writers or syncers and return. */
@@ -669,7 +669,7 @@
   case SOUND_MIXER_WRITE_CD:
   case SOUND_MIXER_WRITE_LINE:
   case SOUND_MIXER_WRITE_IMIX:
-    if(get_user(k, arg))
+    if(COPY_IN(arg, k))
       return -EFAULT;
     tprintk(("setting input volume (0x%x)", k));
     if (drv->ops->get_input_channels)
@@ -700,7 +700,7 @@
   case SOUND_MIXER_WRITE_PCM:
   case SOUND_MIXER_WRITE_VOLUME:
   case SOUND_MIXER_WRITE_SPEAKER:
-    if(get_user(k, arg))
+    if(COPY_IN(arg, k))
 	return -EFAULT;
     tprintk(("setting output volume (0x%x)", k));
     if (drv->ops->get_output_channels)
@@ -741,7 +741,7 @@
   case SOUND_MIXER_WRITE_RECSRC: 
     if (!drv->ops->set_input_port)
       return -EINVAL;
-    if(get_user(k, arg))
+    if(COPY_IN(arg, k))
       return -EFAULT;
     /* only one should ever be selected */
     if (k & SOUND_MASK_IMIX) j = AUDIO_ANALOG_LOOPBACK;
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.3.12/linux/drivers/sbus/audio/cs4231.c	Wed Apr 28 08:47:39 1999
+++ linux/drivers/sbus/audio/cs4231.c	Fri Aug  6 11:58:00 1999
@@ -1421,7 +1421,7 @@
     status += 2;
   }
 
-  sparcaudio_input_done(drv, 1);
+  sparcaudio_input_done(drv, status);
 
   return 1;
 }
@@ -1484,26 +1484,23 @@
   cs4231_chip->perchip_info.play.active = 1;
   cs4231_chip->playing_count = 0;
 
+  cs4231_playintr(drv);
   if ((cs4231_chip->regs->dmacsr & APC_PPAUSE) || 
       !(cs4231_chip->regs->dmacsr & APC_PDMA_READY)) {
-    cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY;
-    cs4231_chip->regs->dmacsr &= ~APC_PPAUSE;
-    
-    cs4231_playintr(drv);
-
-    cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP;
+    cs4231_chip->regs->dmacsr &= ~(APC_XINT_PLAY | APC_PPAUSE);
+    cs4231_chip->regs->dmacsr |= APC_GENL_INT | APC_XINT_ENA | APC_XINT_PLAY
+      | APC_XINT_GENL | APC_XINT_PENA | APC_PDMA_READY;
     cs4231_enable_play(drv);
-
+  
     cs4231_ready(drv);
-  } else 
-    cs4231_playintr(drv);
+  }
 }
 
 #ifdef EB4231_SUPPORT
 static void eb4231_stop_output(struct sparcaudio_driver *drv)
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-  int dcsr;
+  unsigned int dcsr;
 
   dprintk(("eb4231_stop_output: dcsr 0x%x dacr 0x%x dbcr %d\n",
            readl(&cs4231_chip->eb2p->dcsr),
@@ -1525,6 +1522,7 @@
 
   /* Else subsequent speed setting changes are ignored by the chip. */
   cs4231_disable_play(drv);
+  cs4231_chip->perchip_info.play.active = 0;
 }
 #endif
 
@@ -1547,9 +1545,14 @@
     cs4231_chip->output_next_dma_handle = 0;
     cs4231_chip->output_next_dma_size = 0;
   }
-#if 0 /* Not safe without shutting off the DMA controller as well. -DaveM */
+#if 1 /* Not safe without shutting off the DMA controller as well. -DaveM */
   /* Else subsequent speed setting changes are ignored by the chip. */
+  cs4231_chip->regs->dmacsr &= ~(APC_GENL_INT | APC_XINT_ENA | APC_XINT_PLAY 
+                                 | APC_XINT_GENL | APC_PDMA_READY 
+                                 | APC_XINT_PENA | APC_PPAUSE );
+  printk("in cs4231_stop_output: 0x%x\n", cs4231_chip->regs->dmacsr);
   cs4231_disable_play(drv);
+  cs4231_chip->perchip_info.play.active = 0;
 #endif
 }
 
@@ -1635,6 +1638,68 @@
   cs4231_pollinput(drv);
 }
 
+#ifdef EB4231_SUPPORT
+static void eb4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, 
+                               unsigned long count)
+{
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  unsigned int dcsr;
+
+  cs4231_chip->input_ptr = buffer;
+  cs4231_chip->input_size = count;
+
+  if (cs4231_chip->perchip_info.record.active || 
+      (cs4231_chip->perchip_info.record.pause))
+    return;
+
+  cs4231_ready(drv);
+
+  cs4231_chip->perchip_info.record.active = 1;
+  cs4231_chip->recording_count = 0;
+
+  dcsr = readl(&cs4231_chip->eb2c->dcsr);
+  if (!(dcsr & EBUS_DCSR_EN_DMA)) {
+    writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2c->dcsr));
+    writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2c->dcsr));
+
+    eb4231_recintr(drv);
+
+    writel(EBUS_DCSR_BURST_SZ_16 |
+           (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT),
+           &(cs4231_chip->eb2c->dcsr));
+
+    cs4231_enable_rec(drv);
+    cs4231_ready(drv);
+  } else
+    eb4231_recintr(drv);
+}
+
+static void eb4231_stop_input(struct sparcaudio_driver *drv)
+{
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  unsigned int dcsr;
+
+  cs4231_chip->perchip_info.record.active = 0;
+
+  cs4231_chip->input_ptr = NULL;
+  cs4231_chip->input_size = 0;
+  if (cs4231_chip->input_dma_handle) {
+    cs4231_chip->input_dma_handle = 0;
+    cs4231_chip->input_dma_size = 0;
+  }
+  if (cs4231_chip->input_next_dma_handle) {
+    cs4231_chip->input_next_dma_handle = 0;
+    cs4231_chip->input_next_dma_size = 0;
+  }
+
+  dcsr = readl(&(cs4231_chip->eb2c->dcsr));
+  if (dcsr & EBUS_DCSR_EN_DMA)
+    writel(dcsr & ~EBUS_DCSR_EN_DMA, &(cs4231_chip->eb2c->dcsr));
+
+  cs4231_disable_rec(drv);
+}
+#endif
+
 static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value)
 {
         struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
@@ -1763,13 +1828,25 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   int dummy;
   
-  /* Read status. */
-  dummy = readl(&cs4231_chip->eb2c->dcsr);
+  /* Clear the interrupt. */
+  dummy = readl(&(cs4231_chip->eb2c->dcsr));
+  writel(dummy, &(cs4231_chip->eb2c->dcsr));
 
-  cs4231_chip->perchip_info.record.samples += 
-          cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), 
-                                       cs4231_chip->reclen);
-  eb4231_recintr(drv);
+  if ((dummy & EBUS_DCSR_TC) != 0
+      /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) {
+    cs4231_chip->perchip_info.record.samples += 
+      cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), 
+                                   cs4231_chip->reclen);
+    eb4231_recintr(drv);
+  }
+
+  if ((dummy & EBUS_DCSR_A_LOADED) == 0) {
+    cs4231_chip->perchip_info.record.active = 0;
+    eb4231_recintr(drv);
+#if 1
+    eb4231_getsamplecount(drv, cs4231_chip->reclen, 1);
+#endif
+  }
 }
 
 /* ebus audio play interrupt handler. */
@@ -1797,7 +1874,6 @@
   }
 
   if((dummy & EBUS_DCSR_A_LOADED) == 0) {
-    cs4231_chip->perchip_info.play.active = 0;
     eb4231_playintr(drv);
 
     eb4231_getsamplecount(drv, cs4231_chip->playlen, 0);
@@ -1822,13 +1898,11 @@
    * if anything since we may be doing shared interrupts 
    */
 
-  if (dummy & APC_PLAY_INT) {
-    if (dummy & APC_XINT_PNVA) {
+  if (dummy & (APC_PLAY_INT|APC_XINT_PNVA|APC_XINT_PLAY|APC_XINT_EMPT|APC_XINT_PEMP)) {
       cs4231_chip->perchip_info.play.samples += 
 	cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
 				     cs4231_chip->playlen); 
       cs4231_playintr(drv);
-    } 
     /* Any other conditions we need worry about? */
   }
 
@@ -1853,6 +1927,7 @@
   }
 
   if (dummy & APC_XINT_EMPT) {
+#if 0 /* Call to stop_output from midlevel will get this */
     if (!cs4231_chip->output_next_dma_handle) {
       cs4231_chip->regs->dmacsr |= (APC_PPAUSE);
       cs4231_disable_play(drv);
@@ -1860,6 +1935,7 @@
     }
     cs4231_chip->perchip_info.play.active = 0;
     cs4231_playintr(drv);
+#endif
 
     cs4231_getsamplecount(drv, cs4231_chip->playlen, 0);
   }
@@ -1937,8 +2013,8 @@
 	cs4231_ioctl,
 	eb4231_start_output,
 	eb4231_stop_output,
-	cs4231_start_input,
-        cs4231_stop_input,
+	eb4231_start_input,
+        eb4231_stop_input,
 	cs4231_audio_getdev,
         cs4231_set_output_volume,
         cs4231_get_output_volume,
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.3.12/linux/drivers/sbus/char/bpp.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/sbus/char/bpp.c	Fri Aug  6 11:58:00 1999
@@ -148,18 +148,18 @@
  */
 struct bpp_regs {
       /* DMA registers */
-      __u32 p_csr;		/* DMA Control/Status Register */
-      __u32 p_addr;		/* Address Register */
-      __u32 p_bcnt;		/* Byte Count Register */
-      __u32 p_tst_csr;		/* Test Control/Status (DMA2 only) */
+      __volatile__ __u32 p_csr;		/* DMA Control/Status Register */
+      __volatile__ __u32 p_addr;	/* Address Register */
+      __volatile__ __u32 p_bcnt;	/* Byte Count Register */
+      __volatile__ __u32 p_tst_csr;	/* Test Control/Status (DMA2 only) */
       /* Parallel Port registers */
-      __u16 p_hcr;		/* Hardware Configuration Register */
-      __u16 p_ocr;		/* Operation Configuration Register */
-      __u8 p_dr;		/* Parallel Data Register */
-      __u8 p_tcr;		/* Transfer Control Register */
-      __u8 p_or;		/* Output Register */
-      __u8 p_ir;		/* Input Register */
-      __u16 p_icr;		/* Interrupt Control Register */
+      __volatile__ __u16 p_hcr;		/* Hardware Configuration Register */
+      __volatile__ __u16 p_ocr;		/* Operation Configuration Register */
+      __volatile__ __u8 p_dr;		/* Parallel Data Register */
+      __volatile__ __u8 p_tcr;		/* Transfer Control Register */
+      __volatile__ __u8 p_or;		/* Output Register */
+      __volatile__ __u8 p_ir;		/* Input Register */
+      __volatile__ __u16 p_icr;		/* Interrupt Control Register */
 };
 
 /* P_CSR.  Bits of type RW1 are cleared with writting '1'. */
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.3.12/linux/drivers/sbus/char/sunkbd.c	Wed May 12 08:41:15 1999
+++ linux/drivers/sbus/char/sunkbd.c	Mon Aug  2 22:07:16 1999
@@ -79,11 +79,6 @@
 
 struct l1a_kbd_state l1a_state = { 0, 0 };
 
-/* Dummy function for now, we need it to link.  -DaveM */
-void kbd_reset_setup(char *str, int *ints)
-{
-}
-
 #ifndef CONFIG_PCI
 DECLARE_WAIT_QUEUE_HEAD(keypress_wait);
 #endif
@@ -1305,7 +1300,7 @@
 	p = buffer;
 	for (; p < end && kbd_head != kbd_tail;){
 #ifdef CONFIG_SPARC32_COMPAT
-		if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (current->thread.flags & SPARC_FLAG_32BIT) {
 			copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], 
 					 sizeof(Firm_event)-sizeof(struct timeval), -EFAULT);
 			p += sizeof(Firm_event)-sizeof(struct timeval);
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.3.12/linux/drivers/sbus/char/sunmouse.c	Wed May 12 08:41:15 1999
+++ linux/drivers/sbus/char/sunmouse.c	Mon Aug  2 22:07:16 1999
@@ -386,7 +386,7 @@
 		
 		while (p < end && !queue_empty ()){
 #ifdef CONFIG_SPARC32_COMPAT
-			if (current->tss.flags & SPARC_FLAG_32BIT) {
+			if (current->thread.flags & SPARC_FLAG_32BIT) {
 				Firm_event *q = get_from_queue();
 				
 				copy_to_user_ret((Firm_event *)p, q, 
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.3.12/linux/drivers/sbus/char/zs.c	Wed May 12 08:41:15 1999
+++ linux/drivers/sbus/char/zs.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.42 1999/05/12 11:15:26 davem Exp $
+/* $Id: zs.c,v 1.43 1999/07/17 06:03:58 zaitcev Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1844,7 +1844,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.42 $";
+	char *revision = "$Revision: 1.43 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2012,9 +2012,8 @@
 		/* Can use the prom for other machine types */
 		zsnode = prom_getchild(prom_root_node);
 		if (sparc_cpu_model == sun4d) {
-			int node;
 			int no = 0;
-			
+
 			tmpnode = zsnode;
 			zsnode = 0;
 			bbnode = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.3.12/linux/drivers/sbus/sbus.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/sbus/sbus.c	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.77 1999/05/29 06:25:57 davem Exp $
+/* $Id: sbus.c,v 1.78 1999/07/23 02:00:27 davem Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.3.12/linux/drivers/scsi/53c7,8xx.c	Thu May 14 18:48:16 1998
+++ linux/drivers/scsi/53c7,8xx.c	Mon Aug  9 10:23:09 1999
@@ -1198,10 +1198,10 @@
  *
  */
 
-__initfunc(static int 
+static int  __init 
 normal_init (Scsi_Host_Template *tpnt, int board, int chip, 
     u32 base, int io_port, int irq, int dma, int pci_valid, 
-    unsigned char pci_bus, unsigned char pci_device_fn, long long options)) {
+    unsigned char pci_bus, unsigned char pci_device_fn, long long options){
     struct Scsi_Host *instance;
     struct NCR53c7x0_hostdata *hostdata;
     char chip_str[80];
@@ -1411,9 +1411,9 @@
  *
  */
 
-__initfunc(static int 
+static int  __init 
 ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip, 
-    unsigned char bus, unsigned char device_fn, long long options)) {
+    unsigned char bus, unsigned char device_fn, long long options){
     unsigned short command;
 #ifdef LINUX_1_2
     unsigned long
@@ -1445,8 +1445,8 @@
 		"	 perhaps you specified an incorrect PCI bus, device, or function.\n", error);
 	return -1;
     }
-    io_port = pdev->base_address[0];
-    base = pdev->base_address[1];
+    io_port = pdev->resource[0].start;
+    base = pdev->resource[1].start;
     irq = pdev->irq;
 
     /* If any one ever clones the NCR chips, this will have to change */
@@ -1560,8 +1560,8 @@
  *
  */
 
-__initfunc(int 
-NCR53c7xx_detect(Scsi_Host_Template *tpnt)) {
+int __init 
+NCR53c7xx_detect(Scsi_Host_Template *tpnt){
     int i;
     int current_override;
     int count;			/* Number of boards detected */
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.3.12/linux/drivers/scsi/53c7xx.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/scsi/53c7xx.c	Mon Aug  9 12:32:28 1999
@@ -296,6 +296,10 @@
  */
 #undef inb
 #undef outb
+#undef inw
+#undef outw
+#undef inl
+#undef outl
 #define inb(x)          1
 #define inw(x)          1
 #define inl(x)          1
@@ -1207,7 +1211,7 @@
     memset((void *)instance->hostdata[0], 0, 8192);
     cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
     cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
-    kernel_set_cachemode(instance->hostdata[0], 8192, KERNELMAP_NOCACHE_SER);
+    kernel_set_cachemode(instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
 
     /* FIXME : if we ever support an ISA NCR53c7xx based board, we
        need to check if the chip is running in a 16 bit mode, and if so 
@@ -1897,7 +1901,7 @@
     if (left < 0) 
 	printk("scsi%d: loop detected in ncr reconncect list\n",
 	    host->host_no);
-    else if (ncr_search) 
+    else if (ncr_search) {
 	if (found)
 	    printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
 		host->host_no, c->pid);
@@ -1908,6 +1912,7 @@
 /* If we're at the tail end of the issue queue, update that pointer too. */
 	    found = 1;
 	}
+    }
 
     /*
      * Traverse the host running list until we find this command or discover
@@ -2958,14 +2963,14 @@
     	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
     else
     	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
-#if 0
-    /* Following disables snooping - run with caches disabled at first */
+    /* Following disables snooping - snooping is not required, as non-
+     * cached pages are used for shared data, and appropriate use is
+     * made of cache_push/cache_clear.  Indeed, for 68060
+     * enabling snooping causes disk corruption of ext2fs free block
+     * bitmaps and the like.  If you have a 68060 with snooping hardwared
+     * on, then you need to enable CONFIG_060_WRITETHROUGH.
+     */
     NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
-#else
-    /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating
-     * cache lines. */
-    NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0);
-#endif
     /* Actually burst of eight, according to my 53c710 databook */
     NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
     NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
@@ -3028,10 +3033,10 @@
 static void
 my_free_page (void *addr, int dummy)
 {
-    /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+    /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
      * XXX may be invalid (CONFIG_060_WRITETHROUGH)
      */
-    kernel_set_cachemode((u32)addr, 4096, KERNELMAP_FULL_CACHING);
+    kernel_set_cachemode((u32)addr, 4096, IOMAP_FULL_CACHING);
     free_page ((u32)addr);
 }
 
@@ -3087,7 +3092,7 @@
         memset((void *)real, 0, 4096);
         cache_push(virt_to_phys((void *)real), 4096);
         cache_clear(virt_to_phys((void *)real), 4096);
-        kernel_set_cachemode(real, 4096, KERNELMAP_NOCACHE_SER);
+        kernel_set_cachemode(real, 4096, IOMAP_NOCACHE_SER);
 	tmp = ROUNDUP(real, void *);
 #ifdef FORCE_DSA_ALIGNMENT
 	{
@@ -3190,7 +3195,6 @@
     case MODE_SELECT: 
     case WRITE_6:
     case WRITE_10:
-    case START_STOP: /* also SCAN, which may do DATA OUT */
 #if 0
 	printk("scsi%d : command is ", host->host_no);
 	print_command(cmd->cmnd);
@@ -3211,6 +3215,7 @@
      */
     case TEST_UNIT_READY:
     case ALLOW_MEDIUM_REMOVAL:
+    case START_STOP:
     	datain = dataout = 0;
 	break;
     /*
@@ -5945,11 +5950,12 @@
 	    	}
     	    }
 	}
-	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) 
+	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
 	    if (stage == 0)
 	    	++stage;
 	    else if (stage == 3)
 		break;
+	}
     }
     hostdata->state = STATE_HALTED;
     restore_flags(flags);
@@ -6090,10 +6096,10 @@
     if (hostdata->events) 
 	vfree ((void *)hostdata->events);
 
-    /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+    /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
      * XXX may be invalid (CONFIG_060_WRITETHROUGH)
      */
-    kernel_set_cachemode((u32)hostdata, 8192, KERNELMAP_FULL_CACHING);
+    kernel_set_cachemode((u32)hostdata, 8192, IOMAP_FULL_CACHING);
     free_pages ((u32)hostdata, 1);
     return 1;
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- v2.3.12/linux/drivers/scsi/AM53C974.c	Mon Jan 11 13:46:47 1999
+++ linux/drivers/scsi/AM53C974.c	Mon Aug  9 10:23:09 1999
@@ -1,4 +1,5 @@
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -659,7 +660,7 @@
 * 
 * Returns : number of host adapters detected
 **************************************************************************/
-__initfunc(int AM53C974_detect(Scsi_Host_Template * tpnt))
+int __init AM53C974_detect(Scsi_Host_Template * tpnt)
 {
 	int count = 0;		/* number of boards detected */
 
@@ -686,7 +687,7 @@
 *       set up by the BIOS (as reflected by contents of register CNTLREG1).
 *       This is the only BIOS assistance we need.
 **************************************************************************/
-__initfunc(static int AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev))
+static int __init  AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev)
 {
 	AM53C974_local_declare();
 	int i, j;
@@ -701,7 +702,7 @@
 	instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata));
 	hostdata = (struct AM53C974_hostdata *) instance->hostdata;
 	instance->base = NULL;
-	instance->io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+	instance->io_port = pdev->resource[0].start;
 	instance->irq = pdev->irq;
 	instance->dma_channel = -1;
 	AM53C974_setio(instance);
@@ -2467,5 +2468,9 @@
 #ifdef MODULE
 static Scsi_Host_Template driver_template = AM53C974;
 
+/* You can specify overrides=a,b,c,d in the same format at AM53C974=a,b,c,d
+   on boot up */
+   
+MODULE_PARM(overrides, "1-32i");
 #include "scsi_module.c"
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.3.12/linux/drivers/scsi/BusLogic.c	Mon Aug 17 01:01:01 1998
+++ linux/drivers/scsi/BusLogic.c	Fri Aug  6 11:43:09 1999
@@ -781,8 +781,8 @@
       unsigned char Bus = PCI_Device->bus->number;
       unsigned char Device = PCI_Device->devfn >> 3;
       unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = PCI_Device->base_address[0];
-      unsigned long BaseAddress1 = PCI_Device->base_address[1];
+      unsigned long BaseAddress0 = PCI_Device->resource[0].start;
+      unsigned long BaseAddress1 = PCI_Device->resource[1].start;
       BusLogic_IO_Address_T IO_Address =
 	BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
       BusLogic_PCI_Address_T PCI_Address =
@@ -987,7 +987,7 @@
       unsigned char Device = PCI_Device->devfn >> 3;
       unsigned int IRQ_Channel = PCI_Device->irq;
       BusLogic_IO_Address_T IO_Address =
-	PCI_Device->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+	PCI_Device->resource[0].start & PCI_BASE_ADDRESS_IO_MASK;
       if (IO_Address == 0 || IRQ_Channel == 0) continue;
       for (i = 0; i < BusLogic_ProbeInfoCount; i++)
 	{
@@ -1030,8 +1030,8 @@
       unsigned char Bus = PCI_Device->bus->number;
       unsigned char Device = PCI_Device->devfn >> 3;
       unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = PCI_Device->base_address[0];
-      unsigned long BaseAddress1 = PCI_Device->base_address[1];
+      unsigned long BaseAddress0 = PCI_Device->resource[0].start;
+      unsigned long BaseAddress1 = PCI_Device->resource[1].start;
       BusLogic_IO_Address_T IO_Address =
 	BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
       BusLogic_PCI_Address_T PCI_Address =
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.3.12/linux/drivers/scsi/NCR5380.c	Thu Apr 15 05:45:12 1999
+++ linux/drivers/scsi/NCR5380.c	Mon Aug  9 10:25:01 1999
@@ -736,12 +736,12 @@
 
 static int probe_irq __initdata = 0;
 
-__initfunc(static void probe_intr(int irq, void *dev_id, struct pt_regs *regs))
+static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	probe_irq = irq;
 }
 
-__initfunc(static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible))
+static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
 {
 	NCR5380_local_declare();
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
@@ -797,7 +797,7 @@
  * Inputs : instance, pointer to this instance.  Unused.
  */
 
-__initfunc(static void NCR5380_print_options(struct Scsi_Host *instance))
+static void __init NCR5380_print_options(struct Scsi_Host *instance)
 {
 	printk(" generic options"
 #ifdef AUTOPROBE_IRQ
@@ -1018,7 +1018,7 @@
  * 
  */
 
-__initfunc(static void NCR5380_init(struct Scsi_Host *instance, int flags))
+static void __init NCR5380_init(struct Scsi_Host *instance, int flags)
 {
 	NCR5380_local_declare();
 	int i, pass;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- v2.3.12/linux/drivers/scsi/NCR53c406a.c	Fri Jan 15 14:41:04 1999
+++ linux/drivers/scsi/NCR53c406a.c	Mon Aug  9 10:25:01 1999
@@ -461,8 +461,8 @@
 }
 #endif USE_PIO
 
-__initfunc(int 
-NCR53c406a_detect(Scsi_Host_Template * tpnt)){
+int  __init 
+NCR53c406a_detect(Scsi_Host_Template * tpnt){
     struct Scsi_Host *shpnt;
 #ifndef PORT_BASE
     int i;
@@ -593,7 +593,7 @@
 }
 
 /* called from init/main.c */
-__initfunc(void NCR53c406a_setup(char *str, int *ints))
+void __init NCR53c406a_setup(char *str, int *ints)
 {
     static size_t setup_idx = 0;
     size_t i;
@@ -1022,7 +1022,7 @@
     outb(SYNC_MODE, SYNCOFF);   /* synchronous mode */  
 }
 
-__initfunc(void calc_port_addr(void))
+void __init calc_port_addr(void)
 {
     /* Control Register Set 0 */
     TC_LSB		= (port_base+0x00);
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v2.3.12/linux/drivers/scsi/README.st	Sat May 22 14:50:07 1999
+++ linux/drivers/scsi/README.st	Mon Aug  9 10:23:42 1999
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Sun Apr 18 13:24:43 1999 by makisara@home
+Last modified: Sat Aug  7 13:52:16 1999 by makisara@kai.makisara.local
 
 
 BASICS
@@ -130,22 +130,26 @@
 2^n * (page size). Because of this the actual buffer size may be
 larger than the buffer size specified with ST_BUFFER_BLOCKS.
 
-Allocation of the buffers is done at run-time when they are
-needed. Allocation of the specified number of buffers can be done at
-initialization if ST_RUNTIME_BUFFERS is defined non-zero. The
-advantage of run-time allocation is that memory is not wasted for
-buffers not being used. The disadvantage is that there may not be
-memory available at the time when a buffer is needed for the first
-time (once a buffer is allocated, it is not released).
-
-The maximum number of buffers allocated at initialization is defined by
-ST_MAX_BUFFERS. One buffer is allocated for each drive detected when
-the driver is initialized up to the maximum. The minimum number of
-allocated buffers is ST_EXTRA_DEVS (in hosts.h). This ensures some
-functionality also for the drives found after tape driver
-initialization (a SCSI adapter driver is loaded as a module). The
-default for ST_EXTRA_DEVS is two. The driver tries to allocate new
-buffers at run-time if necessary.
+A small number of buffers are allocated at driver initialisation. The
+maximum number of these buffers is defined by ST_MAX_BUFFERS. The
+maximum can be changed with kernel or module startup options. One
+buffer is allocated for each drive detected when the driver is
+initialized up to the maximum. The minimum number of allocated buffers
+is ST_EXTRA_DEVS (in hosts.h) (unless this number exceeds the defined
+maximum). This ensures some functionality also for the drives found
+after tape driver initialization (a SCSI adapter driver is loaded as a
+module). The default for ST_EXTRA_DEVS is two.
+
+The driver tries to allocate new buffers at run-time if
+necessary. These buffers are freed after use. If the maximum number of
+initial buffers is set to zero, all buffer allocation is done at
+run-time. The advantage of run-time allocation is that memory is not
+wasted for buffers not being used. The disadvantage is that there may
+not be memory available at the time when a buffer is needed for the
+first time (once a buffer is allocated, it is not released). This risk
+should not be big if the tape drive is connected to a PCI adapter that
+supports scatter/gather (the allocation is not limited to "DMA memory"
+and the buffer can be composed of several fragments).
 
 The threshold for triggering asynchronous write in fixed block mode
 is defined by ST_WRITE_THRESHOLD. This may be optimized for each
@@ -178,31 +182,43 @@
 extending the buffer will always fail.
 
 
-BOOT TIME CONFIGURATION
+MODULE PARAMETERS
 
 The buffer size, write threshold, and the maximum number of allocated buffers
-are configurable at boot time using, e.g., the LILO command line. The option
-syntax is the following:
+are configurable when the driver is loaded as a module. The keywords are:
+
+buffer_kbs=xxx             the buffer size in kilobytes is set to xxx
+write_threshold_kbs=xxx    the write threshold in kilobytes set to xxx
+max_buffers=xxx            the maximum number of tape buffer set to xxx
+max_sg_segs=xxx		   the maximum number of scatter/gather
+			   segments
+
+Note that if the buffer size is changed but the write threshold is not
+set, the write threshold is set to the new buffer size - 2 kB.
+
+
+BOOT TIME CONFIGURATION
+
+If the driver is compiled into the kernel, the same parameters can be
+also set using, e.g., the LILO command line. The preferred syntax is
+to use the same keywords as when loading the driver as module. If
+several parameters are set, the keyword-value pairs are separated with
+a comma (no spaces allowed). A colon can be used instead of the equal
+mark. The definition is prepended by the string st=. Here is an
+example:
 
-           st=aa[,bb[,cc]]
+	st=buffer_kbs:64,max_buffers:2
+
+The following syntax used by the old kernel versions is also supported:
+
+           st=aa[,bb[,cc[,dd]]]
 
 where
   aa is the buffer size in 1024 byte units
   bb is the write threshold in 1024 byte units
   cc is the maximum number of tape buffers to allocate (the number of
         buffers is bounded also by the number of drives detected)
-
-
-MODULE PARAMETERS
-
-The same parameters can be also set when the driver is loaded as a
-module. The keywords are:
-
-buffer_kbs=xxx             the buffer size in kilobytes is set to xxx
-write_threshold_kbs=xxx    the write threshold in kilobytes set to xxx
-max_buffers=xxx            the maximum number of tape buffer set to xxx
-max_sg_segs=xxx		   the maximum number of scatter/gather
-			   segments
+  dd is the maximum number of scatter/gather segments
 
 
 IOCTLS
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.3.12/linux/drivers/scsi/advansys.c	Tue Dec 29 11:35:48 1998
+++ linux/drivers/scsi/advansys.c	Thu Aug  5 15:07:42 1999
@@ -4370,7 +4370,7 @@
                     ASC_DBG2(2,
                         "advansys_detect: devfn %d, bus number %d\n",
                         pci_devp->devfn, pci_devp->bus->number);
-                    iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
+                    iop = pci_devp->resource[0].start;
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
                         pci_devp->vendor, pci_devp->device);
@@ -4484,7 +4484,7 @@
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
-                pci_memory_address = pci_devp->base_address[1];
+                pci_memory_address = pci_devp->resource[1].start;
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.12/linux/drivers/scsi/aic7xxx.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/scsi/aic7xxx.c	Wed Aug  4 22:53:14 1999
@@ -9536,10 +9536,8 @@
           temp_p->pdev = pdev;
           temp_p->pci_bus = pdev->bus->number;
           temp_p->pci_device_fn = pdev->devfn;
-          temp_p->base = pdev->base_address[0];
-          temp_p->mbase = pdev->base_address[1];
-          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
-          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          temp_p->base = pdev->resource[0].start;
+          temp_p->mbase = pdev->resource[1].start;
           current_p = list_p;
 	  while(current_p)
 	  {
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.3.12/linux/drivers/scsi/eata.c	Fri Oct  9 11:56:59 1998
+++ linux/drivers/scsi/eata.c	Mon Aug  9 10:25:01 1999
@@ -516,7 +516,6 @@
 #define ASOK              0x00
 #define ASST              0x01
 
-#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
 #define YESNO(a) ((a) ? 'y' : 'n')
 #define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
 
@@ -829,8 +828,8 @@
    return FALSE;
 }
 
-__initfunc (static inline int
-            get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
+static inline int __init 
+get_pci_irq(unsigned long port_base, unsigned char *apic_irq){
 
 #if defined(CONFIG_PCI)
 
@@ -867,8 +866,8 @@
    return FALSE;
 }
 
-__initfunc (static inline int port_detect \
-      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+static inline int __init port_detect \
+      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt){
    unsigned char irq, dma_channel, subversion, i;
    unsigned char protocol_rev, apic_irq;
    struct eata_info info;
@@ -1152,7 +1151,7 @@
    return TRUE;
 }
 
-__initfunc (void eata2x_setup(char *str, int *ints)) {
+void  __init eata2x_setup(char *str, int *ints){
    int i, argc = ints[0];
    char *cur = str, *pc;
 
@@ -1188,7 +1187,7 @@
    return;
 }
 
-__initfunc (static void add_pci_ports(void)) {
+static void __init add_pci_ports(void){
 
 #if defined(CONFIG_PCI)
 
@@ -1254,7 +1253,7 @@
    return;
 }
 
-__initfunc (int eata2x_detect(Scsi_Host_Template *tpnt)) {
+int __init eata2x_detect(Scsi_Host_Template *tpnt){
    unsigned int j = 0, k;
    IRQ_FLAGS
 
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.3.12/linux/drivers/scsi/eata_dma.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/scsi/eata_dma.c	Thu Aug  5 15:08:56 1999
@@ -1414,12 +1414,12 @@
 	    DBG(DBG_PROBE && DBG_PCI, 
 		printk("eata_dma: find_PCI, HBA at %s\n", dev->name));
 	    pci_set_master(dev);
-	    base = dev->base_address[0];
+	    base = dev->resource[0].flags;
 	    if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) {
 		printk("eata_dma: invalid base address of device %s\n", dev->name);
 		continue;
 	    }
-	    base &= PCI_BASE_ADDRESS_IO_MASK;
+	    base = dev->resource[0].start;
             /* EISA tag there ? */
 	    pal1 = inb(base);
 	    pal2 = inb(base + 1);
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.3.12/linux/drivers/scsi/eata_pio.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/scsi/eata_pio.c	Thu Aug  5 15:08:56 1999
@@ -890,12 +890,12 @@
 	    DBG(DBG_PROBE && DBG_PCI, 
 		printk("eata_pio: find_PCI, HBA at %s\n", dev->name));
 	    pci_set_master(dev);
-	    base = dev->base_address[0];
+	    base = dev->resource[0].flags;
 	    if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) {
 		printk("eata_pio: invalid base address of device %s\n", dev->name);
 		continue;
 	    }
-	    base &= PCI_BASE_ADDRESS_IO_MASK;
+	    base = dev->resource[0].start;
             /* EISA tag there ? */
 	    if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
 		continue;   /* Jep, it's forced, so move on  */
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v2.3.12/linux/drivers/scsi/fdomain.c	Tue Dec 29 11:44:53 1998
+++ linux/drivers/scsi/fdomain.c	Mon Aug  9 10:25:01 1999
@@ -840,14 +840,14 @@
    /* We now have the appropriate device function for the FD board so we
       just read the PCI config info from the registers.  */
 
-   pci_base = pdev->base_address[0];
+   pci_base = pdev->resource[0].start;
    pci_irq = pdev->irq;
 
    /* Now we have the I/O base address and interrupt from the PCI
       configuration registers. */
 
    *irq    = pci_irq;
-   *iobase = (pci_base & PCI_BASE_ADDRESS_IO_MASK);
+   *iobase = pci_base;
 
 #if DEBUG_DETECT
    printk( "scsi: <fdomain> TMC-3260 detect:"
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.3.12/linux/drivers/scsi/g_NCR5380.c	Sun Dec 27 10:53:45 1998
+++ linux/drivers/scsi/g_NCR5380.c	Mon Aug  9 10:25:01 1999
@@ -158,7 +158,7 @@
  *
  */
 
-__initfunc(static void internal_setup(int board, char *str, int *ints)) {
+static void __init internal_setup(int board, char *str, int *ints){
     static int commandline_current = 0;
     switch (board) {
     case BOARD_NCR5380:
@@ -204,7 +204,7 @@
  * 	equal to the number of ints.
  */
 
-__initfunc(void generic_NCR5380_setup (char *str, int *ints)) {
+void __init generic_NCR5380_setup (char *str, int *ints){
     internal_setup (BOARD_NCR5380, str, ints);
 }
 
@@ -217,7 +217,7 @@
  * 	equal to the number of ints.
  */
 
-__initfunc(void generic_NCR53C400_setup (char *str, int *ints)) {
+void __init generic_NCR53C400_setup (char *str, int *ints){
     internal_setup (BOARD_NCR53C400, str, ints);
 }
 
@@ -259,7 +259,7 @@
  *
  */
 
-__initfunc(int generic_NCR5380_detect(Scsi_Host_Template * tpnt)) {
+int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){
     static int current_override = 0;
     int count, i;
     u_int *ports;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.3.12/linux/drivers/scsi/gdth.c	Mon Apr 12 09:56:16 1999
+++ linux/drivers/scsi/gdth.c	Mon Aug  9 10:25:01 1999
@@ -598,7 +598,7 @@
 
 /* controller search and initialization functions */
 
-__initfunc (static int gdth_search_eisa(ushort eisa_adr))
+static int __init gdth_search_eisa(ushort eisa_adr)
 {
     ulong32 id;
     
@@ -616,7 +616,7 @@
 }
 
 
-__initfunc (static int gdth_search_isa(ulong32 bios_adr))
+static int __init gdth_search_isa(ulong32 bios_adr)
 {
     void *addr;
     ulong32 id;
@@ -632,7 +632,7 @@
 }
 
 
-__initfunc (static int gdth_search_pci(gdth_pci_str *pcistr))
+static int __init gdth_search_pci(gdth_pci_str *pcistr)
 {
     ulong32 base0, base1, base2;
     ushort device_id, cnt;
@@ -651,7 +651,6 @@
         if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
             device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
             continue;
-#if LINUX_VERSION_CODE >= 0x2015C
         pdev = NULL;
         while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) 
                != NULL) {
@@ -663,15 +662,15 @@
             pcistr[cnt].bus = pdev->bus->number;
             pcistr[cnt].device_fn = pdev->devfn;
             pcistr[cnt].irq = pdev->irq;
-            base0 = pdev->base_address[0];
-            base1 = pdev->base_address[1];
-            base2 = pdev->base_address[2];
+            base0 = pdev->resource[0].flags;
+            base1 = pdev->resource[1].flags;
+            base2 = pdev->resource[2].flags;
             if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
                 device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
                 if ((base0 & PCI_BASE_ADDRESS_SPACE) != 
                     PCI_BASE_ADDRESS_SPACE_MEMORY)
                     continue;
-                pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+                pcistr[cnt].dpmem = pdev->resource[0].start;
             } else {                                    /* GDT6110, GDT6120, .. */
                 if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
                     PCI_BASE_ADDRESS_SPACE_MEMORY ||
@@ -680,77 +679,21 @@
                     (base1 & PCI_BASE_ADDRESS_SPACE) !=
                     PCI_BASE_ADDRESS_SPACE_IO)
                     continue;
-                pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
-                pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-                pcistr[cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
+                pcistr[cnt].dpmem = pdev->resource[2].start;
+                pcistr[cnt].io_mm = pdev->resource[0].start;
+                pcistr[cnt].io    = pdev->resource[1].start;
             }
             TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
                     pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
                     pcistr[cnt].irq, pcistr[cnt].dpmem));
             cnt++;
         }       
-#else   
-        idx = 0;
-        while (!pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,idx++,
-                                    &pcistr[cnt].bus,&pcistr[cnt].device_fn)) {
-            if (cnt >= MAXHA)
-                return cnt;
-            /* GDT PCI ctr. found, now read resources from config space */
-#if LINUX_VERSION_CODE >= 0x010300
-#define GDTH_BASEP      (int *)
-#else
-#define GDTH_BASEP
-#endif
-            if ((error = pcibios_read_config_dword(pcistr[cnt].bus,
-                                                   pcistr[cnt].device_fn,
-                                                   PCI_BASE_ADDRESS_0,
-                                                   GDTH_BASEP&base0)) ||
-                (error = pcibios_read_config_dword(pcistr[cnt].bus,
-                                                   pcistr[cnt].device_fn,
-                                                   PCI_BASE_ADDRESS_1,
-                                                   GDTH_BASEP&base1)) ||
-                (error = pcibios_read_config_dword(pcistr[cnt].bus,
-                                                   pcistr[cnt].device_fn,
-                                                   PCI_BASE_ADDRESS_2,
-                                                   GDTH_BASEP&base2)) ||
-                (error = pcibios_read_config_byte(pcistr[cnt].bus,
-                                                  pcistr[cnt].device_fn,
-                                                  PCI_INTERRUPT_LINE,
-                                                  &pcistr[cnt].irq))) {
-                printk("GDT-PCI: error %d reading configuration space", error);
-                continue;
-            }
-            pcistr[cnt].device_id = device_id;
-            if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
-                device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
-                if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
-                    PCI_BASE_ADDRESS_SPACE_MEMORY)
-                    continue;
-                pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-            } else {                                    /* GDT6110, GDT6120, .. */
-                if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
-                    PCI_BASE_ADDRESS_SPACE_MEMORY ||
-                    (base2 & PCI_BASE_ADDRESS_SPACE) !=
-                    PCI_BASE_ADDRESS_SPACE_MEMORY ||
-                    (base1 & PCI_BASE_ADDRESS_SPACE) !=
-                    PCI_BASE_ADDRESS_SPACE_IO)
-                    continue;
-                pcistr[cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
-                pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-                pcistr[cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
-            }
-            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
-                    pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
-                    pcistr[cnt].irq, pcistr[cnt].dpmem));
-            cnt++;
-        }
-#endif
     }   
     return cnt;
 }
 
 
-__initfunc (static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt))
+static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
 {    
     gdth_pci_str temp;
     int i, changed;
@@ -788,7 +731,7 @@
 }
 
 
-__initfunc (static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
+static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
 {
     ulong32 retries,id;
     unchar prot_ver,eisacf,i,irq_found;
@@ -877,7 +820,7 @@
 }
 
        
-__initfunc (static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha))
+static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
 {
     register gdt2_dpram_str *dp2_ptr;
     int i;
@@ -974,7 +917,7 @@
 }
 
 
-__initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
+static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
 {
     register gdt6_dpram_str *dp6_ptr;
     register gdt6c_dpram_str *dp6c_ptr;
@@ -1241,7 +1184,7 @@
 
 /* controller protocol functions */
 
-__initfunc (static void gdth_enable_int(int hanum))
+static void __init gdth_enable_int(int hanum)
 {
     gdth_ha_str *ha;
     ulong flags;
@@ -1574,7 +1517,7 @@
 
 /* search for devices */
 
-__initfunc (static int gdth_search_drives(int hanum))
+static int __init gdth_search_drives(int hanum)
 {
     register gdth_ha_str *ha;
     ushort cdev_cnt, i;
@@ -3287,7 +3230,7 @@
 #endif
 
 
-__initfunc (int gdth_detect(Scsi_Host_Template *shtp))
+int __init gdth_detect(Scsi_Host_Template *shtp)
 {
     struct Scsi_Host *shp;
     gdth_ha_str *ha;
@@ -3959,7 +3902,7 @@
 
 
 /* called from init/main.c */
-__initfunc (void gdth_setup(char *str,int *ints))
+void __init gdth_setup(char *str,int *ints)
 {
     int i, argc;
     char *cur_str, *argv;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.3.12/linux/drivers/scsi/hosts.c	Tue May 11 14:37:40 1999
+++ linux/drivers/scsi/hosts.c	Mon Aug  9 10:25:01 1999
@@ -752,7 +752,7 @@
             shpnt->eh_notify = NULL;
 }
 
-__initfunc(unsigned int scsi_init(void))
+unsigned int __init scsi_init(void)
 {
     static int called = 0;
     int i, pcount;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.3.12/linux/drivers/scsi/ini9100u.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/ini9100u.c	Mon Aug  9 10:25:01 1999
@@ -348,7 +348,7 @@
 				dRegValue = 0;
 			wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
 			if (Addi91u_into_Adapter_table(wBIOS,
-							(pDev->base_address[0] & 0xFFFE),
+							(pDev->resource[0].start),
 						       	pDev->irq,
 						       	pDev->bus->number,
 					       		(pDev->devfn >> 3)
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.3.12/linux/drivers/scsi/inia100.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/inia100.c	Mon Aug  9 10:25:01 1999
@@ -330,7 +330,7 @@
 #if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
 					bPCIBusNum = pdev->bus->number;
 					bPCIDeviceNum = pdev->devfn;
-					dRegValue = pdev->base_address[0];
+					dRegValue = pdev->resource[0].start;
 					if (dRegValue == -1) {	/* Check return code            */
 						printk("\n\rinia100: orchid read configuration error.\n");
 						return (0);	/* Read configuration space error  */
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.3.12/linux/drivers/scsi/megaraid.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/megaraid.c	Mon Aug  9 10:25:01 1999
@@ -1267,17 +1267,8 @@
 	    PCI_FUNC (pciDevFun));
 
     /* Read the base port and IRQ from PCI */
-#if LINUX_VERSION_CODE < 0x20100
-    pcibios_read_config_dword (pciBus, pciDevFun,
-			       PCI_BASE_ADDRESS_0,
-			       (u_int *) & megaBase);
-    pcibios_read_config_byte (pciBus, pciDevFun,
-			      PCI_INTERRUPT_LINE,
-			      &megaIrq);
-#else
-    megaBase = pdev->base_address[0];
+    megaBase = pdev->resource[0].start;
     megaIrq  = pdev->irq;
-#endif
     pciIdx++;
 
     if (flag & BOARD_QUARTZ) {
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c
--- v2.3.12/linux/drivers/scsi/pas16.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/pas16.c	Mon Aug  9 10:25:01 1999
@@ -213,8 +213,8 @@
  *
  */
 
-__initfunc(static void
-	enable_board( int  board_num,  unsigned short port ))
+static void __init
+	enable_board( int  board_num,  unsigned short port )
 {
     outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
     outb( port >> 2, MASTER_ADDRESS_PTR );
@@ -233,8 +233,8 @@
  *
  */
 
-__initfunc (static void
-	init_board( unsigned short io_port, int irq, int force_irq ))
+static void __init 
+	init_board( unsigned short io_port, int irq, int force_irq )
 {
 	unsigned int	tmp;
 	unsigned int	pas_irq_code;
@@ -282,8 +282,8 @@
  * Returns : 0 if board not found, 1 if found.
  */
 
-__initfunc(static int
-     pas16_hw_detect( unsigned short  board_num ))
+static int __init 
+     pas16_hw_detect( unsigned short  board_num )
 {
     unsigned char	board_rev, tmp;
     unsigned short	io_port = bases[ board_num ].io_port;
@@ -342,7 +342,8 @@
  *
  */
 
-__initfunc(void pas16_setup(char *str, int *ints)) {
+void __init pas16_setup(char *str, int *ints)
+{
     static int commandline_current = 0;
     int i;
     if (ints[0] != 2) 
@@ -373,7 +374,8 @@
  *
  */
 
-__initfunc(int pas16_detect(Scsi_Host_Template * tpnt)) {
+int __init pas16_detect(Scsi_Host_Template * tpnt)
+{
     static int current_override = 0;
     static unsigned short current_base = 0;
     struct Scsi_Host *instance;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.3.12/linux/drivers/scsi/pci2000.c	Tue Apr 13 07:54:02 1999
+++ linux/drivers/scsi/pci2000.c	Thu Aug  5 15:08:56 1999
@@ -640,12 +640,8 @@
 		pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
 		padapter = HOSTDATA(pshost);
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
-		padapter->basePort = pdev->base_address[1] & 0xFFFE;
-#else
-		pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort);
-		padapter->basePort &= 0xFFFE;
-#endif
+		padapter->basePort = pdev->resource[1].start;
+
 		DEB (printk ("\nBase Regs = %#04X", padapter->basePort));			// get the base I/O port address
 		padapter->mb0	= padapter->basePort + RTR_MAILBOX;		   			// get the 32 bit mail boxes
 		padapter->mb1	= padapter->basePort + RTR_MAILBOX + 4;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.3.12/linux/drivers/scsi/pci2220i.c	Tue Apr 13 07:54:02 1999
+++ linux/drivers/scsi/pci2220i.c	Thu Aug  5 15:08:56 1999
@@ -1822,12 +1822,7 @@
 		padapter = HOSTDATA(pshost);
 		memset (padapter, 0, sizeof (ADAPTER2220I));
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
-		zs = pdev->base_address[1] & 0xFFFE;
-#else
-		pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zs);
-		zs &= 0xFFFE;
-#endif
+		zs = pdev->resource[1].start;
 		padapter->basePort = zs;
 		padapter->regRemap		= zs + RTR_LOCAL_REMAP;				// 32 bit local space remap
 		padapter->regDesc		= zs + RTR_REGIONS;	  				// 32 bit local region descriptor
@@ -1835,12 +1830,7 @@
 		padapter->regIrqControl	= zs + RTR_INT_CONTROL_STATUS;		// 16 bit interupt control and status
 		padapter->regScratchPad	= zs + RTR_MAILBOX;	  				// 16 byte scratchpad I/O base address
 
-#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92)
-		zs = pdev->base_address[2] & 0xFFFE;
-#else
-		pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zs);
-		zs &= 0xFFFE;
-#endif
+		zs = pdev->resource[2].start;
 		padapter->regBase		= zs;
 		padapter->regData		= zs + REG_DATA;					// data register I/O address
 		padapter->regError		= zs + REG_ERROR;					// error register I/O address
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.3.12/linux/drivers/scsi/qlogicfc.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/qlogicfc.c	Thu Aug  5 15:11:52 1999
@@ -1828,7 +1828,7 @@
 		printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id);
 		return 1;
 	}
-	io_base = pdev->base_address[0];
+	io_base = pdev->resource[0].start;
 	irq = pdev->irq;
 
 
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.12/linux/drivers/scsi/qlogicisp.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/qlogicisp.c	Thu Aug  5 15:11:52 1999
@@ -1188,7 +1188,7 @@
 		printk("qlogicisp : error reading PCI configuration\n");
 		return 1;
 	}
-	io_base = pdev->base_address[0];
+	io_base = pdev->resource[0].start;
 	irq = pdev->irq;
 
 	if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.12/linux/drivers/scsi/scsi.c	Tue Jun  8 10:41:03 1999
+++ linux/drivers/scsi/scsi.c	Fri Aug  6 11:43:09 1999
@@ -32,6 +32,8 @@
  *  Converted cli() code to spinlocks, Ingo Molnar
  *
  *  Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
+ *
+ *  out_of_space hacks, D. Gilbert (dpg) 990608
  */
 
 #include <linux/config.h>
@@ -180,6 +182,7 @@
                  int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
                  struct Scsi_Host *shpnt, char * scsi_result);
 void        scsi_build_commandblocks(Scsi_Device * SDpnt);
+static int scsi_unregister_device(struct Scsi_Device_Template * tpnt);
 
 /*
  * These are the interface to the old error handling code.  It should go away
@@ -403,30 +406,43 @@
 	up(SCpnt->request.sem);
 }
 
-__initfunc(void scsi_logging_setup(char *str, int *ints))
+static int __init scsi_logging_setup (char *str)
 {
-    if (ints[0] != 1) {
-	printk("scsi_logging_setup : usage scsi_logging_level=n "
+	int tmp;
+
+	if (get_option(&str, &tmp)==1) {
+	   	scsi_logging_level = (tmp ? ~0 : 0);
+		return 1;
+	} else {
+		printk("scsi_logging_setup : usage scsi_logging_level=n "
                "(n should be 0 or non-zero)\n");
-    } else {
-	scsi_logging_level = (ints[1])? ~0 : 0;
+		return 0;
     }
 }
 
+__setup("scsi_logging=", scsi_logging_setup);
+
 #ifdef CONFIG_SCSI_MULTI_LUN
 static int max_scsi_luns = 8;
 #else
 static int max_scsi_luns = 1;
 #endif
 
-__initfunc(void scsi_luns_setup(char *str, int *ints))
+static int __init scsi_luns_setup (char *str)
 {
-    if (ints[0] != 1)
-	printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
-    else
-	max_scsi_luns = ints[1];
+	int tmp;
+
+	if (get_option(&str, &tmp)==1) {
+		max_scsi_luns = tmp;
+		return 1;
+	} else {
+		printk("scsi_luns_setup : usage max_scsi_luns=n "
+			   "(n should be between 1 and 8)\n");
+		return 0;
+    }
 }
 
+__setup("max_scsi_luns=", scsi_luns_setup);
 /*
  *  Detecting SCSI devices :
  *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
@@ -451,16 +467,18 @@
   Scsi_Device   * SDtail;
   int             sparse_lun;
 
-  SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
-  memset (SCpnt, 0, sizeof (Scsi_Cmnd));
-
-  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
-  memset (SDpnt, 0, sizeof (Scsi_Device));
-
-
-  /* Make sure we have something that is valid for DMA purposes */
-  scsi_result = ( ( !shpnt->unchecked_isa_dma )
-                 ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
+  scsi_result = NULL;
+  SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), 
+					  GFP_ATOMIC | GFP_DMA);
+    if (SCpnt) {
+	SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), 
+						 GFP_ATOMIC);
+	if (SDpnt) {
+	    /* Make sure we have something that is valid for DMA purposes */
+	    scsi_result = ( ( !shpnt->unchecked_isa_dma )
+			? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
+	}
+    }
 
   if (scsi_result == NULL) 
   {
@@ -517,15 +535,23 @@
     if(SDpnt!=oldSDpnt) {
 
 	/* it could happen the blockdevice hasn't yet been inited */
-    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-        if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
 
-            oldSDpnt->scsi_request_fn = NULL;
-            for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-                if(sdtpnt->attach) {
-		  (*sdtpnt->attach)(oldSDpnt);
-                  if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);}
-	    resize_dma_pool();
+	oldSDpnt->scsi_request_fn = NULL;
+	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+	    if(sdtpnt->attach) {
+		(*sdtpnt->attach)(oldSDpnt);
+		if(oldSDpnt->attached) {
+		    scsi_build_commandblocks(oldSDpnt);
+		    if (0 == oldSDpnt->has_cmdblocks) {
+			printk("scan_scsis: DANGER, no command blocks\n");
+			/* What to do now ?? */
+		    }
+		}
+	    }
+	}
+	resize_dma_pool();
 
         for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
             if(sdtpnt->finish && sdtpnt->nr_dev)
@@ -886,8 +912,6 @@
       return 0;
   }
 
-  memset (SDpnt, 0, sizeof (Scsi_Device));
-
   /*
    * And hook up our command block to the new device we will be testing
    * for.
@@ -1903,9 +1927,9 @@
 	for (order = 0, a_size = PAGE_SIZE;
              a_size < size; order++, a_size <<= 1)
             ;
-        retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
+	retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
     } else
-        retval = kmalloc(size, gfp_mask);
+	retval = kmalloc(size, gfp_mask);
 
     if (retval)
 	memset(retval, 0, size);
@@ -1974,9 +1998,10 @@
 	printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n",
 	       SDpnt->queue_depth, j);
 	SDpnt->queue_depth = j;
-	/* Still problem if 0==j , continue anyway ... */
+	SDpnt->has_cmdblocks = (0 != j);
     }
-    SDpnt->has_cmdblocks = 1;
+    else
+	SDpnt->has_cmdblocks = 1;
 }
 
 #ifndef MODULE /* { */
@@ -1985,7 +2010,7 @@
  * initialization, bus scanning, and sd/st initialization routines.
  * This is only used at boot time.
  */
-__initfunc(int scsi_dev_init(void))
+int __init scsi_dev_init(void)
 {
     Scsi_Device * SDpnt;
     struct Scsi_Host * shpnt;
@@ -2040,7 +2065,13 @@
             /* SDpnt->scsi_request_fn = NULL; */
             for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
                 if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-            if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+            if(SDpnt->attached) {
+		scsi_build_commandblocks(SDpnt);
+		if (0 == SDpnt->has_cmdblocks) {
+		    printk("scsi_dev_init: DANGER, no command blocks\n");
+		    /* What to do now ?? */
+		}
+	    }
         }
     }
     
@@ -2433,7 +2464,7 @@
  */
 static void resize_dma_pool(void)
 {
-    int i;
+    int i, k;
     unsigned long size;
     struct Scsi_Host * shpnt;
     struct Scsi_Host * host = NULL;
@@ -2442,6 +2473,7 @@
     unsigned int new_dma_sectors = 0;
     unsigned int new_need_isa_buffer = 0;
     unsigned char ** new_dma_malloc_pages = NULL;
+    int out_of_space = 0;
 
     if( !scsi_hostlist )
     {
@@ -2533,27 +2565,67 @@
      * race conditions that I would rather not even think
      * about right now.
      */
-    if( new_dma_sectors < dma_sectors )
+#if 0  /* Why do this? No gain and risks out_of_space */
+     if( new_dma_sectors < dma_sectors ) 
 	new_dma_sectors = dma_sectors;
+#endif
+    if( new_dma_sectors <= dma_sectors ) 
+	return;	/* best to quit while we are in front */
 
-    if (new_dma_sectors)
-    {
-        size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
-	new_dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC);
-	memset(new_dma_malloc_freelist, 0, size);
-
-        size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(*new_dma_malloc_pages);
-	new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC);
-	memset(new_dma_malloc_pages, 0, size);
-    }
+    for (k = 0; k < 20; ++k) { /* just in case */
+	out_of_space = 0;
+	size = (new_dma_sectors / SECTORS_PER_PAGE) *
+				    sizeof(FreeSectorBitmap);
+	new_dma_malloc_freelist = (FreeSectorBitmap *) 
+			    scsi_init_malloc(size, GFP_ATOMIC);
+	if (new_dma_malloc_freelist) {
+	    size = (new_dma_sectors / SECTORS_PER_PAGE) *
+			    sizeof(*new_dma_malloc_pages);
+	    new_dma_malloc_pages = (unsigned char **) 
+			    scsi_init_malloc(size, GFP_ATOMIC);
+	    if (! new_dma_malloc_pages) {
+		size = (new_dma_sectors / SECTORS_PER_PAGE) *
+				    sizeof(FreeSectorBitmap);
+		scsi_init_free((char *)new_dma_malloc_freelist, size);
+		out_of_space = 1;
+	    }
+	}
+	else
+	    out_of_space = 1;
+	
+	if ((! out_of_space) && (new_dma_sectors > dma_sectors)) { 
+	    for(i = dma_sectors / SECTORS_PER_PAGE; 
+		i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
+		new_dma_malloc_pages[i] = (unsigned char *)
+		    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+		if (! new_dma_malloc_pages[i])
+		    break;
+	    }
+	    if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */
+		int k = i;
 
-    /*
-     * If we need more buffers, expand the list.
-     */
-    if( new_dma_sectors > dma_sectors ) { 
-	for(i=dma_sectors / SECTORS_PER_PAGE; i< new_dma_sectors / SECTORS_PER_PAGE; i++)
-	    new_dma_malloc_pages[i] = (unsigned char *)
-	        scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+		out_of_space = 1;
+		for (i = 0; i < k; ++i)
+		    scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE);
+	    }
+	}
+	if (out_of_space) { /* try scaling down new_dma_sectors request */
+	    printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
+		   "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
+	    if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
+		break; /* pretty well hopeless ... */
+	    new_dma_sectors = (new_dma_sectors * 3) / 4;
+	    new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+	    if (new_dma_sectors <= dma_sectors)
+		break; /* stick with what we have got */
+	}
+	else
+	    break; /* found space ... */
+    } /* end of for loop */
+    if (out_of_space) {
+	scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */
+	printk("      WARNING, not enough memory, pool not expanded\n");
+	return;
     }
 
     /* When we dick with the actual DMA list, we need to
@@ -2600,6 +2672,7 @@
     struct Scsi_Device_Template * sdtpnt;
     const char * name;
     unsigned long flags;
+    int out_of_space = 0;
 
     if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
 					       * no detect routine available
@@ -2699,11 +2772,11 @@
         {
 	    if(shpnt->hostt == tpnt) 
             {
-                scan_scsis(shpnt,0,0,0,0);
-                if (shpnt->select_queue_depths != NULL)
-                {
-                    (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
-                }
+		scan_scsis(shpnt,0,0,0,0);
+		if (shpnt->select_queue_depths != NULL)
+		{
+		    (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
+		}
 	    }
         }
 
@@ -2722,14 +2795,19 @@
                 {
                     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
                         if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-                    if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+                    if(SDpnt->attached) {
+			scsi_build_commandblocks(SDpnt);
+			if (0 == SDpnt->has_cmdblocks)
+			    out_of_space = 1;
+		    }
                 }
         }
 
 	/*
 	 * Now that we have all of the devices, resize the DMA pool,
 	 * as required.  */
-	resize_dma_pool();
+	if (! out_of_space)
+	    resize_dma_pool();
 
 
 	/* This does any final handling that is required. */
@@ -2750,7 +2828,13 @@
 #endif
 
     MOD_INC_USE_COUNT;
-    return 0;
+
+    if (out_of_space) {
+	scsi_unregister_host(tpnt); /* easiest way to clean up?? */
+	return 1;
+    }
+    else
+	return 0;
 }
 
 /*
@@ -3011,6 +3095,7 @@
 {
     Scsi_Device      * SDpnt;
     struct Scsi_Host * shpnt;
+    int out_of_space = 0;
 
     if (tpnt->next) return 1;
 
@@ -3052,6 +3137,8 @@
             {
                 SDpnt->online = TRUE;
                 scsi_build_commandblocks(SDpnt);
+		if (0 == SDpnt->has_cmdblocks)
+		    out_of_space = 1;
             }
         }
     }
@@ -3060,9 +3147,16 @@
      * This does any final handling that is required.
      */
     if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
-    resize_dma_pool();
+    if (! out_of_space)
+	resize_dma_pool();
     MOD_INC_USE_COUNT;
-    return 0;
+
+    if (out_of_space) {
+	scsi_unregister_device(tpnt); /* easiest way to clean up?? */
+	return 1;
+    }
+    else
+	return 0;
 }
 
 static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
@@ -3298,6 +3392,7 @@
 int init_module(void) 
 {
     unsigned long size;
+    int has_space = 0;
 
     /*
      * This makes /proc/scsi visible.
@@ -3313,7 +3408,6 @@
     proc_scsi_register(0, &proc_scsi_scsi);
 #endif
 
-
     dma_sectors = PAGE_SIZE / SECTOR_SIZE;
     scsi_dma_free_sectors= dma_sectors;
     /*
@@ -3322,15 +3416,31 @@
      */
 
     /* One bit per sector to indicate free/busy */
-    size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
-    dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC);
-    memset(dma_malloc_freelist, 0, size);
-
-    /* One pointer per page for the page list */
-    dma_malloc_pages = (unsigned char **)
-	scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC);
-    dma_malloc_pages[0] = (unsigned char *)
-	scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+    size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
+    dma_malloc_freelist = (FreeSectorBitmap *) 
+				scsi_init_malloc(size, GFP_ATOMIC);
+    if (dma_malloc_freelist) {
+	/* One pointer per page for the page list */
+	dma_malloc_pages = (unsigned char **)scsi_init_malloc(
+		(dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
+							      GFP_ATOMIC);
+	if (dma_malloc_pages) {
+	    dma_malloc_pages[0] = (unsigned char *)
+			scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+	    if (dma_malloc_pages[0])
+		has_space = 1;
+	}
+    }
+    if (! has_space) {
+	if (dma_malloc_freelist) {
+	    scsi_init_free((char *)dma_malloc_freelist, size);
+	    if (dma_malloc_pages)
+		scsi_init_free((char *)dma_malloc_pages,
+		(dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
+	}
+	printk("scsi::init_module: failed, out of memory\n");
+	return 1;
+    }
 
     /*
      * This is where the processing takes place for most everything
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.3.12/linux/drivers/scsi/sr.c	Tue May 11 14:37:40 1999
+++ linux/drivers/scsi/sr.c	Mon Aug  9 12:34:22 1999
@@ -34,6 +34,7 @@
 #include <linux/interrupt.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 #define MAJOR_NR SCSI_CDROM_MAJOR
 #include <linux/blk.h>
@@ -70,6 +71,7 @@
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt);
 static int sr_media_change(struct cdrom_device_info*, int);
+static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
@@ -99,8 +101,10 @@
         sr_dev_ioctl,                 /* device-specific ioctl */
         CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED |
         CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
-        CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS,
-        0
+        CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW |
+	CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET,
+        0,
+	sr_packet
 };
 
 /*
@@ -988,25 +992,85 @@
         scsi_CDs[i].cdi.speed      = 1;
         /* disable speed select, drive probably can't do this either */
         scsi_CDs[i].cdi.mask      |= CDC_SELECT_SPEED;
-    } else {
-        n = buffer[3]+4;
-        scsi_CDs[i].cdi.speed    = ((buffer[n+8] << 8) + buffer[n+9])/176;
-      	scsi_CDs[i].readcd_known = 1;
-        scsi_CDs[i].readcd_cdda  = buffer[n+5] & 0x01;
-        /* print some capability bits */
-        printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i,
-               ((buffer[n+14] << 8) + buffer[n+15])/176,
-               scsi_CDs[i].cdi.speed,
-               buffer[n+3]&0x01 ? "writer " : "",   /* CD Writer */
-               buffer[n+2]&0x02 ? "cd/rw " : "",    /* can read rewriteable */
-               buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */
-               buffer[n+5]&0x01 ? "cdda " : "",     /* can read audio data */
-               loadmech[buffer[n+6]>>5]);
-	if ((buffer[n+6] >> 5) == 0)
-		/* caddy drives can't close tray... */
-        	scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
+	scsi_free(buffer, 512);
+	return;
     }
+    
+    n = buffer[3]+4;
+    scsi_CDs[i].cdi.speed    = ((buffer[n+8] << 8) + buffer[n+9])/176;
+    scsi_CDs[i].readcd_known = 1;
+    scsi_CDs[i].readcd_cdda  = buffer[n+5] & 0x01;
+    /* print some capability bits */
+    printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i,
+    	((buffer[n+14] << 8) + buffer[n+15])/176,
+	scsi_CDs[i].cdi.speed,
+	buffer[n+3]&0x01 ? "writer " : "",   /* CD Writer */
+	buffer[n+2]&0x02 ? "cd/rw " : "",    /* can read rewriteable */
+	buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */
+	buffer[n+5]&0x01 ? "cdda " : "",     /* can read audio data */
+	loadmech[buffer[n+6]>>5]);
+    if ((buffer[n+6] >> 5) == 0)
+	/* caddy drives can't close tray... */
+        scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
+    if ((buffer[n+2] & 0x8) == 0)
+	/* not a DVD drive */
+	scsi_CDs[i].cdi.mask |= CDC_DVD;
+    if ((buffer[n+3] & 0x20) == 0)
+    	/* can't write DVD-RAM media */
+	scsi_CDs[i].cdi.mask |= CDC_DVD_RAM;
+    if ((buffer[n+3] & 0x10) == 0)
+    	/* can't write DVD-R media */
+	scsi_CDs[i].cdi.mask |= CDC_DVD_R;
+    if ((buffer[n+3] & 0x2) == 0)
+    	/* can't write CD-RW media */
+	scsi_CDs[i].cdi.mask |= CDC_CD_RW;
+    if ((buffer[n+3] & 0x1) == 0)
+    	/* can't write CD-R media */
+	scsi_CDs[i].cdi.mask |= CDC_CD_R;
+
     scsi_free(buffer, 512);
+}
+
+/*
+ * sr_packet() is the entry point for the generic commands generated
+ * by the Uniform CD-ROM layer. 
+*/
+static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
+{
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device;
+	DECLARE_MUTEX_LOCKED(sem);
+	unsigned long flags;
+	int stat;
+	
+	/* get the device */
+	SCpnt = scsi_allocate_device(NULL, device, 1);
+	if (SCpnt == NULL)
+		return -ENODEV;	/* this just doesn't seem right /axboe */
+	
+	/* set the LUN */
+	cgc->cmd[1] |= device->lun << 5;
+
+	/* do the locking and issue the command */
+	SCpnt->request.rq_dev = cdi->dev;
+	SCpnt->request.rq_status = RQ_SCSI_BUSY;
+	/* scsi_do_cmd sets the command length */
+	SCpnt->cmd_len = 0;
+	SCpnt->request.sem = &sem;
+	spin_lock_irqsave(&io_request_lock, flags);
+	scsi_do_cmd (SCpnt, (void *)cgc->cmd, (void *)cgc->buffer, cgc->buflen,
+		     sr_init_done, SR_TIMEOUT, MAX_RETRIES);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	down(&sem);
+	
+	stat = SCpnt->result;
+
+	/* release */
+	SCpnt->request.rq_dev = MKDEV(0,0);
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+	
+	return stat;
 }
 
 static int sr_registered = 0;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.3.12/linux/drivers/scsi/sr_ioctl.c	Sat May 15 23:43:04 1999
+++ linux/drivers/scsi/sr_ioctl.c	Thu Aug  5 16:24:15 1999
@@ -240,9 +240,8 @@
 int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn)
 {
         u_char  sr_cmd[10];
-	char * buffer;
+	char buffer[32];
         int result;
-        unsigned long flags;
         	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
@@ -254,20 +253,11 @@
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
 
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char*) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
-	
 	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
 	
 	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
         mcn->medium_catalog_number[13] = 0;
 
-        spin_lock_irqsave(&io_request_lock, flags);
-	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	
 	return result;
 }
 
@@ -395,8 +385,7 @@
     case CDROMREADTOCHDR:
     {
 	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
-	char * buffer;
-        unsigned long flags;
+	char buffer[32];
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
@@ -406,27 +395,18 @@
 	sr_cmd[8] = 12;             /* LSB of length */
 	sr_cmd[9] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
-	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
 	
 	tochdr->cdth_trk0 = buffer[2];
 	tochdr->cdth_trk1 = buffer[3];
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
     case CDROMREADTOCENTRY:
     {
 	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
-	unsigned char * buffer;
-        unsigned long flags;
+	unsigned char buffer[32];
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
@@ -437,11 +417,6 @@
 	sr_cmd[8] = 12;            /* LSB of length */
 	sr_cmd[9] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
-	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
 	
         tocentry->cdte_ctrl = buffer[5] & 0xf;	
@@ -455,151 +430,13 @@
 	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
                                        + buffer[10]) << 8) + buffer[11];
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-        break;
-    }
-	
-    case CDROMSTOP:
-	sr_cmd[0] = START_STOP;
-	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-	sr_cmd[4] = 0;
-	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
-        break;
-	
-    case CDROMSTART:
-	sr_cmd[0] = START_STOP;
-	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-	sr_cmd[4] = 1;
-	
-	result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
-        break;
-	
-    case CDROMVOLCTRL:
-    {
-	char * buffer, * mask;
-	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-        unsigned long flags;
-	
-	/* First we get the current params so we can just twiddle the volume */
-	
-	sr_cmd[0] = MODE_SENSE;
-	sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
-	sr_cmd[2] = 0xe;    /* Want mode page 0xe, CDROM audio params */
-	sr_cmd[3] = 0;
-	sr_cmd[4] = 28;
-	sr_cmd[5] = 0;
-	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
-	
-	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
-	    printk ("Hosed while obtaining audio mode page\n");
-            spin_lock_irqsave(&io_request_lock, flags);
-	    scsi_free(buffer, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
-            break;
-	}
-	
-	sr_cmd[0] = MODE_SENSE;
-	sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
-	sr_cmd[2] = 0x4e;   /* Want the mask for mode page 0xe */
-	sr_cmd[3] = 0;
-	sr_cmd[4] = 28;
-	sr_cmd[5] = 0;
-	
-        spin_lock_irqsave(&io_request_lock, flags);
-	mask = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!mask) {
-            spin_lock_irqsave(&io_request_lock, flags);
-	    scsi_free(buffer, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
-	    result = -ENOMEM;
-            break;
-	};
-
-	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) {
-	    printk ("Hosed while obtaining mask for audio mode page\n");
-            spin_lock_irqsave(&io_request_lock, flags);
-	    scsi_free(buffer, 512);
-	    scsi_free(mask, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
-	    break;
-	}
-	
-	/* Now mask and substitute our own volume and reuse the rest */
-	buffer[0] = 0;  /* Clear reserved field */
-	
-	buffer[21] = volctrl->channel0 & mask[21];
-	buffer[23] = volctrl->channel1 & mask[23];
-	buffer[25] = volctrl->channel2 & mask[25];
-	buffer[27] = volctrl->channel3 & mask[27];
-	
-	sr_cmd[0] = MODE_SELECT;
-	sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;    /* Params are SCSI-2 */
-	sr_cmd[2] = sr_cmd[3] = 0;
-	sr_cmd[4] = 28;
-	sr_cmd[5] = 0;
-	
-	result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0);
-        spin_lock_irqsave(&io_request_lock, flags);
-	scsi_free(buffer, 512);
-	scsi_free(mask, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-        break;
-    }
-	
-    case CDROMVOLREAD:
-    {
-	char * buffer;
-	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
-        unsigned long flags;
-	
-	/* Get the current params */
-	
-	sr_cmd[0] = MODE_SENSE;
-	sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
-	sr_cmd[2] = 0xe;    /* Want mode page 0xe, CDROM audio params */
-	sr_cmd[3] = 0;
-	sr_cmd[4] = 28;
-	sr_cmd[5] = 0;
-	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
-	
-	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
-	    printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
-            spin_lock_irqsave(&io_request_lock, flags);
-	    scsi_free(buffer, 512);
-            spin_unlock_irqrestore(&io_request_lock, flags);
-            break;
-	}
-
-	volctrl->channel0 = buffer[21];
-	volctrl->channel1 = buffer[23];
-	volctrl->channel2 = buffer[25];
-	volctrl->channel3 = buffer[27];
-
-        spin_lock_irqsave(&io_request_lock, flags);
-	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
     case CDROMSUBCHNL:
     {
 	struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
-	char * buffer;
-        unsigned long flags;
+	char buffer[32];
 	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
@@ -611,11 +448,6 @@
 	sr_cmd[8] = 16;
 	sr_cmd[9] = 0;
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	buffer = (unsigned char *) scsi_malloc(512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if(!buffer) return -ENOMEM;
-	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0);
 	
 	subchnl->cdsc_audiostatus = buffer[1];
@@ -631,9 +463,6 @@
 	subchnl->cdsc_absaddr.msf.second = buffer[10];
 	subchnl->cdsc_absaddr.msf.frame = buffer[11];
 	
-        spin_lock_irqsave(&io_request_lock, flags);
-	scsi_free(buffer, 512);
-        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
     default:
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.12/linux/drivers/scsi/st.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/st.c	Mon Aug  9 10:25:01 1999
@@ -11,7 +11,7 @@
   Copyright 1992 - 1999 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Tue May 18 08:32:34 1999 by makisara@home
+  Last modified: Sat Aug  7 13:54:31 1999 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
@@ -55,17 +55,29 @@
 
 #include "constants.h"
 
+static int buffer_kbs = 0;
+static int write_threshold_kbs = 0;
+static int max_buffers = (-1);
+static int max_sg_segs = 0;
 #ifdef MODULE
+MODULE_AUTHOR("Kai Makisara");
+MODULE_DESCRIPTION("SCSI Tape Driver");
 MODULE_PARM(buffer_kbs, "i");
 MODULE_PARM(write_threshold_kbs, "i");
 MODULE_PARM(max_buffers, "i");
 MODULE_PARM(max_sg_segs, "i");
-static int buffer_kbs = 0;
-static int write_threshold_kbs = 0;
-static int max_buffers = 0;
-static int max_sg_segs = 0;
+#else
+static struct st_dev_parm {
+    char *name;
+    int *val;
+} parms[] __initdata = {
+    {"buffer_kbs", &buffer_kbs},
+    {"write_threshold_kbs", &write_threshold_kbs},
+    {"max_buffers", &max_buffers},
+    {"max_sg_segs", &max_sg_segs}};
 #endif
 
+
 /* The default definitions have been moved to st_options.h */
 
 #define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_KILOBYTE)
@@ -183,7 +195,7 @@
     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),
+	     dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
 	     host_byte(result));
   }
 
@@ -3318,23 +3330,66 @@
 }
 
 
+/* Validate the options from command line or module parameters */
+static void validate_options(void)
+{
+    if (buffer_kbs > 0)
+	st_buffer_size = buffer_kbs * ST_KILOBYTE;
+    if (write_threshold_kbs > 0)
+	st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
+    else if (buffer_kbs > 0)
+	st_write_threshold = st_buffer_size - 2048;
+    if (st_write_threshold > st_buffer_size) {
+	st_write_threshold = st_buffer_size;
+	printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n",
+	       st_write_threshold);
+    }
+    if (max_buffers >= 0)
+	st_max_buffers = max_buffers;
+    if (max_sg_segs >= ST_FIRST_SG)
+	st_max_sg_segs = max_sg_segs;
+}
+
 #ifndef MODULE
-/* Set the boot options. Syntax: st=xxx,yyy
-   where xxx is buffer size in 1024 byte blocks and yyy is write threshold
-   in 1024 byte blocks. */
-	__initfunc( void
-st_setup(char *str, int *ints))
-{
-  if (ints[0] > 0 && ints[1] > 0)
-    st_buffer_size = ints[1] * ST_KILOBYTE;
-  if (ints[0] > 1 && ints[2] > 0) {
-    st_write_threshold = ints[2] * ST_KILOBYTE;
-    if (st_write_threshold > st_buffer_size)
-      st_write_threshold = st_buffer_size;
-  }
-  if (ints[0] > 2 && ints[3] > 0)
-    st_max_buffers = ints[3];
+/* Set the boot options. Syntax is defined in README.st.
+*/
+static int __init st_setup(char *str)
+{
+    int i, len, ints[5];
+    char *stp;
+
+    stp = get_options(str, ARRAY_SIZE(ints), ints);
+
+    if (ints[0] > 0) {
+	for (i=0; i < ints[0] && i < ARRAY_SIZE(parms) ; i++)
+	    *parms[i].val = ints[i + 1];
+    }
+    else {
+	while (stp != NULL) {
+	    for (i=0; i < ARRAY_SIZE(parms); i++) {
+		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);
+		    break;
+		}
+	    }
+	    if (i >= sizeof(parms) / sizeof(struct st_dev_parm))
+		printk(KERN_WARNING "st: illegal parameter in '%s'\n",
+		       stp);
+	    stp = strchr(stp, ',');
+	    if (stp)
+		stp++;
+	}
+    }
+
+    validate_options();
+
+    return 1;
 }
+
+__setup("st=", st_setup);
+
 #endif
 
 
@@ -3449,12 +3504,13 @@
 {
   int i;
   Scsi_Tape * STp;
-#if !ST_RUNTIME_BUFFERS
   int target_nbr;
-#endif
 
   if (st_template.dev_noticed == 0) return 0;
 
+  printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n",
+	 st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+
   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);
@@ -3505,9 +3561,6 @@
     return 1;
   }
 
-#if ST_RUNTIME_BUFFERS
-  st_nbr_buffers = 0;
-#else
   target_nbr = st_template.dev_noticed;
   if (target_nbr < ST_EXTRA_DEVS)
     target_nbr = ST_EXTRA_DEVS;
@@ -3517,24 +3570,14 @@
   for (i=st_nbr_buffers=0; i < target_nbr; i++) {
     if (!new_tape_buffer(TRUE, TRUE)) {
       if (i == 0) {
-#if 0
-	printk(KERN_ERR "Can't continue without at least one tape buffer.\n");
-	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-	scsi_init_free((char *) st_buffers,
-		       st_template.dev_max * sizeof(ST_buffer *));
-	scsi_init_free((char *) scsi_tapes,
-		       st_template.dev_max * sizeof(Scsi_Tape));
-	return 1;
-#else
 	printk(KERN_INFO "No tape buffers allocated at initialization.\n");
 	break;
-#endif
       }
       printk(KERN_INFO "Number of tape buffers adjusted.\n");
       break;
     }
   }
-#endif
+
   return 0;
 }
 
@@ -3557,21 +3600,10 @@
 
 #ifdef MODULE
 
-int init_module(void) {
+int __init init_module(void) {
   int result;
 
-  if (buffer_kbs > 0)
-      st_buffer_size = buffer_kbs * ST_KILOBYTE;
-  if (write_threshold_kbs > 0)
-      st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
-  if (st_write_threshold > st_buffer_size)
-      st_write_threshold = st_buffer_size;
-  if (max_buffers > 0)
-      st_max_buffers = max_buffers;
-  if (max_sg_segs >= ST_FIRST_SG)
-      st_max_sg_segs = max_sg_segs;
-  printk(KERN_INFO "st: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
-	 st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+  validate_options();
 
   st_template.module = &__this_module;
   result = scsi_register_module(MODULE_SCSI_DEV, &st_template);
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h
--- v2.3.12/linux/drivers/scsi/st_options.h	Sun Sep  6 09:48:30 1998
+++ linux/drivers/scsi/st_options.h	Mon Aug  9 10:23:42 1999
@@ -1,20 +1,14 @@
 /*
    The compile-time configurable defaults for the Linux SCSI tape driver.
 
-   Copyright 1995 Kai Makisara.
+   Copyright 1995-1999 Kai Makisara.
 
-   Last modified: Wed Sep  2 21:24:07 1998 by root@home
+   Last modified: Sat Aug  7 13:42:21 1999 by makisara@kai.makisara.local
 */
 
 #ifndef _ST_OPTIONS_H
 #define _ST_OPTIONS_H
 
-/* The driver allocates the tape buffers when needed if ST_RUNTIME_BUFFERS
-   is nonzero. Otherwise a number of buffers are allocated at initialization.
-   The drawback of runtime allocation is that allocation may fail. In any
-   case the driver tries to allocate a new tape buffer when none is free. */
-#define ST_RUNTIME_BUFFERS 0
-
 /* The minimum limit for the number of SCSI tape devices is determined by
    ST_MAX_TAPES. If the number of tape devices and the "slack" defined by
    ST_EXTRA_DEVS exceeds ST_MAX_TAPES, the large number is used. */
@@ -49,9 +43,10 @@
    below. */
 #define ST_WRITE_THRESHOLD_BLOCKS 30
 
-/* The maximum number of tape buffers the driver allocates. The number
-   is also constrained by the number of drives detected. Determines the
-   maximum number of concurrently active tape drives. */
+/* The maximum number of tape buffers the driver tries to allocate at 
+   driver initialisation. The number is also constrained by the number
+   of drives detected. If more buffers are needed, they are allocated
+   at run time and freed after use. */
 #define ST_MAX_BUFFERS (2 + ST_EXTRA_DEVS)
 
 /* Maximum number of scatter/gather segments */
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.3.12/linux/drivers/scsi/sym53c8xx.c	Mon Apr 12 09:51:04 1999
+++ linux/drivers/scsi/sym53c8xx.c	Wed Aug  4 10:54:13 1999
@@ -10115,14 +10115,14 @@
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
 )
 {
-	*base = pdev->base_address[index++];
-	if ((*base & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
-		*base |= (((u_long)pdev->base_address[index]) << 32);
-#endif
+	/* FIXME! This is just unbelieably horrible backwards compatibility code */
+	struct resource *res = pdev->resource + index;
+
+	*base = res->start | (res->flags & 0xf);
+	if ((res->flags & 0x7) == 0x4) {
 		++index;
 	}
-	return index;
+	return index+1;
 }
 #endif
 
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- v2.3.12/linux/drivers/scsi/t128.c	Sat Sep  5 17:01:45 1998
+++ linux/drivers/scsi/t128.c	Mon Aug  9 10:25:01 1999
@@ -168,7 +168,7 @@
  *
  */
 
-__initfunc(void t128_setup(char *str, int *ints)) {
+void __init t128_setup(char *str, int *ints){
     static int commandline_current = 0;
     int i;
     if (ints[0] != 2) 
@@ -199,7 +199,7 @@
  *
  */
 
-__initfunc(int t128_detect(Scsi_Host_Template * tpnt)) {
+int __init t128_detect(Scsi_Host_Template * tpnt){
     static int current_override = 0, current_base = 0;
     struct Scsi_Host *instance;
     unsigned char *base;
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.3.12/linux/drivers/scsi/tmscsim.c	Fri Dec 25 16:41:39 1998
+++ linux/drivers/scsi/tmscsim.c	Mon Aug  9 10:25:01 1999
@@ -319,7 +319,7 @@
 # define PCI_PRESENT pci_present ()
 # define PCI_SET_MASTER pci_set_master (pdev)
 # define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
-# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+# define PCI_GET_IO_AND_IRQ io_port = pdev->resource[0].start; irq = pdev->irq
 #else
 # include <linux/bios32.h>
 # define PDEV pbus, pdevfn
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.3.12/linux/drivers/scsi/u14-34f.c	Fri Oct  9 11:56:59 1998
+++ linux/drivers/scsi/u14-34f.c	Mon Aug  9 10:25:01 1999
@@ -467,7 +467,6 @@
 #define ASOK              0x00
 #define ASST              0x91
 
-#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
 #define YESNO(a) ((a) ? 'y' : 'n')
 #define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
 
@@ -701,8 +700,8 @@
    return FALSE;
 }
 
-__initfunc (static inline int port_detect \
-      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
+static inline int __init port_detect \
+      (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) {
    unsigned char irq, dma_channel, subversion, i;
    unsigned char in_byte;
    char *bus_type, dma_name[16];
@@ -915,7 +914,8 @@
    return TRUE;
 }
 
-__initfunc (void u14_34f_setup(char *str, int *ints)) {
+void __init u14_34f_setup(char *str, int *ints)
+{
    int i, argc = ints[0];
    char *cur = str, *pc;
 
@@ -949,7 +949,8 @@
    return;
 }
 
-__initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt)) {
+int __init u14_34f_detect(Scsi_Host_Template *tpnt)
+{
    unsigned int j = 0, k;
    IRQ_FLAGS
 
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v2.3.12/linux/drivers/scsi/ultrastor.c	Sat Apr 11 11:13:25 1998
+++ linux/drivers/scsi/ultrastor.c	Fri Aug  6 11:43:09 1999
@@ -162,8 +162,6 @@
 
 #define VERSION "1.12"
 
-#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
-
 #define PACKED		__attribute__((packed))
 #define ALIGNED(x)	__attribute__((aligned(x)))
 
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c
--- v2.3.12/linux/drivers/scsi/wd33c93.c	Mon Apr 12 16:18:26 1999
+++ linux/drivers/scsi/wd33c93.c	Mon Aug  9 12:33:30 1999
@@ -75,6 +75,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/version.h>
+#include <linux/init.h>
 #include <asm/irq.h>
 
 #if LINUX_VERSION_CODE >= 0x010300
@@ -176,6 +177,7 @@
 static inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num)
 {
    regp->SASR = reg_num;
+   mb();
    return(regp->SCMD);
 }
 
@@ -186,14 +188,18 @@
 static inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value)
 {
    regp->SASR = reg_num;
+   mb();
    regp->SCMD = value;
+   mb();
 }
 
 
 static inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd)
 {
    regp->SASR = WD_COMMAND;
+   mb();
    regp->SCMD = cmd;
+   mb();
 }
 
 
@@ -216,9 +222,11 @@
 static void write_wd33c93_count(wd33c93_regs *regp,unsigned long value)
 {
    regp->SASR = WD_TRANSFER_COUNT_MSB;
+   mb();
    regp->SCMD = value >> 16;
    regp->SCMD = value >> 8;
    regp->SCMD = value;
+   mb();
 }
 
 
@@ -227,9 +235,11 @@
 unsigned long value;
 
    regp->SASR = WD_TRANSFER_COUNT_MSB;
+   mb();
    value = regp->SCMD << 16;
    value |= regp->SCMD << 8;
    value |= regp->SCMD;
+   mb();
    return value;
 }
 
@@ -1587,10 +1597,10 @@
 static char setup_used[MAX_SETUP_ARGS];
 static int done_setup = 0;
 
-void wd33c93_setup (char *str, int *ints)
+int wd33c93_setup (char *str)
 {
-int i,x;
-char *p1,*p2;
+   int i;
+   char *p1,*p2;
 
    /* The kernel does some processing of the command-line before calling
     * this function: If it begins with any decimal or hex number arguments,
@@ -1603,12 +1613,17 @@
 
    p1 = setup_buffer;
    *p1 = '\0';
+#if 0
+/*
+ * Old style command line arguments are now dead
+ */
    if (ints[0]) {
       for (i=0; i<ints[0]; i++) {
          x = vsprintf(p1,"nosync:0x%02x,",&(ints[i+1]));
          p1 += x;
          }
       }
+#endif
    if (str)
       strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
    setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
@@ -1631,8 +1646,12 @@
    for (i=0; i<MAX_SETUP_ARGS; i++)
       setup_used[i] = 0;
    done_setup = 1;
+
+   return 0;
 }
 
+__setup("wd33c93", wd33c93_setup);
+
 
 /* check_setup_args() returns index if key found, 0 if not
  */
@@ -1676,7 +1695,7 @@
 char buf[32];
 
    if (!done_setup && setup_strings)
-      wd33c93_setup(setup_strings,0);
+      wd33c93_setup(setup_strings);
 
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h
--- v2.3.12/linux/drivers/scsi/wd33c93.h	Wed Jul 16 19:22:51 1997
+++ linux/drivers/scsi/wd33c93.h	Mon Aug  9 12:33:30 1999
@@ -223,13 +223,13 @@
     uchar            clock_freq;
     uchar            chip;             /* what kind of wd33c93? */
     uchar            microcode;        /* microcode rev */
+    uchar            dma_buffer_pool;  /* FEF: buffer from chip_ram? */
     int              dma_dir;          /* data transfer dir. */
     dma_setup_t      dma_setup;
     dma_stop_t       dma_stop;
     unsigned int     dma_xfer_mask;
     uchar            *dma_bounce_buffer;
     unsigned int     dma_bounce_len;
-    uchar            dma_buffer_pool;  /* FEF: buffer from chip_ram? */
     volatile uchar   busy[8];          /* index = target, bit = lun */
     volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
     volatile Scsi_Cmnd *selecting;     /* trying to select this command */
diff -u --recursive --new-file v2.3.12/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.3.12/linux/drivers/scsi/wd7000.c	Thu Jan  7 09:24:00 1999
+++ linux/drivers/scsi/wd7000.c	Thu Aug  5 14:43:32 1999
@@ -1561,19 +1561,16 @@
 			break;
 
 		if (i == pass) {
-#if (LINUX_VERSION_CODE < 0x020100)
-#else
 		    void *biosaddr = ioremap (wd7000_biosaddr[biosaddr_ptr] +
 			                      signatures[sig_ptr].ofs,
 					      signatures[sig_ptr].len);
-#endif
-		    short bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig,
+		    short bios_match=0;
+		    
+		    if(biosaddr)
+		    	bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig,
 			                       signatures[sig_ptr].len);
 
-#if (LINUX_VERSION_CODE < 0x020100)
-#else
 		    iounmap (biosaddr);
-#endif
 
 		    if (! bios_match)
 		        goto bios_matched;
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.3.12/linux/drivers/sound/Config.in	Wed May 26 09:35:00 1999
+++ linux/drivers/sound/Config.in	Mon Aug  9 12:13:39 1999
@@ -11,16 +11,8 @@
 
 dep_tristate 'C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND
 dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
-if [ "$CONFIG_SOUND_ES1370" = "y" ]; then
-   bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT
-fi
 dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
-if [ "$CONFIG_SOUND_ES1371" = "y" ]; then
-   bool 'Joystick support at boot time' CONFIG_SOUND_ES1371_JOYPORT_BOOT
-   if [ "$CONFIG_SOUND_ES1371_JOYPORT_BOOT" = "y" ]; then
-      hex 'Gameport I/O 200,208,210,218' CONFIG_SOUND_ES1371_GAMEPORT 200
-   fi
-fi
+dep_tristate 'ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
 dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 
 dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.12/linux/drivers/sound/Makefile	Wed May 26 09:35:00 1999
+++ linux/drivers/sound/Makefile	Mon Aug  9 12:13:39 1999
@@ -75,11 +75,11 @@
 obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
 obj-$(CONFIG_SOUND_WAVEFRONT)   += wavefront.o
 
-#jnx
+obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 obj-$(CONFIG_SOUND_CMPCI)	+= cmpci.o
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o
-obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
+obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
 
 # Declare multi-part drivers.
 
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.3.12/linux/drivers/sound/cmpci.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sound/cmpci.c	Thu Aug  5 15:11:52 1999
@@ -2232,7 +2232,7 @@
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
 		s->magic = CM_MAGIC;
-		s->iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+		s->iobase = pcidev->resource[0].start;
 #ifdef CONFIG_SOUND_CMPCI_FM
 		s->iosynth = 0x388;
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.12/linux/drivers/sound/es1370.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/sound/es1370.c	Fri Aug  6 11:43:09 1999
@@ -101,6 +101,11 @@
  *    15.06.99   0.23  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.24  Add pci_set_master
+ *    02.08.99   0.25  Added workaround for the "phantom write" bug first
+ *                     documented by Dave Sharpless from Anchor Games
+ *    03.08.99   0.26  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+ *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -123,7 +128,6 @@
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -175,12 +179,14 @@
 #define ES1370_REG_DAC2_SCOUNT    0x28
 #define ES1370_REG_ADC_SCOUNT     0x2c
 
-#define ES1370_REG_DAC1_FRAMEADR  0xc30
-#define ES1370_REG_DAC1_FRAMECNT  0xc34
-#define ES1370_REG_DAC2_FRAMEADR  0xc38
-#define ES1370_REG_DAC2_FRAMECNT  0xc3c
-#define ES1370_REG_ADC_FRAMEADR   0xd30
-#define ES1370_REG_ADC_FRAMECNT   0xd34
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
 
 #define ES1370_FMT_U8_MONO     0
 #define ES1370_FMT_U8_STEREO   1
@@ -360,6 +366,13 @@
 
 static struct es1370_state *devs = NULL;
 
+/*
+ * The following buffer is used to point the phantom write channel to,
+ * so that it cannot wreak havoc. The attribute makes sure it doesn't
+ * cross a page boundary and ensures dword alignment for the DMA engine
+ */
+static unsigned char bugbuf[16] __attribute__ ((aligned (16)));
+
 /* --------------------------------------------------------------------- */
 
 extern inline unsigned ld2(unsigned int x)
@@ -2282,11 +2295,8 @@
 
 /* maximum number of devices */
 #define NR_DEVICE 5
-#ifdef CONFIG_SOUND_ES1370_JOYPORT_BOOT
-static int joystick[NR_DEVICE] = { 1, 0, };
-#else
+
 static int joystick[NR_DEVICE] = { 0, };
-#endif
 static int lineout[NR_DEVICE] = { 0, };
 static int micbias[NR_DEVICE] = { 0, };
 
@@ -2308,11 +2318,10 @@
 	{ SOUND_MIXER_WRITE_OGAIN, 0x4040 }
 };
 
-#ifdef MODULE
-int __init init_module(void)
-#else
-int __init init_es1370(void)
+#ifndef MODULE
+static
 #endif
+int __init init_module(void)
 {
 	struct es1370_state *s;
 	struct pci_dev *pcidev = NULL;
@@ -2321,11 +2330,11 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.24 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.26 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
-		if (pcidev->base_address[0] == 0 || 
-		    (pcidev->base_address[0] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (pcidev->resource[0].flags == 0 || 
+		    (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
 			continue;
 		if (pcidev->irq == 0) 
 			continue;
@@ -2342,7 +2351,7 @@
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
 		s->magic = ES1370_MAGIC;
-		s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+		s->io = pcidev->resource[0].start;
 		s->irq = pcidev->irq;
 		if (check_region(s->io, ES1370_EXTENT)) {
 			printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
@@ -2385,6 +2394,10 @@
 		/* initialize the chips */
 		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+		/* point phantom write channel to "bugbuf" */
+		outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+		outl(virt_to_bus(bugbuf), s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
+		outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
 		pci_set_master(pcidev);  /* enable bus mastering */
 		wrcodec(s, 0x16, 3); /* no RST, PD */
 		wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
@@ -2458,5 +2471,28 @@
 	}
 	printk(KERN_INFO "es1370: unloading\n");
 }
+
+#else /* MODULE */
+
+/* format is: es1370=[joystick[,lineout[,micbias]]] */
+
+static int __init es1370_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= NR_DEVICE)
+		return 0;
+
+	(   (get_option(&str,&joystick[nr_dev]) == 2)
+	 && (get_option(&str,&lineout [nr_dev]) == 2)
+	 &&  get_option(&str,&micbias [nr_dev])
+	);
+
+	nr_dev++;
+	return 1;
+}
+
+__setup("es1370=", es1370_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.12/linux/drivers/sound/es1371.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/sound/es1371.c	Fri Aug  6 11:43:09 1999
@@ -68,12 +68,14 @@
  *    15.06.99   0.12  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.13  Add pci_set_master
+ *    03.08.99   0.14  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1371=joystickaddr"
+ *                     removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -2694,13 +2696,7 @@
 /* maximum number of devices */
 #define NR_DEVICE 5
 
-#if CONFIG_SOUND_ES1371_JOYPORT_BOOT
-static int joystick[NR_DEVICE] = { 
-CONFIG_SOUND_ES1371_GAMEPORT
-, 0, };
-#else
 static int joystick[NR_DEVICE] = { 0, };
-#endif
 
 /* --------------------------------------------------------------------- */
 
@@ -2723,11 +2719,10 @@
 	{ SOUND_MIXER_WRITE_IGAIN, 0x4040 }
 };
 
-#ifdef MODULE
-int __init init_module(void)
-#else
-int __init init_es1371(void)
+#ifndef MODULE
+static
 #endif
+int __init init_module(void)
 {
 	struct es1371_state *s;
 	struct pci_dev *pcidev = NULL;
@@ -2736,11 +2731,11 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.13 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.14 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
-		if (pcidev->base_address[0] == 0 || 
-		    (pcidev->base_address[0] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (pcidev->resource[0].flags == 0 || 
+		    (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
 			continue;
 		if (pcidev->irq == 0) 
 			continue;
@@ -2757,7 +2752,7 @@
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
 		s->magic = ES1371_MAGIC;
-		s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+		s->io = pcidev->resource[0].start;
 		s->irq = pcidev->irq;
 		if (check_region(s->io, ES1371_EXTENT)) {
 			printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
@@ -2917,5 +2912,24 @@
 	}
 	printk(KERN_INFO "es1371: unloading\n");
 }
+
+#else /* MODULE */
+
+/* format is: es1371=[joystick] */
+
+static int __init es1371_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+        int ints[11];
+
+	if (nr_dev >= NR_DEVICE)
+		return 0;
+	get_option(&str, &joystick[nr_dev]);
+	nr_dev++;
+	return 1;
+}
+
+__setup("es1371=", es1371_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.12/linux/drivers/sound/esssolo1.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/esssolo1.c	Mon Aug  9 12:13:39 1999
@@ -0,0 +1,2239 @@
+/*****************************************************************************/
+
+/*
+ *      esssolo1.c  --  ESS Technology Solo1 (ES1946) audio driver.
+ *
+ *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *      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.
+ *
+ * Module command line parameters:
+ *   none so far
+ *
+ *  Supported devices:
+ *  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
+ *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
+ *  /dev/midi   simple MIDI UART interface, no ioctl
+ *
+ *  Revision history
+ *    10.11.98   0.1   Initial release (without any hardware)
+ *    22.03.99   0.2   cinfo.blocks should be reset after GETxPTR ioctl.
+ *                     reported by Johan Maes <joma@telindus.be>
+ *                     return EAGAIN instead of EBUSY when O_NONBLOCK
+ *                     read/write cannot be executed
+ *    07.04.99   0.3   implemented the following ioctl's: SOUND_PCM_READ_RATE, 
+ *                     SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
+ *                     Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ *    15.06.99   0.4   Fix bad allocation bug.
+ *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.99   0.5   Add pci_set_master
+ *
+ *
+ */
+
+/*****************************************************************************/
+      
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+
+#include "dm.h"
+
+/* --------------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_ESS
+#define PCI_VENDOR_ID_ESS         0x125d
+#endif
+#ifndef PCI_DEVICE_ID_ESS_SOLO1
+#define PCI_DEVICE_ID_ESS_SOLO1   0x1969
+#endif
+
+#define SOLO1_MAGIC  ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
+
+#define IOBASE_EXTENT             16
+#define SBBASE_EXTENT             16
+#define VCBASE_EXTENT             16
+#define MPUBASE_EXTENT            4
+#define GPBASE_EXTENT             4
+
+
+/* MIDI buffer sizes */
+
+#define MIDIINBUF  256
+#define MIDIOUTBUF 256
+
+#define FMODE_MIDI_SHIFT 3
+#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
+#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
+
+#define FMODE_DMFM 0x10
+
+/* --------------------------------------------------------------------- */
+
+#define DEBUGREC
+
+/* --------------------------------------------------------------------- */
+
+struct solo1_state {
+	/* magic */
+	unsigned int magic;
+
+	/* we keep sb cards in a linked list */
+	struct solo1_state *next;
+
+	/* soundcore stuff */
+	int dev_audio;
+	int dev_mixer;
+	int dev_midi;
+	int dev_dmfm;
+
+	/* hardware resources */
+	unsigned long iobase, sbbase, vcbase, mpubase, gpbase; /* long for SPARC */
+	unsigned int irq;
+
+	/* mixer registers; there is no HW readback */
+	struct {
+		unsigned short vol[10];
+		unsigned int recsrc;
+		unsigned int modcnt;
+		unsigned short micpreamp;
+	} mix;
+
+	/* wave stuff */
+	unsigned fmt;
+	unsigned channels;
+	unsigned rate;
+	unsigned char clkdiv;
+	unsigned ena;
+
+	spinlock_t lock;
+	struct semaphore open_sem;
+	mode_t open_mode;
+	wait_queue_head_t open_wait;
+
+	struct dmabuf {
+		void *rawbuf;
+		unsigned buforder;
+		unsigned numfrag;
+		unsigned fragshift;
+		unsigned hwptr, swptr;
+		unsigned total_bytes;
+		int count;
+		unsigned error; /* over/underrun */
+		wait_queue_head_t wait;
+		/* redundant, but makes calculations easier */
+		unsigned fragsize;
+		unsigned dmasize;
+		unsigned fragsamples;
+		/* OSS stuff */
+		unsigned mapped:1;
+		unsigned ready:1;
+		unsigned endcleared:1;
+		unsigned ossfragshift;
+		int ossmaxfrags;
+		unsigned subdivision;
+	} dma_dac, dma_adc;
+
+	/* midi stuff */
+	struct {
+		unsigned ird, iwr, icnt;
+		unsigned ord, owr, ocnt;
+		wait_queue_head_t iwait;
+		wait_queue_head_t owait;
+		struct timer_list timer;
+		unsigned char ibuf[MIDIINBUF];
+		unsigned char obuf[MIDIOUTBUF];
+	} midi;
+};
+
+/* --------------------------------------------------------------------- */
+
+struct solo1_state *devs = NULL;
+
+/* --------------------------------------------------------------------- */
+
+extern inline void write_seq(struct solo1_state *s, unsigned char data)
+{
+        int i;
+	unsigned long flags;
+        
+	/* the __cli stunt is to send the data within the command window */
+        for (i = 0; i < 0xffff; i++) {
+		__save_flags(flags);
+		__cli();
+                if (!(inb(s->sbbase+0xc) & 0x80)) {
+                        outb(data, s->sbbase+0xc);
+			__restore_flags(flags);
+                        return;
+                }
+		__restore_flags(flags);
+	}
+}
+
+extern inline int read_seq(struct solo1_state *s, unsigned char *data)
+{
+        int i;
+
+        if (!data)
+                return 0;
+        for (i = 0; i < 0xffff; i++)
+                if (inb(s->sbbase+0xe) & 0x80) {
+                        *data = inb(s->sbbase+0xa);
+                        return 1;
+                }
+        return 0;
+}
+
+static int inline reset_ctrl(struct solo1_state *s)
+{
+        int i;
+
+        outb(3, s->sbbase+6); /* clear sequencer and FIFO */
+        udelay(10);
+        outb(0, s->sbbase+6);
+        for (i = 0; i < 0xffff; i++)
+                if (inb(s->sbbase+0xe) & 0x80)
+                        if (inb(s->sbbase+0xa) == 0xaa) {
+				write_seq(s, 0xc6); /* enter enhanced mode */
+                                return 1;
+			}
+        return 0;
+}
+
+static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data)
+{
+	write_seq(s, reg);
+	write_seq(s, data);
+}
+
+static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
+{
+        unsigned char r;
+
+	write_seq(s, 0xc0);
+	write_seq(s, reg);
+	read_seq(s, &r);
+	return r;
+}
+
+static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
+{
+	outb(reg, s->sbbase+4);
+	outb(data, s->sbbase+5);
+}
+
+static unsigned char read_mixer(struct solo1_state *s, unsigned char reg)
+{
+	outb(reg, s->sbbase+4);
+	return inb(s->sbbase+5);
+}
+
+/* --------------------------------------------------------------------- */
+
+extern inline unsigned ld2(unsigned int x)
+{
+	unsigned r = 0;
+	
+	if (x >= 0x10000) {
+		x >>= 16;
+		r += 16;
+	}
+	if (x >= 0x100) {
+		x >>= 8;
+		r += 8;
+	}
+	if (x >= 0x10) {
+		x >>= 4;
+		r += 4;
+	}
+	if (x >= 4) {
+		x >>= 2;
+		r += 2;
+	}
+	if (x >= 2)
+		r++;
+	return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+extern inline void stop_dac(struct solo1_state *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	s->ena &= ~FMODE_WRITE;
+	write_mixer(s, 0x78, 0x10);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void start_dac(struct solo1_state *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+		s->ena |= FMODE_WRITE;
+		write_mixer(s, 0x78, 0x13);
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+}	
+
+extern inline void stop_adc(struct solo1_state *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	s->ena &= ~FMODE_READ;
+	write_ctrl(s, 0xb8, 0xe);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void start_adc(struct solo1_state *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+	    && s->dma_adc.ready) {
+		s->ena |= FMODE_READ;
+		write_ctrl(s, 0xb8, 0xf);
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+                outb(0, s->vcbase+0xd); /* master reset */
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x (a. clr)\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outb(1, s->vcbase+0xf);  /* mask */
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x (a. mask)\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outb(0x54/*0x14*/, s->vcbase+0xb);  /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x (a. wrmode)\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outl(virt_to_bus(s->dma_adc.rawbuf), s->vcbase);
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x (a. wrbase)\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outw(s->dma_adc.dmasize-1, s->vcbase+4);
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x (a. wrcnt)\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outb(0, s->vcbase+0xf);
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x (a. clrmask)\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+#ifdef DEBUGREC
+	printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  DMAmask: 0x%02x  SBstat: 0x%02x\n", 
+	       read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->vcbase+0xf), inb(s->sbbase+0xc));
+
+	printk(KERN_DEBUG "solo1: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"  
+	       KERN_DEBUG "solo1: B1: 0x%02x  B2: 0x%02x  B4: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n",
+	       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 
+	       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), 
+	       read_ctrl(s, 0xb9));
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+extern inline void dealloc_dmabuf(struct dmabuf *db)
+{
+	unsigned long map, mapend;
+
+	if (db->rawbuf) {
+		/* undo marking the pages as reserved */
+		mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+		for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+			clear_bit(PG_reserved, &mem_map[map].flags);	
+		free_pages((unsigned long)db->rawbuf, db->buforder);
+	}
+	db->rawbuf = NULL;
+	db->mapped = db->ready = 0;
+}
+
+static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, int gfp_mask)
+{
+	int order;
+	unsigned bytespersec;
+	unsigned bufs, sample_shift = 0;
+	unsigned long map, mapend;
+
+	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+	if (!db->rawbuf) {
+		db->ready = db->mapped = 0;
+                for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+                        if ((db->rawbuf = (void *)__get_free_pages(gfp_mask, order)))
+				break;
+		if (!db->rawbuf)
+			return -ENOMEM;
+		db->buforder = order;
+		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+		mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+		for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+			set_bit(PG_reserved, &mem_map[map].flags);
+	}
+	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+		sample_shift++;
+	if (s->channels > 1)
+		sample_shift++;
+	bytespersec = s->rate << sample_shift;
+	bufs = PAGE_SIZE << db->buforder;
+	if (db->ossfragshift) {
+		if ((1000 << db->ossfragshift) < bytespersec)
+			db->fragshift = ld2(bytespersec/1000);
+		else
+			db->fragshift = db->ossfragshift;
+	} else {
+		db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));
+		if (db->fragshift < 3)
+			db->fragshift = 3;
+	}
+	db->numfrag = bufs >> db->fragshift;
+	while (db->numfrag < 4 && db->fragshift > 3) {
+		db->fragshift--;
+		db->numfrag = bufs >> db->fragshift;
+	}
+	db->fragsize = 1 << db->fragshift;
+	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+		db->numfrag = db->ossmaxfrags;
+	db->fragsamples = db->fragsize >> sample_shift;
+	db->dmasize = db->numfrag << db->fragshift;
+	return 0;
+}
+
+extern inline int prog_dmabuf_adc(struct solo1_state *s)
+{
+	unsigned long va;
+	int c;
+
+	stop_adc(s);
+	if ((c = prog_dmabuf(s, &s->dma_adc, GFP_KERNEL | GFP_DMA)))
+		return c;
+	va = virt_to_bus(s->dma_adc.rawbuf);
+	if ((va & ~((1<<24)-1)))
+		panic("solo1: buffer above 16M boundary");
+	outb(0, s->vcbase+0xd);  /* clear */
+	outb(1, s->vcbase+0xf); /* mask */
+	//outb(0, s->vcbase+8);  /* enable (enable is active low!) */
+	outb(0x54, s->vcbase+0xb);  /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+	outl(va, s->vcbase);
+	outw(s->dma_adc.dmasize-1, s->vcbase+4);
+	c = - s->dma_adc.fragsamples;
+	write_ctrl(s, 0xa4, c);
+	write_ctrl(s, 0xa5, c >> 8);
+	outb(0, s->vcbase+0xf);
+	s->dma_adc.ready = 1;
+	return 0;
+}
+
+extern inline int prog_dmabuf_dac(struct solo1_state *s)
+{
+	unsigned long va;
+	int c;
+
+	stop_dac(s);
+	if ((c = prog_dmabuf(s, &s->dma_dac, GFP_KERNEL)))
+		return c;
+	memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
+	va = virt_to_bus(s->dma_dac.rawbuf);
+	if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
+		panic("solo1: buffer crosses 1M boundary");
+	outl(va, s->iobase);
+	/* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */
+	outw(s->dma_dac.dmasize, s->iobase+4);
+	c = - s->dma_dac.fragsamples;
+	write_mixer(s, 0x74, c);
+	write_mixer(s, 0x76, c >> 8);
+	outb(0xa, s->iobase+6);
+	s->dma_dac.ready = 1;
+	return 0;
+}
+
+extern inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
+{
+	if (bptr + len > bsize) {
+		unsigned x = bsize - bptr;
+		memset(((char *)buf) + bptr, c, x);
+		bptr = 0;
+		len -= x;
+	}
+	memset(((char *)buf) + bptr, c, len);
+}
+
+/* call with spinlock held! */
+
+static void solo1_update_ptr(struct solo1_state *s)
+{
+	int diff;
+	unsigned hwptr;
+
+	/* update ADC pointer */
+	if (s->ena & FMODE_READ) {
+		hwptr = (s->dma_adc.dmasize - 1 - inw(s->vcbase+4)) % s->dma_adc.dmasize;
+                diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+                s->dma_adc.hwptr = hwptr;
+		s->dma_adc.total_bytes += diff;
+		s->dma_adc.count += diff;
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
+		       s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
+#endif
+		if (s->dma_adc.mapped) {
+			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+				wake_up(&s->dma_adc.wait);
+		} else {
+			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+				s->ena &= ~FMODE_READ;
+				write_ctrl(s, 0xb8, 0xe);
+				s->dma_adc.error++;
+			}
+			if (s->dma_adc.count > 0)
+				wake_up(&s->dma_adc.wait);
+		}
+	}
+	/* update DAC pointer */
+	if (s->ena & FMODE_WRITE) {
+                hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize;
+                diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+                s->dma_dac.hwptr = hwptr;
+		s->dma_dac.total_bytes += diff;
+#if 0
+		printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",
+		       s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);
+#endif
+		if (s->dma_dac.mapped) {
+			s->dma_dac.count += diff;
+			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+				wake_up(&s->dma_dac.wait);
+		} else {
+			s->dma_dac.count -= diff;
+			if (s->dma_dac.count <= 0) {
+				s->ena &= ~FMODE_WRITE;
+				write_mixer(s, 0x78, 0x12);
+				s->dma_dac.error++;
+			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+				clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr,
+					      s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);
+				s->dma_dac.endcleared = 1;
+			}
+			if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+				wake_up(&s->dma_dac.wait);
+		}
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void prog_codec(struct solo1_state *s)
+{
+	unsigned long flags;
+	int fdiv, filter;
+	unsigned char c;
+
+	reset_ctrl(s);
+	write_seq(s, 0xd3);
+	/* program sampling rates */
+	filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */
+	fdiv = 256 - 7160000 / (filter * 82);
+	spin_lock_irqsave(&s->lock, flags);
+	write_ctrl(s, 0xa1, s->clkdiv);
+	write_ctrl(s, 0xa2, fdiv);
+	write_mixer(s, 0x70, s->clkdiv);
+	write_mixer(s, 0x72, fdiv);
+	/* program ADC parameters */
+	write_ctrl(s, 0xb8, 0xe);
+	write_ctrl(s, 0xb9, /*0x1*/0);
+	write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);
+	c = 0xd0;
+	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+		c |= 0x04;
+	if (s->fmt & (AFMT_S16_LE | AFMT_S8))
+		c |= 0x20;
+	if (s->channels > 1)
+		c ^= 0x48;
+	write_ctrl(s, 0xb7, (c & 0x70) | 1);
+	write_ctrl(s, 0xb7, c);
+	write_ctrl(s, 0xb1, 0x50);
+	write_ctrl(s, 0xb2, 0x50);
+	/* program DAC parameters */
+	c = 0x40;
+	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+		c |= 1;
+	if (s->fmt & (AFMT_S16_LE | AFMT_S8))
+		c |= 4;
+	if (s->channels > 1)
+		c |= 2;
+	write_mixer(s, 0x7a, c);
+	write_mixer(s, 0x78, 0x10);
+	s->ena = 0;
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+/* --------------------------------------------------------------------- */
+
+static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";
+
+#define VALIDATE_STATE(s)                         \
+({                                                \
+	if (!(s) || (s)->magic != SOLO1_MAGIC) { \
+		printk(invalid_magic);            \
+		return -ENXIO;                    \
+	}                                         \
+})
+
+/* --------------------------------------------------------------------- */
+
+static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg)
+{
+	static const unsigned int mixer_src[8] = {
+		SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
+		SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
+	};
+	static const unsigned char mixtable[SOUND_MIXER_NRDEVICES] = {
+		[SOUND_MIXER_PCM]    = 0x7c,   /* voice */
+		[SOUND_MIXER_SYNTH]  = 0x36,   /* FM */
+		[SOUND_MIXER_CD]     = 0x38,   /* CD */
+		[SOUND_MIXER_LINE]   = 0x3e,   /* Line */
+		[SOUND_MIXER_LINE1]  = 0x3a,   /* AUX */
+		[SOUND_MIXER_MIC]    = 0x1a,   /* Mic */
+		[SOUND_MIXER_LINE2]  = 0x6d    /* Mono in */
+	};
+	unsigned char l, r, rl, rr;
+	int i, val;
+
+	VALIDATE_STATE(s);
+
+	if (cmd == SOUND_MIXER_PRIVATE1) {
+		/* enable/disable/query mixer preamp */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != -1) {
+			val = val ? 0xff : 0xf7;
+			write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
+		}
+		val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
+		return put_user(val, (int *)arg);
+	}
+	if (cmd == SOUND_MIXER_PRIVATE1) {
+		/* enable/disable/query mixer preamp */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != -1) {
+			val = val ? 0xff : 0xf7;
+			write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
+		}
+		val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
+		return put_user(val, (int *)arg);
+	}
+	if (cmd == SOUND_MIXER_PRIVATE2) {
+		/* enable/disable/query spatializer */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != -1) {
+			val &= 0x3f;
+			write_mixer(s, 0x52, val);
+			write_mixer(s, 0x50, val ? 0x08 : 0);
+		}
+		return put_user(read_mixer(s, 0x52), (int *)arg);
+	}
+        if (cmd == SOUND_MIXER_INFO) {
+		mixer_info info;
+		strncpy(info.id, "Solo1", sizeof(info.id));
+		strncpy(info.name, "ESS Solo1", sizeof(info.name));
+		info.modify_counter = s->mix.modcnt;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == SOUND_OLD_MIXER_INFO) {
+		_old_mixer_info info;
+		strncpy(info.id, "Solo1", sizeof(info.id));
+		strncpy(info.name, "ESS Solo1", sizeof(info.name));
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == OSS_GETVERSION)
+		return put_user(SOUND_VERSION, (int *)arg);
+	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+                return -EINVAL;
+        if (_IOC_DIR(cmd) == _IOC_READ) {
+                switch (_IOC_NR(cmd)) {
+                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+			return put_user(mixer_src[read_mixer(s, 0x1c) & 7], (int *)arg);
+
+                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+					SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+					SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
+					SOUND_MASK_SPEAKER, (int *)arg);
+
+                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+			return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, (int *)arg);
+
+                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
+					SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+					SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, (int *)arg);
+			
+                case SOUND_MIXER_CAPS:
+			return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+
+		case SOUND_MIXER_VOLUME:
+			rl = read_mixer(s, 0x60);
+			rr = read_mixer(s, 0x62);
+			l = (rl * 3 + 11) / 2;
+			if (rl & 0x40)
+				l = 0;
+			r = (rr * 3 + 11) / 2;
+			if (rr & 0x40)
+				r = 0;
+			return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+		case SOUND_MIXER_SPEAKER:
+			rl = read_mixer(s, 0x3c);
+			l = (rl & 7) * 14 + 2;
+			return put_user(l * 0x101, (int *)arg);
+
+		case SOUND_MIXER_RECLEV:
+			rl = read_ctrl(s, 0xb4);
+			r = ((rl & 0xf) * 13 + 5) / 2;
+			l = (((rl >> 4) & 0xf) * 13 + 5) / 2;
+			return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+		default:
+			i = _IOC_NR(cmd);
+                        if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i])
+                                return -EINVAL;
+			rl = read_mixer(s, mixtable[i]);
+			r = ((rl & 0xf) * 13 + 5) / 2;
+			l = (((rl >> 4) & 0xf) * 13 + 5) / 2;
+			return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+		}
+	}
+        if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
+		return -EINVAL;
+	s->mix.modcnt++;
+	switch (_IOC_NR(cmd)) {
+	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+
+	{
+		static const unsigned char regs[] = {
+			0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
+		};
+		int i;
+
+		for (i = 0; i < sizeof(regs); i++)
+			printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
+			       regs[i], read_mixer(s, regs[i]));
+		printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
+		       0xb4, read_ctrl(s, 0xb4));
+	} 
+
+		get_user_ret(val, (int *)arg, -EFAULT);
+                i = hweight32(val);
+                if (i == 0)
+                        return 0;
+                else if (i > 1) 
+                        val &= ~mixer_src[read_mixer(s, 0x1c) & 7];
+		for (i = 0; i < 8; i++) {
+			if (mixer_src[i] & val)
+				break;
+		}
+		if (i > 7)
+			return 0;
+		write_mixer(s, 0x1c, i);
+		return 0;
+
+	case SOUND_MIXER_VOLUME:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		l = val & 0xff;
+		if (l > 100)
+			l = 100;
+		r = (val >> 8) & 0xff;
+		if (r > 100)
+			r = 100;
+		if (l < 6) {
+			rl = 0x40;
+			l = 0;
+		} else {
+			rl = (l * 2 - 11) / 3;
+			l = (rl * 3 + 11) / 2;
+		}
+		if (r < 6) {
+			rr = 0x40;
+			r = 0;
+		} else {
+			rr = (r * 2 - 11) / 3;
+			r = (rr * 3 + 11) / 2;
+		}
+		write_mixer(s, 0x60, rl);
+		write_mixer(s, 0x62, rr);
+		return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+	case SOUND_MIXER_SPEAKER:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		l = val & 0xff;
+		if (l > 100)
+			l = 100;
+		else if (l < 2)
+			l = 2;
+		rl = (l - 2) / 14;
+		l = rl * 14 + 2;
+		write_mixer(s, 0x3c, rl);
+		return put_user(l * 0x101, (int *)arg);
+
+	case SOUND_MIXER_RECLEV:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		l = (val << 1) & 0x1fe;
+		if (l > 200)
+			l = 200;
+		else if (l < 5)
+			l = 5;
+		r = (val >> 7) & 0x1fe;
+		if (r > 200)
+			r = 200;
+		else if (r < 5)
+			r = 5;
+		rl = (l - 5) / 13;
+		rr = (r - 5) / 13;
+		r = (rl * 13 + 5) / 2;
+		l = (rr * 13 + 5) / 2;
+		write_ctrl(s, 0xb4, (rl << 4) | rr);
+		return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+
+	default:
+		i = _IOC_NR(cmd);
+		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i])
+			return -EINVAL;
+		get_user_ret(val, (int *)arg, -EFAULT);
+		l = (val << 1) & 0x1fe;
+		if (l > 200)
+			l = 200;
+		else if (l < 5)
+			l = 5;
+		r = (val >> 7) & 0x1fe;
+		if (r > 200)
+			r = 200;
+		else if (r < 5)
+			r = 5;
+		rl = (l - 5) / 13;
+		rr = (r - 5) / 13;
+		r = (rl * 13 + 5) / 2;
+		l = (rr * 13 + 5) / 2;
+		write_mixer(s, mixtable[i], (rl << 4) | rr);
+		return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static loff_t solo1_llseek(struct file *file, loff_t offset, int origin)
+{
+        return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int solo1_open_mixdev(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct solo1_state *s = devs;
+
+	while (s && s->dev_mixer != minor)
+		s = s->next;
+	if (!s)
+		return -ENODEV;
+       	VALIDATE_STATE(s);
+	file->private_data = s;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int solo1_release_mixdev(struct inode *inode, struct file *file)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	
+	VALIDATE_STATE(s);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);
+}
+
+static /*const*/ struct file_operations solo1_mixer_fops = {
+	&solo1_llseek,
+	NULL,  /* read */
+	NULL,  /* write */
+	NULL,  /* readdir */
+	NULL,  /* poll */
+	&solo1_ioctl_mixdev,
+	NULL,  /* mmap */
+	&solo1_open_mixdev,
+	NULL,  /* flush */
+	&solo1_release_mixdev,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+#if 0
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+static int drain_dac(struct solo1_state *s, int nonblock)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	int count, tmo;
+	
+	if (s->dma_dac.mapped)
+		return 0;
+        current->state = TASK_INTERRUPTIBLE;
+        add_wait_queue(&s->dma_dac.wait, &wait);
+        for (;;) {
+                spin_lock_irqsave(&s->lock, flags);
+		count = s->dma_dac.count;
+                spin_unlock_irqrestore(&s->lock, flags);
+		if (count <= 0)
+			break;
+		if (signal_pending(current))
+                        break;
+                if (nonblock) {
+                        remove_wait_queue(&s->dma_dac.wait, &wait);
+                        current->state = TASK_RUNNING;
+                        return -EBUSY;
+                }
+		tmo = (count * HZ) / s->rate;
+		if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+			tmo >>= 1;
+		if (s->channels > 1)
+			tmo >>= 1;
+                if (!schedule_timeout(tmo ? : 1) && tmo)
+                        printk(KERN_DEBUG "solo1: dma timed out??\n");
+        }
+        remove_wait_queue(&s->dma_dac.wait, &wait);
+        current->state = TASK_RUNNING;
+        if (signal_pending(current))
+                return -ERESTARTSYS;
+        return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+
+	VALIDATE_STATE(s);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (s->dma_adc.mapped)
+		return -ENXIO;
+	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	while (count > 0) {
+		spin_lock_irqsave(&s->lock, flags);
+		swptr = s->dma_adc.swptr;
+		cnt = s->dma_adc.dmasize-swptr;
+		if (s->dma_adc.count < cnt)
+			cnt = s->dma_adc.count;
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (cnt > count)
+			cnt = count;
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x  cnt: %u\n", 
+		       read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc), cnt);
+#endif
+		if (cnt <= 0) {
+			start_adc(s);
+#ifdef DEBUGREC
+			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"
+			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"
+			       KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"  
+			       KERN_DEBUG "solo1_read: SBstat: 0x%02x  cnt: %u\n",
+			       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 
+			       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), 
+			       inl(s->vcbase), inw(s->vcbase+4), inb(s->vcbase+8), inb(s->vcbase+15), inb(s->sbbase+0xc), cnt);
+#endif
+			if (inb(s->vcbase+15) & 1) {
+				printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
+				return -EIO;
+			}
+			if (file->f_flags & O_NONBLOCK)
+				return ret ? ret : -EAGAIN;
+			interruptible_sleep_on(&s->dma_adc.wait);
+#ifdef DEBUGREC
+			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"
+			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"
+			       KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"  
+			       KERN_DEBUG "solo1_read: SBstat: 0x%02x  cnt: %u\n",
+			       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 
+			       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), 
+			       inl(s->vcbase), inw(s->vcbase+4), inb(s->vcbase+8), inb(s->vcbase+15), inb(s->sbbase+0xc), cnt);
+#endif
+			if (signal_pending(current))
+				return ret ? ret : -ERESTARTSYS;
+			continue;
+		}
+		if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
+			return ret ? ret : -EFAULT;
+		swptr = (swptr + cnt) % s->dma_adc.dmasize;
+		spin_lock_irqsave(&s->lock, flags);
+		s->dma_adc.swptr = swptr;
+		s->dma_adc.count -= cnt;
+		spin_unlock_irqrestore(&s->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_adc(s);
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x\n", 
+		       read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc));
+#endif
+	}
+	return ret;
+}
+
+static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+
+	VALIDATE_STATE(s);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (s->dma_dac.mapped)
+		return -ENXIO;
+	if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+		return ret;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+#if 0
+	printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x  71: 0x%02x  72: 0x%02x  74: 0x%02x  76: 0x%02x  78: 0x%02x  7A: 0x%02x\n"
+	       KERN_DEBUG "solo1_write: DMA: addr: 0x%08x  cnt: 0x%04x  stat: 0x%02x  SBstat: 0x%02x\n", 
+	       read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),
+	       read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
+	printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x  reg 7A: 0x%02x  DMAcnt: 0x%04x  DMAstat: 0x%02x  SBstat: 0x%02x\n", 
+	       read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
+#endif
+	ret = 0;
+	while (count > 0) {
+		spin_lock_irqsave(&s->lock, flags);
+		if (s->dma_dac.count < 0) {
+			s->dma_dac.count = 0;
+			s->dma_dac.swptr = s->dma_dac.hwptr;
+		}
+		swptr = s->dma_dac.swptr;
+		cnt = s->dma_dac.dmasize-swptr;
+		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+			cnt = s->dma_dac.dmasize - s->dma_dac.count;
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			start_dac(s);
+			if (file->f_flags & O_NONBLOCK)
+				return ret ? ret : -EAGAIN;
+			interruptible_sleep_on(&s->dma_dac.wait);
+			if (signal_pending(current))
+				return ret ? ret : -ERESTARTSYS;
+			continue;
+		}
+		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+			return ret ? ret : -EFAULT;
+		swptr = (swptr + cnt) % s->dma_dac.dmasize;
+		spin_lock_irqsave(&s->lock, flags);
+		s->dma_dac.swptr = swptr;
+		s->dma_dac.count += cnt;
+		s->dma_dac.endcleared = 0;
+		spin_unlock_irqrestore(&s->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_dac(s);
+	}
+	return ret;
+}
+
+static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	VALIDATE_STATE(s);
+	if (file->f_mode & FMODE_WRITE)
+		poll_wait(file, &s->dma_dac.wait, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &s->dma_adc.wait, wait);
+	spin_lock_irqsave(&s->lock, flags);
+	solo1_update_ptr(s);
+	if (file->f_mode & FMODE_READ) {
+		if (s->dma_adc.mapped) {
+			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+				mask |= POLLIN | POLLRDNORM;
+		} else {
+			if (s->dma_adc.count > 0)
+				mask |= POLLIN | POLLRDNORM;
+		}
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (s->dma_dac.mapped) {
+			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	return mask;
+}
+
+
+static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	struct dmabuf *db;
+	int ret;
+	unsigned long size;
+
+	VALIDATE_STATE(s);
+	if (vma->vm_flags & VM_WRITE) {
+		if ((ret = prog_dmabuf_dac(s)) != 0)
+			return ret;
+		db = &s->dma_dac;
+	} else if (vma->vm_flags & VM_READ) {
+		if ((ret = prog_dmabuf_adc(s)) != 0)
+			return ret;
+		db = &s->dma_adc;
+	} else 
+		return -EINVAL;
+	if (vma->vm_offset != 0)
+		return -EINVAL;
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << db->buforder))
+		return -EINVAL;
+	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+		return -EAGAIN;
+	db->mapped = 1;
+	return 0;
+}
+
+static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	unsigned long flags;
+        audio_buf_info abinfo;
+        count_info cinfo;
+	int val, mapped, ret;
+        int div1, div2;
+        unsigned rate1, rate2;
+
+	VALIDATE_STATE(s);
+        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_SYNC:
+		if (file->f_mode & FMODE_WRITE)
+			return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+		return 0;
+		
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+		
+        case SNDCTL_DSP_RESET:
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			synchronize_irq();
+			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			synchronize_irq();
+			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+		}
+		prog_codec(s);
+		return 0;
+
+        case SNDCTL_DSP_SPEED:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val >= 0) {
+			stop_adc(s);
+			stop_dac(s);
+			s->dma_adc.ready = s->dma_dac.ready = 0;
+			/* program sampling rates */
+			if (val > 48000)
+				val = 48000;
+			if (val < 6300)
+				val = 6300;
+			div1 = (768000 + val / 2) / val;
+			rate1 = (768000 + div1 / 2) / div1;
+			div1 = -div1;
+			div2 = (793800 + val / 2) / val;
+			rate2 = (793800 + div2 / 2) / div2;
+			div2 = (-div2) & 0x7f;
+			if (abs(val - rate2) < abs(val - rate1)) {
+				rate1 = rate2;
+				div1 = div2;
+			}
+			s->rate = rate1;
+			s->clkdiv = div1;
+			prog_codec(s);
+		}
+		return put_user(s->rate, (int *)arg);
+		
+        case SNDCTL_DSP_STEREO:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		stop_adc(s);
+		stop_dac(s);
+		s->dma_adc.ready = s->dma_dac.ready = 0;
+		/* program channels */
+		s->channels = val ? 2 : 1;
+		prog_codec(s);
+		return 0;
+
+        case SNDCTL_DSP_CHANNELS:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 0) {
+			stop_adc(s);
+			stop_dac(s);
+			s->dma_adc.ready = s->dma_dac.ready = 0;
+			/* program channels */
+			s->channels = val ? 2 : 1;
+			prog_codec(s);
+		}
+		return put_user(s->channels, (int *)arg);
+
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+                return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			stop_adc(s);
+			stop_dac(s);
+			s->dma_adc.ready = s->dma_dac.ready = 0;
+			/* program format */
+			if (val != AFMT_S16_LE && val != AFMT_U16_LE && 
+			    val != AFMT_S8 && val != AFMT_U8)
+				val = AFMT_U8;
+			s->fmt = val;
+			prog_codec(s);
+		}
+		return put_user(s->fmt, (int *)arg);
+
+	case SNDCTL_DSP_POST:
+                return 0;
+
+        case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if (file->f_mode & s->ena & FMODE_READ)
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & s->ena & FMODE_WRITE)
+			val |= PCM_ENABLE_OUTPUT;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			if (val & PCM_ENABLE_INPUT) {
+				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+					return ret;
+				start_adc(s);
+				if (inb(s->vcbase+15) & 1)
+					printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
+			} else
+				stop_adc(s);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+					return ret;
+				start_dac(s);
+			} else
+				stop_dac(s);
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
+			return val;
+		spin_lock_irqsave(&s->lock, flags);
+		solo1_update_ptr(s);
+		abinfo.fragsize = s->dma_dac.fragsize;
+                abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+                abinfo.fragstotal = s->dma_dac.numfrag;
+                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
+		spin_unlock_irqrestore(&s->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
+			return val;
+		spin_lock_irqsave(&s->lock, flags);
+		solo1_update_ptr(s);
+		abinfo.fragsize = s->dma_adc.fragsize;
+                abinfo.bytes = s->dma_adc.count;
+                abinfo.fragstotal = s->dma_adc.numfrag;
+                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
+		spin_unlock_irqrestore(&s->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+        case SNDCTL_DSP_NONBLOCK:
+                file->f_flags |= O_NONBLOCK;
+                return 0;
+
+        case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		solo1_update_ptr(s);
+                val = s->dma_dac.count;
+		spin_unlock_irqrestore(&s->lock, flags);
+		return put_user(val, (int *)arg);
+
+        case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		solo1_update_ptr(s);
+                cinfo.bytes = s->dma_adc.total_bytes;
+                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+                cinfo.ptr = s->dma_adc.hwptr;
+		if (s->dma_adc.mapped)
+			s->dma_adc.count &= s->dma_adc.fragsize-1;
+		spin_unlock_irqrestore(&s->lock, flags);
+                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+        case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		solo1_update_ptr(s);
+                cinfo.bytes = s->dma_dac.total_bytes;
+                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+                cinfo.ptr = s->dma_dac.hwptr;
+		if (s->dma_dac.mapped)
+			s->dma_dac.count &= s->dma_dac.fragsize-1;
+		spin_unlock_irqrestore(&s->lock, flags);
+                return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+        case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if ((val = prog_dmabuf_dac(s)))
+				return val;
+			return put_user(s->dma_dac.fragsize, (int *)arg);
+		}
+		if ((val = prog_dmabuf_adc(s)))
+			return val;
+		return put_user(s->dma_adc.fragsize, (int *)arg);
+
+        case SNDCTL_DSP_SETFRAGMENT:
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			s->dma_adc.ossfragshift = val & 0xffff;
+			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+			if (s->dma_adc.ossfragshift < 4)
+				s->dma_adc.ossfragshift = 4;
+			if (s->dma_adc.ossfragshift > 15)
+				s->dma_adc.ossfragshift = 15;
+			if (s->dma_adc.ossmaxfrags < 4)
+				s->dma_adc.ossmaxfrags = 4;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			s->dma_dac.ossfragshift = val & 0xffff;
+			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+			if (s->dma_dac.ossfragshift < 4)
+				s->dma_dac.ossfragshift = 4;
+			if (s->dma_dac.ossfragshift > 15)
+				s->dma_dac.ossfragshift = 15;
+			if (s->dma_dac.ossmaxfrags < 4)
+				s->dma_dac.ossmaxfrags = 4;
+		}
+		return 0;
+
+        case SNDCTL_DSP_SUBDIVIDE:
+		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+			return -EINVAL;
+                get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+		if (file->f_mode & FMODE_READ)
+			s->dma_adc.subdivision = val;
+		if (file->f_mode & FMODE_WRITE)
+			s->dma_dac.subdivision = val;
+		return 0;
+
+        case SOUND_PCM_READ_RATE:
+		return put_user(s->rate, (int *)arg);
+
+        case SOUND_PCM_READ_CHANNELS:
+		return put_user(s->channels, (int *)arg);
+
+        case SOUND_PCM_READ_BITS:
+		return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, (int *)arg);
+
+        case SOUND_PCM_WRITE_FILTER:
+        case SNDCTL_DSP_SETSYNCRO:
+        case SOUND_PCM_READ_FILTER:
+                return -EINVAL;
+		
+	}
+	return mixer_ioctl(s, cmd, arg);
+}
+
+static int solo1_release(struct inode *inode, struct file *file)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+
+	VALIDATE_STATE(s);
+	if (file->f_mode & FMODE_WRITE)
+		drain_dac(s, file->f_flags & O_NONBLOCK);
+	down(&s->open_sem);
+	if (file->f_mode & FMODE_WRITE) {
+		stop_dac(s);
+		outb(0, s->iobase+6);  /* disable DMA */
+		dealloc_dmabuf(&s->dma_dac);
+	}
+	if (file->f_mode & FMODE_READ) {
+		stop_adc(s);
+		outb(1, s->vcbase+0xf); /* mask DMA channel */
+		//outb(0, s->vcbase+0xd); /* DMA master clear */
+		dealloc_dmabuf(&s->dma_adc);
+	}
+	s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
+	up(&s->open_sem);
+	wake_up(&s->open_wait);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int solo1_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct solo1_state *s = devs;
+
+	while (s && ((s->dev_audio ^ minor) & ~0xf))
+		s = s->next;
+	if (!s)
+		return -ENODEV;
+       	VALIDATE_STATE(s);
+	file->private_data = s;
+	/* wait for device to become free */
+	down(&s->open_sem);
+	while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&s->open_sem);
+			return -EBUSY;
+		}
+		up(&s->open_sem);
+		interruptible_sleep_on(&s->open_wait);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		down(&s->open_sem);
+	}
+	s->fmt = AFMT_U8;
+	s->channels = 1;
+	s->rate = 8000;
+	s->clkdiv = 96 | 0x80;
+	s->ena = 0;
+	s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+	s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	up(&s->open_sem);
+	MOD_INC_USE_COUNT;
+	if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) {
+		solo1_release(inode, file);
+		return -ENOMEM;
+	}
+	prog_codec(s);
+	return 0;
+}
+
+static /*const*/ struct file_operations solo1_audio_fops = {
+	&solo1_llseek,
+	&solo1_read,
+	&solo1_write,
+	NULL,  /* readdir */
+	&solo1_poll,
+	&solo1_ioctl,
+	&solo1_mmap,
+	&solo1_open,
+	NULL,  /* flush */
+	&solo1_release,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+#if 0
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+/* hold spinlock for the following! */
+static void solo1_handle_midi(struct solo1_state *s)
+{
+	unsigned char ch;
+	int wake;
+
+	if (!(s->mpubase))
+		return;
+	wake = 0;
+	while (inb(s->mpubase+1) & 0x80) {
+		ch = inb(s->mpubase);
+		if (s->midi.icnt < MIDIINBUF) {
+			s->midi.ibuf[s->midi.iwr] = ch;
+			s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
+			s->midi.icnt++;
+		}
+		wake = 1;
+	}
+	if (wake)
+		wake_up(&s->midi.iwait);
+	wake = 0;
+	while ((inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
+		outb(s->midi.obuf[s->midi.ord], s->mpubase);
+		s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
+		s->midi.ocnt--;
+		if (s->midi.ocnt < MIDIOUTBUF-16)
+			wake = 1;
+	}
+	if (wake)
+		wake_up(&s->midi.owait);
+}
+
+static void solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+        struct solo1_state *s = (struct solo1_state *)dev_id;
+	unsigned int intsrc;
+
+	static unsigned lim = 0;
+	
+	/* fastpath out, to ease interrupt sharing */
+	intsrc = inb(s->iobase+7); /* get interrupt source(s) */
+	if (!intsrc)
+		return;
+	(void)inb(s->sbbase+0xe);  /* clear interrupt */
+#ifdef DEBUGREC
+	if (intsrc & 0x10 && lim < 20) {
+		lim++;
+		printk(KERN_DEBUG "solo1: audio1int reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x\n", 
+		       read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc));
+	}
+	//printk(KERN_DEBUG "solo1: interrupt 0x%02x\n", intsrc);
+#endif
+	spin_lock(&s->lock);
+	/* clear audio interrupts first */
+	if (intsrc & 0x20)
+		write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f);
+	solo1_update_ptr(s);
+	solo1_handle_midi(s);
+	spin_unlock(&s->lock);
+}
+
+static void solo1_midi_timer(unsigned long data)
+{
+	struct solo1_state *s = (struct solo1_state *)data;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&s->lock, flags);
+	solo1_handle_midi(s);
+	spin_unlock_irqrestore(&s->lock, flags);
+	s->midi.timer.expires = jiffies+1;
+	add_timer(&s->midi.timer);
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned ptr;
+	int cnt;
+
+	VALIDATE_STATE(s);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	while (count > 0) {
+		spin_lock_irqsave(&s->lock, flags);
+		ptr = s->midi.ird;
+		cnt = MIDIINBUF - ptr;
+		if (s->midi.icnt < cnt)
+			cnt = s->midi.icnt;
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			if (file->f_flags & O_NONBLOCK)
+				return ret ? ret : -EAGAIN;
+			interruptible_sleep_on(&s->midi.iwait);
+			if (signal_pending(current))
+				return ret ? ret : -ERESTARTSYS;
+			continue;
+		}
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+			return ret ? ret : -EFAULT;
+		ptr = (ptr + cnt) % MIDIINBUF;
+		spin_lock_irqsave(&s->lock, flags);
+		s->midi.ird = ptr;
+		s->midi.icnt -= cnt;
+		spin_unlock_irqrestore(&s->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+	}
+	return ret;
+}
+
+static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned ptr;
+	int cnt;
+
+	VALIDATE_STATE(s);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	ret = 0;
+	while (count > 0) {
+		spin_lock_irqsave(&s->lock, flags);
+		ptr = s->midi.owr;
+		cnt = MIDIOUTBUF - ptr;
+		if (s->midi.ocnt + cnt > MIDIOUTBUF)
+			cnt = MIDIOUTBUF - s->midi.ocnt;
+		if (cnt <= 0)
+			solo1_handle_midi(s);
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			if (file->f_flags & O_NONBLOCK)
+				return ret ? ret : -EAGAIN;
+			interruptible_sleep_on(&s->midi.owait);
+			if (signal_pending(current))
+				return ret ? ret : -ERESTARTSYS;
+			continue;
+		}
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+			return ret ? ret : -EFAULT;
+		ptr = (ptr + cnt) % MIDIOUTBUF;
+		spin_lock_irqsave(&s->lock, flags);
+		s->midi.owr = ptr;
+		s->midi.ocnt += cnt;
+		spin_unlock_irqrestore(&s->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		spin_lock_irqsave(&s->lock, flags);
+		solo1_handle_midi(s);
+		spin_unlock_irqrestore(&s->lock, flags);
+	}
+	return ret;
+}
+
+static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	VALIDATE_STATE(s);
+	if (file->f_flags & FMODE_WRITE)
+		poll_wait(file, &s->midi.owait, wait);
+	if (file->f_flags & FMODE_READ)
+		poll_wait(file, &s->midi.iwait, wait);
+	spin_lock_irqsave(&s->lock, flags);
+	if (file->f_flags & FMODE_READ) {
+		if (s->midi.icnt > 0)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_flags & FMODE_WRITE) {
+		if (s->midi.ocnt < MIDIOUTBUF)
+			mask |= POLLOUT | POLLWRNORM;
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	return mask;
+}
+
+static int solo1_midi_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct solo1_state *s = devs;
+	unsigned long flags;
+
+	while (s && s->dev_midi != minor)
+		s = s->next;
+	if (!s)
+		return -ENODEV;
+       	VALIDATE_STATE(s);
+	file->private_data = s;
+	/* wait for device to become free */
+	down(&s->open_sem);
+	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&s->open_sem);
+			return -EBUSY;
+		}
+		up(&s->open_sem);
+		interruptible_sleep_on(&s->open_wait);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		down(&s->open_sem);
+	}
+	spin_lock_irqsave(&s->lock, flags);
+	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+		outb(0xff, s->mpubase+1); /* reset command */
+		outb(0x3f, s->mpubase+1); /* uart command */
+		if (!(inb(s->mpubase+1) & 0x80))
+			inb(s->mpubase);
+		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+		outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */
+		init_timer(&s->midi.timer);
+		s->midi.timer.expires = jiffies+1;
+		s->midi.timer.data = (unsigned long)s;
+		s->midi.timer.function = solo1_midi_timer;
+		add_timer(&s->midi.timer);
+	}
+	if (file->f_mode & FMODE_READ) {
+		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+	up(&s->open_sem);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int solo1_midi_release(struct inode *inode, struct file *file)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	unsigned count, tmo;
+
+	VALIDATE_STATE(s);
+
+	if (file->f_mode & FMODE_WRITE) {
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&s->midi.owait, &wait);
+		for (;;) {
+			spin_lock_irqsave(&s->lock, flags);
+			count = s->midi.ocnt;
+			spin_unlock_irqrestore(&s->lock, flags);
+			if (count <= 0)
+				break;
+			if (signal_pending(current))
+				break;
+			if (file->f_flags & O_NONBLOCK) {
+				remove_wait_queue(&s->midi.owait, &wait);
+				current->state = TASK_RUNNING;
+				return -EBUSY;
+			}
+			tmo = (count * HZ) / 3100;
+			if (!schedule_timeout(tmo ? : 1) && tmo)
+				printk(KERN_DEBUG "solo1: midi timed out??\n");
+		}
+		remove_wait_queue(&s->midi.owait, &wait);
+		current->state = TASK_RUNNING;
+	}
+	down(&s->open_sem);
+	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+	spin_lock_irqsave(&s->lock, flags);
+	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
+		outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
+		del_timer(&s->midi.timer);		
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	up(&s->open_sem);
+	wake_up(&s->open_wait);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static /*const*/ struct file_operations solo1_midi_fops = {
+	&solo1_llseek,
+	&solo1_midi_read,
+	&solo1_midi_write,
+	NULL,  /* readdir */
+	&solo1_midi_poll,
+	NULL,  /* ioctl */
+	NULL,  /* mmap */
+	&solo1_midi_open,
+	NULL,  /* flush */
+	&solo1_midi_release,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+#if 0
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	static const unsigned char op_offset[18] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15
+	};
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	struct dm_fm_voice v;
+	struct dm_fm_note n;
+	struct dm_fm_params p;
+	unsigned int io;
+	unsigned int regb;
+
+	switch (cmd) {		
+	case FM_IOCTL_RESET:
+		for (regb = 0xb0; regb < 0xb9; regb++) {
+			outb(regb, s->sbbase);
+			outb(0, s->sbbase+1);
+			outb(regb, s->sbbase+2);
+			outb(0, s->sbbase+3);
+		}
+		return 0;
+
+	case FM_IOCTL_PLAY_NOTE:
+		if (copy_from_user(&n, (void *)arg, sizeof(n)))
+			return -EFAULT;
+		if (n.voice >= 18)
+			return -EINVAL;
+		if (n.voice >= 9) {
+			regb = n.voice - 9;
+			io = s->sbbase+2;
+		} else {
+			regb = n.voice;
+			io = s->sbbase;
+		}
+		outb(0xa0 + regb, io);
+		outb(n.fnum & 0xff, io+1);
+		outb(0xb0 + regb, io);
+		outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
+		return 0;
+
+	case FM_IOCTL_SET_VOICE:
+		if (copy_from_user(&v, (void *)arg, sizeof(v)))
+			return -EFAULT;
+		if (v.voice >= 18)
+			return -EINVAL;
+		regb = op_offset[v.voice];
+		io = s->sbbase + ((v.op & 1) << 1);
+		outb(0x20 + regb, io);
+		outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | 
+		     ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
+		outb(0x40 + regb, io);
+		outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
+		outb(0x60 + regb, io);
+		outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
+		outb(0x80 + regb, io);
+		outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
+		outb(0xe0 + regb, io);
+		outb(v.waveform & 0x7, io+1);
+		if (n.voice >= 9) {
+			regb = n.voice - 9;
+			io = s->sbbase+2;
+		} else {
+			regb = n.voice;
+			io = s->sbbase;
+		}
+		outb(0xc0 + regb, io);
+		outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
+		     (v.connection & 1), io+1);
+		return 0;
+		
+	case FM_IOCTL_SET_PARAMS:
+		if (copy_from_user(&p, (void *)arg, sizeof(p)))
+			return -EFAULT;
+		outb(0x08, s->sbbase);
+		outb((p.kbd_split & 1) << 6, s->sbbase+1);
+		outb(0xbd, s->sbbase);
+		outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
+		     ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);
+		return 0;
+
+	case FM_IOCTL_SET_OPL:
+		outb(4, s->sbbase+2);
+		outb(arg, s->sbbase+3);
+		return 0;
+
+	case FM_IOCTL_SET_MODE:
+		outb(5, s->sbbase+2);
+		outb(arg & 1, s->sbbase+3);
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int solo1_dmfm_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct solo1_state *s = devs;
+
+	while (s && s->dev_dmfm != minor)
+		s = s->next;
+	if (!s)
+		return -ENODEV;
+       	VALIDATE_STATE(s);
+	file->private_data = s;
+	/* wait for device to become free */
+	down(&s->open_sem);
+	while (s->open_mode & FMODE_DMFM) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&s->open_sem);
+			return -EBUSY;
+		}
+		up(&s->open_sem);
+		interruptible_sleep_on(&s->open_wait);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		down(&s->open_sem);
+	}
+	/* init the stuff */
+	outb(1, s->sbbase);
+	outb(0x20, s->sbbase+1); /* enable waveforms */
+	outb(4, s->sbbase+2);
+	outb(0, s->sbbase+3);  /* no 4op enabled */
+	outb(5, s->sbbase+2);
+	outb(1, s->sbbase+3);  /* enable OPL3 */
+	s->open_mode |= FMODE_DMFM;
+	up(&s->open_sem);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int solo1_dmfm_release(struct inode *inode, struct file *file)
+{
+	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	unsigned int regb;
+
+	VALIDATE_STATE(s);
+	down(&s->open_sem);
+	s->open_mode &= ~FMODE_DMFM;
+	for (regb = 0xb0; regb < 0xb9; regb++) {
+		outb(regb, s->sbbase);
+		outb(0, s->sbbase+1);
+		outb(regb, s->sbbase+2);
+		outb(0, s->sbbase+3);
+	}
+	up(&s->open_sem);
+	wake_up(&s->open_wait);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static /*const*/ struct file_operations solo1_dmfm_fops = {
+	&solo1_llseek,
+	NULL,  /* read */
+	NULL,  /* write */
+	NULL,  /* readdir */
+	NULL,  /* poll */
+	&solo1_dmfm_ioctl,
+	NULL,  /* mmap */
+	&solo1_dmfm_open,
+	NULL,  /* flush */
+	&solo1_dmfm_release,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+#if 0
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+
+/* maximum number of devices */
+#define NR_DEVICE 5
+
+/* --------------------------------------------------------------------- */
+
+static struct initvol {
+	int mixch;
+	int vol;
+} initvol[] __initdata = {
+	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
+	{ SOUND_MIXER_WRITE_PCM, 0x4040 },
+	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
+	{ SOUND_MIXER_WRITE_CD, 0x4040 },
+	{ SOUND_MIXER_WRITE_LINE, 0x4040 },
+	{ SOUND_MIXER_WRITE_LINE1, 0x4040 },
+	{ SOUND_MIXER_WRITE_LINE2, 0x4040 },
+	{ SOUND_MIXER_WRITE_RECLEV, 0x4040 },
+	{ SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
+	{ SOUND_MIXER_WRITE_MIC, 0x4040 }
+};
+
+static int __init init_solo1(void)
+{
+	struct solo1_state *s;
+	struct pci_dev *pcidev = NULL;
+	mm_segment_t fs;
+	int i, val, index = 0;
+	u16 ddmabase;
+
+	if (!pci_present())   /* No PCI bus in this machine! */
+		return -ENODEV;
+	printk(KERN_INFO "solo1: version v0.5 time " __TIME__ " " __DATE__ "\n");
+	while (index < NR_DEVICE && 
+	       (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
+		if (pcidev->resource[0].start == 0 ||
+		    (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
+		    pcidev->resource[1].start == 0 ||
+		    (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
+		    pcidev->resource[2].start == 0 ||
+		    (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
+		    pcidev->resource[3].start == 0 ||
+		    (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+			continue;
+		if (pcidev->irq == 0)
+			continue;
+		if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
+			printk(KERN_WARNING "solo1: out of memory\n");
+			continue;
+		}
+		memset(s, 0, sizeof(struct solo1_state));
+		init_waitqueue_head(&s->dma_adc.wait);
+		init_waitqueue_head(&s->dma_dac.wait);
+		init_waitqueue_head(&s->open_wait);
+		init_waitqueue_head(&s->midi.iwait);
+		init_waitqueue_head(&s->midi.owait);
+		init_MUTEX(&s->open_sem);
+		s->magic = SOLO1_MAGIC;
+		s->iobase = pcidev->resource[0].start;
+		s->sbbase = pcidev->resource[1].start;
+		s->vcbase = pcidev->resource[2].start;
+		s->mpubase = pcidev->resource[3].start;
+		s->gpbase = pcidev->resource[4].start;
+		s->irq = pcidev->irq;
+		if (check_region(s->iobase, IOBASE_EXTENT) ||
+		    check_region(s->sbbase, SBBASE_EXTENT) ||
+		    check_region(s->vcbase, VCBASE_EXTENT) ||
+		    check_region(s->mpubase, MPUBASE_EXTENT)) {
+			printk(KERN_ERR "solo1: io ports in use\n");
+			goto err_region;
+		}
+		request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
+		request_region(s->sbbase, SBBASE_EXTENT, "ESS Solo1");
+		request_region(s->vcbase, VCBASE_EXTENT, "ESS Solo1");
+		request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
+		if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
+			printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
+			goto err_irq;
+		}
+		/* initialize DDMA base address */
+		/* use PCI config reg, and not vcbase, we need the bus view */
+		pci_read_config_word(pcidev, 0x18, &ddmabase);
+		pci_write_config_word(pcidev, 0x60, (ddmabase & (~0xf)) | 1);
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		/* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
+		pci_write_config_dword(pcidev, 0x50, 0);
+		/* disable legacy audio address decode */
+		pci_write_config_word(pcidev, 0x40, 0x907f);
+
+		printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
+
+		/* register devices */
+		if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0)
+			goto err_dev1;
+		if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0)
+			goto err_dev2;
+		if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0)
+			goto err_dev3;
+		if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
+			goto err_dev4;
+		/* initialize the chips */
+		outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
+
+		/* initialize mixer regs */
+		write_mixer(s, 0x7f, 0); /* disable music digital recording */
+		write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
+		write_mixer(s, 0x64, 0x45); /* volume control */
+		write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
+		write_mixer(s, 0x50, 0);  /* disable spatializer */
+		write_mixer(s, 0x52, 0);
+		write_mixer(s, 0x14, 0);  /* DAC1 minimum volume */
+		write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outb(0, s->vcbase+0xd); /* DMA master clear */
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		outb(1, s->vcbase+0xf); /* mask channel */
+#ifdef DEBUGREC
+		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x\n", 
+		       inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+#endif
+		//outb(0, s->vcbase+0x8); /* enable controller (enable is low active!!) */
+
+		pci_set_master(pcidev);  /* enable bus mastering */
+		
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+		val = SOUND_MASK_LINE;
+		mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+		for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+			val = initvol[i].vol;
+			mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+		}
+		set_fs(fs);
+		/* queue it for later freeing */
+		s->next = devs;
+		devs = s;
+		index++;
+		continue;
+
+	err_dev4:
+		unregister_sound_dsp(s->dev_midi);
+	err_dev3:
+		unregister_sound_mixer(s->dev_mixer);
+	err_dev2:
+		unregister_sound_dsp(s->dev_audio);
+	err_dev1:
+		printk(KERN_ERR "solo1: cannot register misc device\n");
+		free_irq(s->irq, s);
+	err_irq:
+		release_region(s->iobase, IOBASE_EXTENT);
+		release_region(s->sbbase, SBBASE_EXTENT);
+		release_region(s->vcbase, VCBASE_EXTENT);
+		release_region(s->mpubase, MPUBASE_EXTENT);
+	err_region:
+		kfree_s(s, sizeof(struct solo1_state));
+	}
+	if (!devs)
+		return -ENODEV;
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
+MODULE_DESCRIPTION("ESS Solo1 Driver");
+
+static void __exit cleanup_solo1(void)
+{
+	struct solo1_state *s;
+
+	while ((s = devs)) {
+		devs = devs->next;
+		/* stop DMA controller */
+		outb(0, s->iobase+6);
+		outb(0, s->vcbase+0xd); /* DMA master clear */
+		outb(3, s->sbbase+6); /* reset sequencer and FIFO */
+		synchronize_irq();
+		free_irq(s->irq, s);
+		release_region(s->iobase, IOBASE_EXTENT);
+		release_region(s->sbbase, SBBASE_EXTENT);
+		release_region(s->vcbase, VCBASE_EXTENT);
+		release_region(s->mpubase, MPUBASE_EXTENT);
+		unregister_sound_dsp(s->dev_audio);
+		unregister_sound_mixer(s->dev_mixer);
+		unregister_sound_midi(s->dev_midi);
+		unregister_sound_special(s->dev_dmfm);
+		kfree_s(s, sizeof(struct solo1_state));
+	}
+	printk(KERN_INFO "solo1: unloading\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+module_init(init_solo1);
+module_exit(cleanup_solo1);
+
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/lowlevel/awe_compat-fbsd.h linux/drivers/sound/lowlevel/awe_compat-fbsd.h
--- v2.3.12/linux/drivers/sound/lowlevel/awe_compat-fbsd.h	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sound/lowlevel/awe_compat-fbsd.h	Thu Aug  5 14:43:32 1999
@@ -51,6 +51,7 @@
 
 #ifdef AWE_OBSOLETE_VOXWARE
 
+#include <i386/isa/sound/sound_config.h>
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32)
 #define CONFIG_AWE32_SYNTH
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.3.12/linux/drivers/sound/maui.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sound/maui.c	Wed Aug  4 16:36:41 1999
@@ -23,7 +23,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 #define USE_SEQ_MACROS
 #define USE_SIMPLE_MACROS
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.3.12/linux/drivers/sound/sb_common.c	Wed May 26 09:35:00 1999
+++ linux/drivers/sound/sb_common.c	Wed Aug  4 15:48:00 1999
@@ -18,7 +18,7 @@
  */
 #include <linux/config.h>
 #include <linux/delay.h>
-#include <asm/init.h>
+#include <linux/init.h>
 
 #include "sound_config.h"
 #include "sound_firmware.h"
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.12/linux/drivers/sound/sonicvibes.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/sound/sonicvibes.c	Fri Aug  6 11:43:09 1999
@@ -71,6 +71,8 @@
  *    15.06.99   0.15  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.16  Add pci_set_master
+ *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
  *
  */
 
@@ -2312,11 +2314,10 @@
 	{ SOUND_MIXER_WRITE_PCM, 0x4040 }
 };
 
-#ifdef MODULE
-int __init init_module(void)
-#else
-int __init init_sonicvibes(void)
+#ifndef MODULE
+static
 #endif
+int __init init_module(void)
 {
 	struct sv_state *s;
 	struct pci_dev *pcidev = NULL;
@@ -2325,21 +2326,21 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.16 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.17 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
 #endif
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) {
-		if (pcidev->base_address[1] == 0 || 
-		    (pcidev->base_address[1] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (pcidev->resource[1].flags == 0 || 
+		    (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
 			continue;
-		if (pcidev->base_address[2] == 0 || 
-		    (pcidev->base_address[2] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (pcidev->resource[2].flags == 0 || 
+		    (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
 			continue;
-		if (pcidev->base_address[3] == 0 || 
-		    (pcidev->base_address[3] & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (pcidev->resource[3].flags == 0 || 
+		    (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
 			continue;
 		if (pcidev->irq == 0)
 			continue;
@@ -2355,11 +2356,11 @@
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
 		s->magic = SV_MAGIC;
-		s->iosb = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-		s->ioenh = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
-		s->iosynth = pcidev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
-		s->iomidi = pcidev->base_address[3] & PCI_BASE_ADDRESS_IO_MASK;
-		s->iogame = pcidev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+		s->iosb = pcidev->resource[0].start;
+		s->ioenh = pcidev->resource[1].start;
+		s->iosynth = pcidev->resource[2].start;
+		s->iomidi = pcidev->resource[3].start;
+		s->iogame = pcidev->resource[4].start;
 		pci_read_config_dword(pcidev, 0x40, &s->iodmaa);
 		pci_read_config_dword(pcidev, 0x48, &s->iodmac);
 		dmaio &= ~(SV_EXTENT_DMA-1);
@@ -2525,8 +2526,8 @@
 		synchronize_irq();
 		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
 		wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-		//outb(0, s->iodmaa + SV_DMA_RESET);
-		//outb(0, s->iodmac + SV_DMA_RESET);
+		/*outb(0, s->iodmaa + SV_DMA_RESET);*/
+		/*outb(0, s->iodmac + SV_DMA_RESET);*/
 		free_irq(s->irq, s);
 		release_region(s->iodmac, SV_EXTENT_DMA);
 		release_region(s->iodmaa, SV_EXTENT_DMA);
@@ -2543,5 +2544,40 @@
 		free_pages(wavetable_mem, 20-PAGE_SHIFT);
 	printk(KERN_INFO "sv: unloading\n");
 }
+
+#else /* MODULE */
+
+/* format is: sonicvibes=[reverb] sonicvibesdmaio=dmaioaddr */
+
+static int __init sonicvibes_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= NR_DEVICE)
+		return 0;
+
+	(   (get_option(&str, &reverb   [nr_dev]) == 2)
+#if 0
+	 &&  get_option(&str, &wavetable[nr_dev])
+#endif
+	};
+
+	nr_dev++;
+	return 1;
+}
+
+static int __init sonicvibesdmaio_setup(char *str)
+{
+        int ints[11];
+
+        get_options(str, ints);
+	if (ints[0] >= 1)
+		dmaio = ints[1];
+	return 1;
+}
+
+__setup("sonicvibes=", sonicvibes_setup);
+__setup("sonicvibesdmaio=", sonicvibesdmaio_setup);
+__initcall(init_module);
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.12/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- v2.3.12/linux/drivers/sound/sound_core.c	Mon Jun  7 11:06:10 1999
+++ linux/drivers/sound/sound_core.c	Wed Aug  4 09:27:54 1999
@@ -52,15 +52,6 @@
 	struct sound_unit *next;
 };
 
-#ifdef CONFIG_SOUND_SONICVIBES
-extern int init_sonicvibes(void);
-#endif
-#ifdef CONFIG_SOUND_ES1370
-extern int init_es1370(void);
-#endif
-#ifdef CONFIG_SOUND_ES1371
-extern int init_es1371(void);
-#endif
 #ifdef CONFIG_SOUND_MSNDCLAS
 extern int msnd_classic_init(void);
 #endif
@@ -395,17 +386,8 @@
 	/*
 	 *	Now init non OSS drivers
 	 */
-#ifdef CONFIG_SOUND_SONICVIBES
-	init_sonicvibes();
-#endif
 #ifdef CONFIG_SOUND_CMPCI
 	init_cmpci();
-#endif
-#ifdef CONFIG_SOUND_ES1370
-	init_es1370();
-#endif
-#ifdef CONFIG_SOUND_ES1371
-	init_es1371();
 #endif
 #ifdef CONFIG_SOUND_MSNDCLAS
 	msnd_classic_init();
diff -u --recursive --new-file v2.3.12/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
--- v2.3.12/linux/drivers/tc/tc.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/tc/tc.c	Wed Aug  4 16:36:45 1999
@@ -12,7 +12,7 @@
  */
 
 #include <linux/string.h>
-#include <asm/init.h>
+#include <linux/init.h>
 #include <asm/addrspace.h>
 #include <asm/errno.h>
 #include <asm/dec/machtype.h>
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- v2.3.12/linux/drivers/usb/CREDITS	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/CREDITS	Mon Aug  2 14:29:08 1999
@@ -31,6 +31,10 @@
         The following corporations have helped us in the development
         of Linux USB / UUSBD:
 
+	- 3Com GmbH for donating a ISDN Pro TA and supporting me
+	  in technical questions and with test equipment. I'd never 
+	  expect such a great help.
+
         - USAR Systems provided us with one of their excellent USB
           Evaluation Kits. It allows us to test the Linux-USB driver
           for compilance with the latest USB specification. USAR
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.12/linux/drivers/usb/Config.in	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/Config.in	Mon Aug  9 12:15:53 1999
@@ -28,13 +28,15 @@
   dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
   dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
   dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
-  dep_tristate 'USB Abstract Control Model support' CONFIG_USB_ACM $CONFIG_USB
+  dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
   dep_tristate 'USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+  dep_tristate 'USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
   dep_tristate 'USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
   if [ "$CONFIG_USB_SCSI" != "n" ]; then
 	  dep_tristate '  USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
   fi
   dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
+  dep_tristate 'USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
   if [ "$CONFIG_PROC_FS" != "n" ]; then
   	bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC
   fi
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.12/linux/drivers/usb/Makefile	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/Makefile	Mon Aug  9 12:15:53 1999
@@ -85,6 +85,15 @@
   MIX_OBJS += printer.o  
 endif
 
+ifeq ($(CONFIG_USB_CPIA),y)
+  L_OBJS += cpia.o
+endif
+
+ifeq ($(CONFIG_USB_CPIA),m)
+  M_OBJS += cpia.o
+  MIX_OBJS += cpia.o  
+endif
+
 ifeq ($(CONFIG_USB_KBD),y)
   L_OBJS += keyboard.o keymap.o
 endif
@@ -119,6 +128,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_USB_SCSI),m)
+  M_OBJS += usb-scsi.o
+  MIX_OBJS += usb_scsi.o
+  ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
+    MIX_OBJS += usb_scsi_debug.o
+  endif
+endif
+
 ifeq ($(CONFIG_USB_EZUSB),y)
   L_OBJS += ezusb.o
 endif
@@ -128,6 +145,15 @@
   MIX_OBJS += ezusb.o
 endif
 
+ifeq ($(CONFIG_USB_USS720),y)
+  L_OBJS += uss720.o
+endif
+
+ifeq ($(CONFIG_USB_USS720),m)
+  M_OBJS += uss720.o
+  MIX_OBJS += uss720.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 keymap.o: keymap.c
@@ -145,6 +171,14 @@
 else
 usb-keyboard.o: keymap-mac.o keyboard.o
 	$(LD) $(LD_RFLAG) -r -o $@  keymap-mac.o keyboard.o 
+endif
+
+ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
+usb-scsi.o: usb_scsi.o usb_scsi_debug.o
+	$(LD) $(LD_RFLAG) -r -o $@  usb_scsi.o usb_scsi_debug.o 
+else
+usb-scsi.o: usb_scsi.o
+	$(LD) $(LD_RFLAG) -r -o $@  usb_scsi.o
 endif
 
 usb-uhci.o: uhci.o uhci-debug.o 
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/README.acm linux/drivers/usb/README.acm
--- v2.3.12/linux/drivers/usb/README.acm	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/README.acm	Mon Aug  2 14:29:08 1999
@@ -0,0 +1,94 @@
+The ACM driver works with modems and ISDN TAs that use the USB Abstract
+Control Model standard. 
+
+****************************
+Test it:
+Watch out, the driver is not stable and tested. Sync often, make backups,
+most importand: don't blame me...
+
+Create device files:
+mknod /dev/ttyACM0 c 166 0
+mknod /dev/ttyACM1 c 166 1
+mknod /dev/ttyACM2 c 166 2
+mknod /dev/ttyACM3 c 166 3
+Compile a kernel with support for your host controller (uhci only for now!)
+and support for ACM. Boot this kernel. If you connect your device to the
+USB bus you should see messages like the following:
+
+Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
+Jul 19 20:14:29 office kernel: Found 02:09
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office last message repeated 2 times
+Jul 19 20:14:29 office kernel: parsed = 39 len = 67
+Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
+Jul 19 20:14:29 office kernel:    0 09
+Jul 19 20:14:29 office kernel:    1 02
+Jul 19 20:14:29 office kernel:    2 43
+Jul 19 20:14:29 office kernel:    3 00
+Jul 19 20:14:29 office kernel:    4 02
+Jul 19 20:14:29 office kernel:    5 02
+Jul 19 20:14:29 office kernel:    6 04
+Jul 19 20:14:29 office kernel:    7 60
+Jul 19 20:14:29 office kernel:    8 00
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 02:09
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: parsed = 67 len = 0
+Jul 19 20:14:29 office kernel: getstringtable
+Jul 19 20:14:29 office kernel: acm_probe
+Jul 19 20:14:29 office kernel: USB ACM found
+
+Watch out for the line:
+Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
+and the line:
+Jul 19 20:14:29 office kernel: USB ACM found
+These two lines show that the device was seen by the usb host controller and
+then recognized by the acm driver as a valid device.
+
+If you use a terminal emulation software like minicom with /dev/ttyACM0 you
+should be able to send AT commands to your device and get responses. I've 
+been able to do zmodem downloads to another pc. However downloads from one
+ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
+know why. Flow control is not finised after all and i'd guess there might
+be problems on heavily loades PCs. I also did some tests with ppp but i'm
+not finised with this. There might be a chance to get it working. However
+i'd like to know if your device is recognized as an ACM device. I'm also
+interested if the thing is stable or if it crashes.
+(should i say how it crases?)
+
+You should be able to add and remove devices from the bus. The driver will
+always try to fill up unused ttys. This means if you hotplug devices their
+order may have changed after reboot. This is not the behaviour Linus liked
+to see but it's ok for now. (I hope ;-)
+
+Please report your experiences to me:
+fuerst@in.tum.de
+
+***************************
+I've tested it with:
+3Com ISDN Pro TA.
+
+It should work with (That means i know these devices conform to ACM):
+3Com Office Connect Modem
+3Com Sportster USB (I think that's what it's called)
+
+***************************
+Many thanks to 3Com which did not only support me with hardware but also
+with technical support in USB questions. They also allowed me to do tests in
+their lab. Great!
+
+***************************
+Known bugs:
+Flow control not tested (likely not to work)
+Some tty function calls not implemented (putchar, etc...)
+Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
+Not all mem is freed at close (need terminate irq in hcd)
+
+***************************
+Have fun,
+	Armin Fuerst
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.12/linux/drivers/usb/acm.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/acm.c	Mon Aug  2 14:29:08 1999
@@ -3,6 +3,35 @@
  *
  * Armin Fuerst 5/8/1999
  *
+ * version 0.7: Added usb flow control. Fixed bug in uhci.c (what idiot
+ * wrote this code? ...Oops that was me). Fixed module cleanup. Did some
+ * testing at 3Com => zmodem uload+download works, pppd had trouble but
+ * seems to work now. Changed Menuconfig texts "Communications Device
+ * Class (ACM)" might be a bit more intuitive. Ported to 2.3.13-1 prepatch. 
+ * (2/8/99)
+ *
+ * version 0.6: Modularized driver, added disconnect code, improved
+ * assignment of device to tty minor number.
+ * (21/7/99)
+ *
+ * version 0.5: Driver now generates a tty instead of a simple character
+ * device. Moved async bulk transfer to 2.3.10 kernel version. fixed a bug
+ * in uhci_td_allocate. Commenetd out getstringtable which causes crash.
+ * (13/7/99)
+ *
+ * version 0.4: Small fixes in the FIFO, cleanup. Updated Bulk transfer in 
+ * uhci.c. Should have the correct interface now. 
+ * (6/6/99)
+ *
+ * version 0.5 driver now generates a tty instead of a simple character
+ * device
+ *
+ * version 0.3: Mayor changes. Changed Bulk transfer to interrupt based
+ * transfer. Using FIFO Buffers now. Consistent handling of open/close
+ * file state and detected/nondetected device. File operations behave
+ * according to this. Driver is able to send+receive now! Heureka!
+ * (27/5/99)
+ *
  * version 0.2: Improved Bulk transfer. TX led now flashes every time data is
  * sent. Send Encapsulated Data is not needed, nor does it do anything.
  * Why's that ?!? Thanks to Thomas Sailer for his close look at the bulk code.
@@ -22,171 +51,448 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/miscdevice.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
 #include <linux/module.h>
-
+//#include <sys/ioctl.h>
 #include <asm/spinlock.h>
-
 #include "usb.h"
 
-#define USB_ACM_MINOR 32
+#define NR_PORTS 3
+#define ACM_MAJOR 166
+
+#define info(message); printk(message);
+//#define info(message);
+
+#define CTRL_STAT_DTR	1
+#define CTRL_STAT_RTS	2
+
+static int acm_refcount;
+
+static struct tty_driver acm_tty_driver;
+static struct tty_struct *acm_tty[NR_PORTS];
+static struct termios *acm_termios[NR_PORTS];
+static struct termios *acm_termios_locked[NR_PORTS];
+static struct acm_state acm_state_table[NR_PORTS];
 
 struct acm_state {
-	int present; /* this acm is plugged in */
-	int active; /* someone is has this acm's device open */
-	int serstate; /* Status of the serial port (rate, handshakelines,...) */
-	struct usb_device *dev;
-	unsigned ctrlbuffer;	/*buffer for control messages*/
-	unsigned int readendp,writeendp,ctrlendp;
-	unsigned int readpipe,writepipe,ctrlpipe;
-	char buffer;
+	struct usb_device *dev;				//the coresponding usb device
+	struct tty_struct *tty;				//the coresponding tty
+	char present;					//a device for this struct was detected => this tty is used
+	char active;					//someone has this acm's device open 
+	unsigned int ctrlstate;				//Status of the serial control lines  (handshake,...)
+	unsigned int linecoding;			//Status of the line coding (Bits, Stop, Parity)
+	int writesize, readsize;			//size of the usb buffers
+	char *writebuffer, *readbuffer;			//the usb buffers
+	void *readtransfer, *writetransfer;
+	void *ctrltransfer;				//ptr to HC internal transfer struct
+	char writing, reading;				//flag if transfer is running
+	unsigned int readendp,writeendp,ctrlendp;	//endpoints and
+	unsigned int readpipe,writepipe,ctrlpipe;	//pipes (are one of these obsolete?)
+	unsigned ctrlinterval;				//interval to poll from device
 };
 
-static struct acm_state static_acm_state;
 
-spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
+//functions for various ACM requests
+
+void Set_Control_Line_Status (unsigned int status,struct acm_state *acm)
+{
+	devrequest dr;
+
+	info("Set_control_Line_Status\n");
+
+	dr.requesttype = 0x22;
+	dr.request = 0x22;
+	dr.value = status;
+	dr.index = 0;
+	dr.length = 0;
+	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0);
+
+	acm->ctrlstate=status;
+}
+
+void Set_Line_Coding (unsigned int coding,struct acm_state *acm)
+{
+	devrequest dr;
+
+	info("Set_Line_Coding\n");
+
+	dr.requesttype = 0x22;
+	dr.request = 0x30;
+	dr.value = coding;
+	dr.index = 0;
+	dr.length = 0;
+	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0);
+	
+	acm->linecoding=coding;
+}
 
-static int acm_irq(int state, void *__buffer, int len, void *dev_id)
+//Interrupt handler for various usb events
+static int acm_irq(int state, void *__buffer, int count, void *dev_id)
 {
-//	unsigned char *data = __buffer;
-        struct acm_state *acm = &static_acm_state; 
+
+	unsigned char *data;
+	struct acm_state *acm = (struct acm_state *) dev_id; 
         devrequest *dr;
+		
+	info("ACM_USB_IRQ\n");
 
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return 0;
+	}
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return 1;
+	}
+       
         dr=__buffer;
-	printk("ACM_USB_IRQ\n");
+	data=__buffer;
+	data+=sizeof(dr);
+ 
+#if 1
         printk("reqtype: %02X\n",dr->requesttype);
         printk("request: %02X\n",dr->request);
 	printk("wValue: %02X\n",dr->value);
 	printk("wIndex: %02X\n",dr->index);
 	printk("wLength: %02X\n",dr->length);
+#endif
 	
 	switch(dr->request) {
 	  //Network connection 
 	  case 0x00:
 	    printk("Network connection: ");
-	    if (dr->request==0) printk("disconnected\n");
-	    if (dr->request==1) printk("connected\n");
+	    if (dr->request==0) info("disconnected\n");
+	    if (dr->request==1) info("connected\n");
 	    break;
-
+	    
     	  //Response available
 	  case 0x01:
 	    printk("Response available\n");
-	    acm->buffer=1;
 	    break;
 	
 	  //Set serial line state
 	  case 0x20:
+	    printk("Set serial control line state\n");
 	    if ((dr->index==1)&&(dr->length==2)) {
-	      acm->serstate=acm->ctrlbuffer;
-	      printk("Serstate: %02X\n",acm->ctrlbuffer);
+	      acm->ctrlstate=* ((unsigned short int *)data);
+	      printk("Serstate: %02X\n",acm->ctrlstate);
 	    }
 	    break;
 	}
-/*
-	if(!acm->active)
-		return 1;
-*/
+
+	//info("Done\n");
+	//Continue transfer
+	return 1;
+}
+
+static int acm_read_irq(int state, void *__buffer, int count, void *dev_id)
+{
+	struct acm_state *acm = (struct acm_state *) dev_id; 
+       	struct tty_struct *tty = acm->tty; 
+       	unsigned char* data=__buffer;
+	int i;
+
+	info("ACM_READ_IRQ\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		//Stop transfer
+		return 0;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		//Stop transfer
+		return 0;
+	}
+
+//	printk("%d %s\n",count,data);
+	for (i=0;i<count;i++) {
+		 tty_insert_flip_char(tty,data[i],0);
+  	}
+  	tty_flip_buffer_push(tty);
+  	
+	//info("Done\n");
+  	//Continue transfer
 	return 1;
 }
 
-static int release_acm(struct inode * inode, struct file * file)
+static int acm_write_irq(int state, void *__buffer, int count, void *dev_id)
 {
-	struct acm_state *acm = &static_acm_state;
-	printk("ACM_FILE_RELEASE\n");
+	struct acm_state *acm = (struct acm_state *) dev_id; 
+       	struct tty_struct *tty = acm->tty; 
+
+	info("ACM_WRITE_IRQ\n");
 
-//	fasync_acm(-1, file, 0);
-	if (--acm->active)
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		//Stop transfer
 		return 0;
+	}
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		//Stop transfer
+		return 0;
+	}
+
+	usb_terminate_bulk(acm->dev, acm->writetransfer);
+	acm->writing=0;
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+	wake_up_interruptible(&tty->write_wait);
+	
+	//info("Done\n");
+	//Stop transfer
 	return 0;
 }
 
-static int open_acm(struct inode * inode, struct file * file)
+/*TTY STUFF*/
+static int rs_open(struct tty_struct *tty, struct file * filp) 
 {
-	struct acm_state *acm = &static_acm_state;
-	printk("USB_FILE_OPEN\n");
+	struct acm_state *acm;
+
+	
+	info("USB_FILE_OPEN\n");
 
-	if (!acm->present)
+	tty->driver_data=acm=&acm_state_table[MINOR(tty->device)-tty->driver.minor_start];
+	acm->tty=tty;
+	 
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
 		return -EINVAL;
-	if (acm->active++)
-		return 0;
+	}
+
+	if (acm->active) {
+		info ("ACM DEVICE ALREADY OPEN\n");
+		return -EINVAL;
+	}
+	acm->active=1;
+ 
+	/*Start reading from the device*/
+	acm->ctrltransfer=usb_request_irq(acm->dev,acm->ctrlpipe, acm_irq, acm->ctrlinterval, acm);
+	
+	acm->reading=1;
+	acm->readtransfer=usb_request_bulk(acm->dev,acm->readpipe, acm_read_irq, acm->readbuffer, acm->readsize, acm );
+	
+	Set_Control_Line_Status (CTRL_STAT_DTR | CTRL_STAT_RTS, acm);
+				                  
 	return 0;
 }
 
-static ssize_t write_acm(struct file * file,
-       const char * buffer, size_t count, loff_t *ppos)
+static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-        devrequest dr;
-	struct acm_state *acm = &static_acm_state;
-	unsigned long retval;	        
-
-	printk("USB_FILE_WRITE\n");
-//Huh, i seem to got that wrong, we don't need this ?!?
-/*
-	dr.requesttype = USB_TYPE_CLASS | USB_RT_ENDPOINT;
-	dr.request = 0;
-	dr.value = 0;
-	dr.index = acm->writeendp;
-	dr.length = count;
-	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), &dr, NULL, 0);
-*/	
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
+	info("rs_close\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return;
+	}
 
-	acm->dev->bus->op->bulk_msg(acm->dev,&acm->writepipe,buffer, count, &retval);
-	return -EINVAL;
+	Set_Control_Line_Status (0, acm);
+	
+	if (acm->writing){
+		usb_terminate_bulk(acm->dev, acm->writetransfer);
+		acm->writing=0;
+	}
+	if (acm->reading){
+		usb_terminate_bulk(acm->dev, acm->readtransfer);
+		acm->reading=0;
+	}
+//  usb_release_irq(acm->dev,acm->ctrltransfer);
+	
+	acm->active=0;
 }
 
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
+	int written;
+	
+	info("rs_write\n");
+
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return -EINVAL;
+	}
 
-static ssize_t read_acm(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return -EINVAL;
+	}
+	
+	if (acm->writing) {
+		info ("already writing\n");
+		return 0;
+	}
+
+	written=(count>acm->writesize) ? acm->writesize : count;
+	  
+	if (from_user) {
+		//info("fromuser\n");
+		copy_from_user(acm->writebuffer,buf,written);
+	}
+	else {
+		//info("notfromuser\n");
+		memcpy(acm->writebuffer,buf,written);
+	}  
+
+	//start the transfer
+	acm->writing=1;
+	acm->writetransfer=usb_request_bulk(acm->dev,acm->writepipe, acm_write_irq, acm->writebuffer, written, acm);
+
+	return written;
+} 
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	devrequest dr;
-        struct acm_state *acm = &static_acm_state;
-	unsigned long retval;
-	printk("USB_FILE_READ\n");
-//        if (!acm->buffer) return -1;
-     	acm->buffer=0;
-//We don't need this
-/*
-	printk("writing control msg\n");
-	dr.requesttype = USB_TYPE_CLASS | USB_RT_ENDPOINT | 0x80;
-	dr.request = 1;
-	dr.value = 0;
-	dr.index = acm->readendp;
-	dr.length = 0;
-	acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), &dr, NULL, 0);
-*/
-	printk("reading:>%s<\n",buffer);
-	acm->dev->bus->op->bulk_msg(acm->dev,&acm->readpipe,buffer, 1,&retval);
-	printk("done:>%s<\n",buffer);
-	return 1;
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
+	
+	info("rs_put_char\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return;
+	}
+//  printk("%c\n",ch);
+}                   
+
+static int rs_write_room(struct tty_struct *tty) 
+{
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
+
+	info("rs_write_room\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return -EINVAL;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return -EINVAL;
+	}
+	
+	if (acm->writing) {
+		return 0;
+	}
+	return acm->writesize;
 }
 
-struct file_operations usb_acm_fops = {
-	NULL,		/* acm_seek */
-	read_acm,
-	write_acm,
-	NULL, 		/* acm_readdir */
-	NULL,	 	/* acm_poll */
-	NULL, 		/* acm_ioctl */
-	NULL,		/* acm_mmap */
-	open_acm,
-	NULL,		/* flush */
-	release_acm,
-	NULL,
-	NULL,		/*fasync*/
-};
+static int rs_chars_in_buffer(struct tty_struct *tty) 
+{
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
 
-static struct miscdevice usb_acm = {
-	USB_ACM_MINOR, "USB ACM", &usb_acm_fops
-};
+	info("rs_chars_in_buffer\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return -EINVAL;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return -EINVAL;
+	}
+	
+	if (acm->writing) {
+		return acm->writesize;
+	}
+	return 0;
+}
+
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
+	
+	info("rs_throttle\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return;
+	}
+
+/*	
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+*/    
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		Set_Control_Line_Status (acm->ctrlstate & ~CTRL_STAT_RTS, acm);
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct acm_state *acm = (struct acm_state *) tty->driver_data; 
+	
+	info("rs_unthrottle\n");
+	
+	if (!acm->present) {
+		info("NO ACM DEVICE REGISTERED\n");
+		return;
+	}
+
+	if (!acm->active) {
+		info ("ACM DEVICE NOT OPEN\n");
+		return;
+	}
+
+/*	
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+*/    
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		Set_Control_Line_Status (acm->ctrlstate | CTRL_STAT_RTS, acm);
+}
+
+static int get_free_acm()
+{
+ int i;
+ 
+ for (i=0;i<NR_PORTS;i++) {
+	 if (!acm_state_table[i].present)
+		 return i;
+ }
+ return -1;
+}
 
 static int acm_probe(struct usb_device *dev)
 {
+	struct acm_state *acm;
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
-	struct acm_state *acm = &static_acm_state;
-	int cfgnum;
+	int cfgnum,acmno;
+	
+	info("acm_probe\n");
+	
+	if (0>(acmno=get_free_acm())) {
+		info("Too many acm devices connected\n");
+		return -1;
+	}
+	acm = &acm_state_table[acmno];
 
 	/* Only use CDC */
 	if (dev->descriptor.bDeviceClass != 2 ||
@@ -230,34 +536,74 @@
 		    (endpoint->bmAttributes & 3) != 2)
 			continue;
 
-		printk("USB ACM found\n");
-		if (usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue)) {
-			printk (KERN_INFO " Failed usb_set_configuration: ACM\n");
-			continue;
-		}
+		printk("USB ACM %d found\n",acmno);
+		usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
+
 		acm->dev=dev;
+		dev->private=acm;
+
 		acm->readendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].bEndpointAddress;
-		acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress;
-		acm->ctrlendp=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bEndpointAddress;
 		acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp);
+		acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].wMaxPacketSize,GFP_KERNEL);
+		acm->reading=0;
+		if (!acm->readbuffer) {
+			printk("ACM: Couldn't allocate readbuffer\n");
+			return -1;
+		}
+		
+		acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress;
 		acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp);
-		usb_request_irq(dev,acm->ctrlpipe=usb_rcvctrlpipe(dev,acm->ctrlendp), acm_irq, dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bInterval, &acm->ctrlbuffer);
-		acm->present = 1;
-		acm->buffer=0;
+		acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].wMaxPacketSize, GFP_KERNEL);
+		acm->writing=0;
+		if (!acm->writebuffer) {
+			printk("ACM: Couldn't allocate writebuffer\n");
+			kfree(acm->readbuffer);
+			return -1;
+		}
+		
+		acm->ctrlendp=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bEndpointAddress;
+		acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp);
+		acm->ctrlinterval=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bInterval;
+
+		acm->present=1;				
+		MOD_INC_USE_COUNT;
 		return 0;
 	}
-
 	return -1;
 }
 
 static void acm_disconnect(struct usb_device *dev)
 {
-	struct acm_state *acm = &static_acm_state;
+	struct acm_state *acm = (struct acm_state *) dev->private;
 
-	/* this might need work */
-	acm->present = 0;
+	info("acm_disconnect\n");
+	
+	if (!acm->present) {
+		printk("device not present\n");
+		return;
+	}
+
+	printk("disconnecting\n");
+	
+	if (acm->writing){
+		usb_terminate_bulk(acm->dev, acm->writetransfer);
+		acm->writing=0;
+	}
+	if (acm->reading){
+		usb_terminate_bulk(acm->dev, acm->readtransfer);
+		acm->reading=0;
+	}
+//  usb_release_irq(acm->dev,acm->ctrltransfer);
+	//BUG: What to do if a device is open?? Notify process or not allow cleanup?
+	acm->active=0;
+	acm->present=0;
+	kfree(acm->writebuffer);
+	kfree(acm->readbuffer);
+
+	MOD_DEC_USE_COUNT;
 }
 
+/*USB DRIVER STUFF*/
 static struct usb_driver acm_driver = {
 	"acm",
 	acm_probe,
@@ -267,19 +613,83 @@
 
 int usb_acm_init(void)
 {
-	struct acm_state *acm = &static_acm_state;
-
-	misc_register(&usb_acm);
-
-	acm->present = acm->active = 0;
+	int cnt;
+	
+	info("usb_acm_init\n");
+		
+	//INITIALIZE GLOBAL DATA STRUCTURES
+	for (cnt=0;cnt<NR_PORTS;cnt++) {
+		memset(&acm_state_table[cnt], 0, sizeof(struct acm_state));
+	}
 
+	//REGISTER TTY DRIVER
+	memset(&acm_tty_driver, 0, sizeof(struct tty_driver));
+	acm_tty_driver.magic = TTY_DRIVER_MAGIC;
+	acm_tty_driver.driver_name = "usb";
+	acm_tty_driver.name = "ttyACM";
+	acm_tty_driver.major = ACM_MAJOR;
+	acm_tty_driver.minor_start = 0;
+	acm_tty_driver.num = NR_PORTS;
+	acm_tty_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	acm_tty_driver.subtype = SERIAL_TYPE_NORMAL;
+	acm_tty_driver.init_termios = tty_std_termios;
+	acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	acm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
+	acm_tty_driver.refcount = &acm_refcount;
+	acm_tty_driver.table = acm_tty;
+	acm_tty_driver.termios = acm_termios;
+	acm_tty_driver.termios_locked = acm_termios_locked;
+	
+	acm_tty_driver.open = rs_open;
+	acm_tty_driver.close = rs_close;
+	acm_tty_driver.write = rs_write;
+	acm_tty_driver.put_char = rs_put_char; //FUCKIN BUG IN DOKU!!!
+	acm_tty_driver.flush_chars = NULL; //rs_flush_chars;
+	acm_tty_driver.write_room = rs_write_room; //ANBOTHER FUCKIN BUG!!
+	acm_tty_driver.ioctl = NULL; //rs_ioctl;
+	acm_tty_driver.set_termios = NULL; //rs_set_termios;
+	acm_tty_driver.set_ldisc = NULL; 
+	acm_tty_driver.throttle = rs_throttle;
+	acm_tty_driver.unthrottle = rs_unthrottle;
+	acm_tty_driver.stop = NULL; //rs_stop;
+	acm_tty_driver.start = NULL; //rs_start;
+	acm_tty_driver.hangup = NULL; //rs_hangup;
+	acm_tty_driver.break_ctl = NULL; //rs_break;
+	acm_tty_driver.wait_until_sent = NULL; //rs_wait_until_sent;
+	acm_tty_driver.send_xchar = NULL; //rs_send_xchar;
+	acm_tty_driver.read_proc = NULL; //rs_read_proc;
+	acm_tty_driver.chars_in_buffer = rs_chars_in_buffer;
+	acm_tty_driver.flush_buffer = NULL; //rs_flush_buffer;
+	tty_register_driver(&acm_tty_driver);
+	
+	//REGISTER USB DRIVER
 	usb_register(&acm_driver);
+
 	printk(KERN_INFO "USB ACM registered.\n");
 	return 0;
 }
 
-#ifdef MODULE
+void usb_acm_cleanup(void)
+{
+	int i;
+	struct acm_state *acm;
 
+	info("usb_acm_cleanup\n");
+		
+	for (i=0;i<NR_PORTS;i++) {
+		acm=&acm_state_table[i];
+		if (acm->present) {
+			printk("disconnecting %d\n",i);
+			acm_disconnect(acm->dev);
+		}  
+	}
+	tty_unregister_driver(&acm_tty_driver);
+	
+	usb_deregister(&acm_driver);
+	
+}
+
+#ifdef MODULE
 int init_module(void)
 {
 	return usb_acm_init();
@@ -287,9 +697,6 @@
 
 void cleanup_module(void)
 {
-	/* this, too, probably needs work */
-	usb_deregister(&acm_driver);
-	misc_deregister(&usb_acm);
+	usb_acm_cleanup();
 }
-
-#endif
+#endif
\ No newline at end of file
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.12/linux/drivers/usb/audio.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/audio.c	Sat Aug  7 13:01:44 1999
@@ -11,24 +11,25 @@
 static void usb_audio_disconnect(struct usb_device *dev);
 static LIST_HEAD(usb_audio_list);
 
-struct usb_audio
-{
+struct usb_audio {
 	struct usb_device *dev;
 	struct list_head list;
 };
 
-static struct usb_driver usb_audio_driver =
-{
+static struct usb_driver usb_audio_driver = {
 	"audio",
 	usb_audio_probe,
 	usb_audio_disconnect,
-	{NULL, NULL}
+	{ NULL, NULL }
 };
 
 
 static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
 {
-	struct usb_audio *aud = (struct usb_audio*) dev_id;
+	struct usb_audio *aud = (struct usb_audio *)dev_id;
+
+	printk("irq on %p\n", aud);
+
 	return 1;
 }
 
@@ -37,16 +38,12 @@
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_audio *aud;
-
 	int i;
 	int na=0;
 	
 	interface = &dev->config[0].altsetting[0].interface[0];
 
-	for(i=0;i<dev->config[0].bNumInterfaces;i++)
-	{
-		int x;
-		
+	for (i=0; i<dev->config[0].bNumInterfaces; i++) {
 		endpoint = &interface->endpoint[i];
 
 		if(interface->bInterfaceClass != 1) 
@@ -54,8 +51,7 @@
 
 		printk(KERN_INFO "USB audio device detected.\n");
 	
-		switch(interface->bInterfaceSubClass)
-		{
+		switch(interface->bInterfaceSubClass) {
 			case 0x01:
 				printk(KERN_INFO "audio: Control device.\n");
 				break;
@@ -69,12 +65,11 @@
 		na++;
 	}
 	
-	if(na==0)
+	if (!na)
 		return -1;
 
 	aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL);
-	if(aud)
-	{
+	if (aud) {
         	memset(aud, 0, sizeof(*aud));
         	aud->dev = dev;
         	dev->private = aud;
@@ -107,8 +102,8 @@
 static void usb_audio_disconnect(struct usb_device *dev)
 {
 	struct usb_audio *aud = (struct usb_audio*) dev->private;
-	if(aud)
-	{
+
+	if (aud) {
         	dev->private = NULL;
         	list_del(&aud->list);
         	kfree(aud);
@@ -146,3 +141,4 @@
 }
 
 #endif
+
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.12/linux/drivers/usb/cpia.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/cpia.c	Fri Jul 30 12:31:45 1999
@@ -25,6 +25,8 @@
 #include "usb.h"
 #include "cpia.h"
 
+#define CPIA_DEBUG	/* Gobs of debugging info */
+
 #define MAX_FRAME_SIZE (384 * 288 * 3)
 
 /*******************************/
@@ -319,11 +321,13 @@
 	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
 }
 
+/* How much data is left in the scratch buf? */
 #define scratch_left(x)	(cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
 
 static void cpia_parse_data(struct usb_cpia *cpia)
 {
 	unsigned char *data = cpia->scratch;
+	unsigned long l;
 	int done;
 
 	done = 0;
@@ -339,6 +343,7 @@
 				break;
 			}
 
+			/* 0x1968 is magic */
 			printk("header: %X\n", (*data << 8) + *(data + 1));
 			if ((*data == 0x19) && (*(data + 1) == 0x68)) {
 				cpia->state = STATE_HEADER;
@@ -346,6 +351,7 @@
 				break;
 			}
 
+			/* Woops, lost the header, find the end of the frame */
 			if (scratch_left(data) < 4) {
 				done = 1;
 				break;
@@ -362,7 +368,9 @@
 				}
 				data++;
 			}
-printk("scan: scanned %d bytes\n", data-begin);
+#ifdef CPIA_DEBUG
+			printk("scan: scanned %d bytes\n", data-begin);
+#endif
 			break;
 		}
 		case STATE_HEADER:
@@ -372,7 +380,9 @@
 				break;
 			}
 
-printk("header: framerate %d\n", data[41]);
+#ifdef CPIA_DEBUG
+			printk("header: framerate %d\n", data[41]);
+#endif
 
 			data += 64;
 
@@ -390,11 +400,11 @@
 					found = 1;
 					break;
 				} else if ((*data == 0xFF) &&
-					(scratch_left(data) >= 3) &&
-					(*(data + 1) == 0xFF) &&
-					(*(data + 2) == 0xFF) &&
-					(*(data + 3) == 0xFF)) {
-					data+=4;
+						(scratch_left(data) >= 3) &&
+						(*(data + 1) == 0xFF) &&
+						(*(data + 2) == 0xFF) &&
+						(*(data + 3) == 0xFF)) {
+					data += 4;
 					cpia->curline = 144;
 					found = 1;
 					break;
@@ -402,25 +412,21 @@
 
 				data++;
 			}
-#if 0
-printk("line %d: scanned %d bytes\n", cpia->curline, data-begin);
-#endif
-if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) {
-	int i;
-	char *f = cpia->frame[cpia->curframe].data, *b = begin;
 
-#if 0
-printk("copying\n");
-#endif
+			if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) {
+				int i;
+				char *f = cpia->frame[cpia->curframe].data, *b = begin;
+
+				b += 2;
+				f += (cpia->frame[cpia->curframe].width * 3) * cpia->curline;
+
+				for (i = 0; i < 176; i++)
+					f[(i * 3) + 0] =
+					f[(i * 3) + 1] =
+					f[(i * 3) + 2] =
+						b[(i * 2)];
+			}
 
-	b+=2;
-	f+=(cpia->frame[cpia->curframe].width*3)*cpia->curline;
-	for (i = 0; i < 176; i++)
-		f[(i * 3) + 0] =
-		f[(i * 3) + 1] =
-		f[(i * 3) + 2] =
-			b[(i * 2)];
-}
 			if (found) {
 				cpia->curline++;
 				if (cpia->curline >= 144) {
@@ -440,13 +446,11 @@
 		}
 	}
 
-	{
-	int l;
-
+	/* Grab the remaining */
 	l = scratch_left(data);
 	memmove(cpia->scratch, data, l);
+
 	cpia->scratchlen = l;
-	}
 }
 
 static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
@@ -466,13 +470,21 @@
 		if (cpia->frame[0].state == FRAME_READY) {
 			cpia->curframe = 0;
 			cpia->frame[0].state = FRAME_GRABBING;
-printk("capturing to frame 0\n");
+#ifdef CPIA_DEBUG
+			printk("capturing to frame 0\n");
+#endif
 		} else if (cpia->frame[1].state == FRAME_READY) {
 			cpia->curframe = 1;
 			cpia->frame[1].state = FRAME_GRABBING;
-printk("capturing to frame 1\n");
+#ifdef CPIA_DEBUG
+			printk("capturing to frame 1\n");
+#endif
+#ifdef CPIA_DEBUG
 		} else
-printk("no frame available\n");
+			printk("no frame available\n");
+#else
+		}
+#endif
 	}
 
 	sbuf = &cpia->sbuf[cpia->receivesbuf];
@@ -482,8 +494,10 @@
 	/* Do something to it now */
 	sbuf->len = usb_compress_isochronous(dev, sbuf->isodesc);
 
+#ifdef CPIA_DEBUG
 	if (sbuf->len)
-	printk("%d bytes received\n", sbuf->len);
+		printk("%d bytes received\n", sbuf->len);
+#endif
 
 	if (sbuf->len && cpia->curframe >= 0) {
 		if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) {
@@ -511,10 +525,6 @@
 
 	cpia->receivesbuf = 0;
 
-#if 0
-	cpia->parsesbuf = 0;
-	cpia->parsepos = 0;
-#endif
 	cpia->scratchlen = 0;
 	cpia->curline = 0;
 	cpia->state = STATE_SCANNING;
@@ -524,15 +534,20 @@
 	cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
 	cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
 
+#ifdef CPIA_DEBUG
 	printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc);
 	printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc);
 	printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc);
+#endif
 
 	/* Schedule the queues */
 	usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
 	usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
 	usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
 
+#ifdef CPIA_DEBUG
+	printk("done scheduling\n");
+#endif
 	if (usb_set_interface(cpia->dev, 1, 3)) {
 		printk("cpia_set_interface error\n");
 		return -EINVAL;
@@ -541,6 +556,9 @@
 	usb_cpia_startstreamcap(cpia->dev);
 
 	cpia->streaming = 1;
+#ifdef CPIA_DEBUG
+	printk("now streaming\n");
+#endif
 
 	return 0;
 }
@@ -579,7 +597,9 @@
 {
 	struct usb_cpia *cpia = (struct usb_cpia *)dev;
 
-printk("cpia_open\n");
+#ifdef CPIA_DEBUG
+	printk("cpia_open\n");
+#endif
 
 	cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
 	if (!cpia->fbuf)
@@ -590,8 +610,10 @@
 
 	cpia->frame[0].data = cpia->fbuf;
 	cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
+#ifdef CPIA_DEBUG
 	printk("frame [0] @ %p\n", cpia->frame[0].data);
 	printk("frame [1] @ %p\n", cpia->frame[1].data);
+#endif
 
 	cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
 	if (!cpia->sbuf[0].data)
@@ -605,9 +627,11 @@
 	if (!cpia->sbuf[2].data)
 		goto open_err_on2;
 
+#ifdef CPIA_DEBUG
 	printk("sbuf[0] @ %p\n", cpia->sbuf[0].data);
 	printk("sbuf[1] @ %p\n", cpia->sbuf[1].data);
 	printk("sbuf[2] @ %p\n", cpia->sbuf[2].data);
+#endif
 
 	cpia->curframe = -1;
 	cpia->receivesbuf = 0;
@@ -632,7 +656,9 @@
 {
 	struct usb_cpia *cpia = (struct usb_cpia *)dev;
 
-printk("cpia_close\n");
+#ifdef CPIA_DEBUG
+	printk("cpia_close\n");
+#endif
 
 	cpia_stop_isoc(cpia);
 
@@ -655,90 +681,6 @@
 	return -EINVAL;
 }
 
-#if 0
-	if (usb_set_interface(dev, 1, 3)) {
-		printk("cpia_set_interface error\n");
-		return -EINVAL;
-	}
-
-	if (usb_cpia_grab_frame(dev, 0)) {
-		printk("cpia_grab_frame error\n");
-		return -EINVAL;
-	}
-
-	if (usb_cpia_upload_frame(dev, 0)) {
-		printk("cpia_upload_frame error\n");
-		return -EINVAL;
-	}
-
-	buf = cpia->ibuf;
-	uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 176*144*4);
-
-	{
-	printk("header magic: %X\n", (buf[0] << 8) + buf[1]);
-
-	while ((buf[0] != 0x19) || (buf[1] != 0x68)) {
-		int i;
-
-		printk("resync'ing\n");
-		for (i=0;i<(176*144*4)-4;i++, buf++)
-			if (
-				(buf[0] == 0xFF) &&
-				(buf[1] == 0xFF) &&
-				(buf[2] == 0xFF) &&
-				(buf[3] == 0xFF)) {
-				buf+=4;
-				i+=4;
-				break;
-			}
-
-		memmove(cpia->ibuf, buf, (176*144*4) - i);
-		uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->ibuf + (176*144*4) - i, i);
-		buf = cpia->ibuf;
-
-#if 0
-		printk("header magic: %X\n", (buf[0] << 8) + buf[1]);
-#endif
-	}
-
-	printk("size: %d, sample: %d, order: %d\n", buf[16], buf[17], buf[18]);
-	printk("comp: %d, decimation: %d\n", buf[28], buf[29]);
-	printk("roi: top left: %d, %d bottom right: %d, %d\n",
-		buf[26] * 4, buf[24] * 8,
-		buf[27] * 4, buf[25] * 8);
-
-	printk("vm->frame: %d\n", vm->frame);
-
-	{
-	int i, i1;
-	char *b = buf + 64, *fbuf = &cpia->fbuffer[MAX_FRAME_SIZE * (vm->frame & 1)];
-	for (i=0;i<144;i++) {
-#if 0
-		printk("line len: %d\n", (b[1] << 8) + b[0]);
-#endif
-		b += 2;
-		for (i1=0;i1<176;i1++) {
-			fbuf[(i * vm->width * 3) + (i1 * 3)] = 
-			fbuf[(i * vm->width * 3) + (i1 * 3) + 1] = 
-			fbuf[(i * vm->width * 3) + (i1 * 3) + 2] = 
-				b[i1 * 2];
-#if 0
-			*((short *)&fbuf[(i * vm->width * 2) + (i1 * 2)]) =
-				((b[i1 * 2] >> 3) << 11) + ((b[i1 * 2] >> 2) << 6) + (b[i1 * 2] >> 3);
-#endif
-		}
-		b += (176 * 2) + 1;
-	}
-	}
-
-	}
-
-	if (usb_set_interface(dev, 1, 0)) {
-		printk("cpia_set_interface error\n");
-		return -EINVAL;
-	}
-#endif
-
 static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
 	struct usb_cpia *cpia = (struct usb_cpia *)dev;
@@ -752,10 +694,10 @@
 			b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */;
 			b.channels = 1;
 			b.audios = 0;
-			b.maxwidth = 176 /* 352 */;
-			b.maxheight = 144 /* 240 */;
-			b.minwidth = 176 /* (Something small?) */;
-			b.minheight = 144 /* "         " */;
+			b.maxwidth = 176	/* 352 */;
+			b.maxheight = 144	/* 240 */;
+			b.minwidth = 176	/* (Something small?) */;
+			b.minheight = 144	/* "         " */;
 
 			if (copy_to_user(arg, &b, sizeof(b)))
 				return -EFAULT;
@@ -855,13 +797,9 @@
 			if (copy_from_user(&p, arg, sizeof(p)))
 				return -EFAULT;
 
-printk("Attempting to set palette %d, depth %d\n", p.palette, p.depth);
-
-#if 0
-			if (p.palette != VIDEO_PALETTE_YUYV)
-				return -EINVAL;
-			if (p.depth != 16)
-				return -EINVAL;
+#ifdef CPIA_DEBUG
+			printk("Attempting to set palette %d, depth %d\n",
+				p.palette, p.depth);
 #endif
 
 			return 0;
@@ -870,7 +808,10 @@
 		{
 			struct video_window vw;
 
-printk("VIDIOCSWIN\n");
+#ifdef CPIA_DEBUG
+			printk("VIDIOCSWIN\n");
+#endif
+
 			if (copy_from_user(&vw, arg, sizeof(vw)))
 				return -EFAULT;
 			if (vw.flags)
@@ -888,7 +829,10 @@
 		{
 			struct video_window vw;
 
-printk("VIDIOCGWIN\n");
+#ifdef CPIA_DEBUG
+			printk("VIDIOCGWIN\n");
+#endif
+
 			vw.x = 0;
 			vw.y = 0;
 			vw.width = 176;
@@ -923,8 +867,11 @@
 			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
 				return -EFAULT;
 
-printk("MCAPTURE\n");
-printk("frame: %d, size: %dx%d, format: %d\n", vm.frame, vm.width, vm.height, vm.format);
+#ifdef CPIA_DEBUG
+			printk("MCAPTURE\n");
+			printk("frame: %d, size: %dx%d, format: %d\n",
+				vm.frame, vm.width, vm.height, vm.format);
+#endif
 
 			if (vm.format != VIDEO_PALETTE_RGB24)
 				return -EINVAL;
@@ -947,7 +894,9 @@
 			if (copy_from_user((void *)&frame, arg, sizeof(int)))
 				return -EFAULT;
 
+#ifdef CPIA_DEBUG
 			printk("syncing to frame %d\n", frame);
+#endif
 			switch (cpia->frame[frame].state) {
 				case FRAME_UNUSED:
 					return -EINVAL;
@@ -958,7 +907,9 @@
 					cpia->frame[frame].state = FRAME_UNUSED;
 					break;
 			}
+#ifdef CPIA_DEBUG
 			printk("synced to frame %d\n", frame);
+#endif
 			return 0;
 		}
 		case VIDIOCCAPTURE:
@@ -988,7 +939,9 @@
 	struct usb_cpia *cpia = (struct usb_cpia *)dev;
 	int len;
 
+#ifdef CPIA_DEBUG
 	printk("cpia_read: %ld bytes\n", count);
+#endif
 #if 0
 	len = cpia_capture(cpia, buf, count);
 
@@ -1003,17 +956,12 @@
 	unsigned long start = (unsigned long)adr;
 	unsigned long page, pos;
 
+#ifdef CPIA_DEBUG
 	printk("mmap: %ld (%lX) bytes\n", size, size);
+#endif
 	if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
 		return -EINVAL;
 
-#if 0
-	if (!cpia->fbuffer) {
-		if ((cpia->fbuffer = rvmalloc(2 * MAX_FRAME_SIZE)) == NULL)
-			return -EINVAL;
-	}
-#endif
-
 	pos = (unsigned long)cpia->fbuf;
 	while (size > 0)
 	{
@@ -1123,39 +1071,6 @@
 		printk("cpia_set_compression error\n");
 		return;
 	}
-
-#if 0
-	if (usb_cpia_grab_frame(dev, 0)) {
-		printk("cpia_grab_frame error\n");
-		return;
-	}
-
-	if (usb_cpia_upload_frame(dev, 1)) {
-		printk("cpia_upload_frame error\n");
-		return;
-	}
-
-	buf = (void *)__get_free_page(GFP_KERNEL);
-
-	{
-	int i;
-	for (i=0;i<448;i++)
-		buf[i]=0;
-	}
-	uhci_receive_isochronous(dev, usb_rcvisocpipe(dev,1), buf, 448);
-
-	{
-	int i;
-	for (i=0;i<448;i++) {
-		printk("%02X ", buf[i]);
-		if ((i % 16) == 15)
-			printk("\n");
-	}
-	printk("\n");
-	}
-
-	free_page((unsigned long)buf);
-#endif
 }
 
 static int cpia_probe(struct usb_device *dev)
@@ -1168,29 +1083,9 @@
 	if (dev->descriptor.bNumConfigurations != 1)
 		return -1;
 
-#if 0
-	/* We don't handle multi-interface hubs */
-	if (dev->config[0].bNumInterfaces != 1)
-		return -1;
-#endif
-
 	interface = &dev->config[0].altsetting[0].interface[0];
 
 	/* Is it a CPiA? */
-/*
-Apr 24 17:49:04 bjorn kernel:   Vendor:  0545 
-Apr 24 17:49:04 bjorn kernel:   Product: 8080 
-*/
-/*
-	if (dev->descriptor.idVendor != 0x0545)
-		return -1;
-	if (dev->descriptor.idProduct != 0x8080)
-		return -1;
-	if (interface->bInterfaceClass != 0xFF)
-		return -1;
-	if (interface->bInterfaceSubClass != 0xFF)
-		return -1;
-*/
 	if (dev->descriptor.idVendor != 0x0553)
 		return -1;
 	if (dev->descriptor.idProduct != 0x0002)
@@ -1200,22 +1095,6 @@
 	if (interface->bInterfaceSubClass != 0x00)
 		return -1;
 
-#if 0
-	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
-	if (interface->bNumEndpoints != 1)
-		return -1;
-
-	endpoint = &interface->endpoint[0];
-
-	/* Output endpoint? Curiousier and curiousier.. */
-	if (!(endpoint->bEndpointAddress & 0x80))
-		return -1;
-
-	/* If it's not an interrupt endpoint, we'd better punt! */
-	if ((endpoint->bmAttributes & 3) != 3)
-		return -1;
-#endif
-
 	/* We found a CPiA */
 	printk("USB CPiA camera found\n");
 
@@ -1231,10 +1110,6 @@
 
 	usb_cpia_configure(cpia);
 
-#if 0
-	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), pport_irq, endpoint->bInterval, pport);
-#endif
-
 	return 0;
 }
 
@@ -1270,6 +1145,7 @@
 {
 	return usb_cpia_init();
 }
+
 void cleanup_module(void)
 {
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.12/linux/drivers/usb/hub.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/hub.c	Sat Aug  7 13:01:44 1999
@@ -14,23 +14,91 @@
 #include <linux/module.h>
 
 #include <asm/spinlock.h>
+#include <asm/uaccess.h>
 
 #include "usb.h"
 #include "hub.h"
 
 /* Wakes up khubd */
-static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait);
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED;
 
-/* List of hubs needing servicing */
-static struct list_head hub_event_list;
+static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
+static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */
 
-/* List containing all of the hubs (for cleanup) */
-static struct list_head all_hubs_list;
+static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+static int khubd_pid = 0;			/* PID of khubd */
+static int khubd_running = 0;
 
-/* PID of khubd */
-static int khubd_pid = 0;
+static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_DIR_IN | USB_RT_HUB;
+	dr.request = USB_REQ_GET_DESCRIPTOR;
+	dr.value = (USB_DT_HUB << 8);
+	dr.index = 0;
+	dr.length = size;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr,
+		data, size);
+}
+
+static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_PORT;
+	dr.request = USB_REQ_CLEAR_FEATURE;
+	dr.value = feature;
+	dr.index = port;
+	dr.length = 0;
+
+	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr,
+		NULL, 0);
+}
+
+static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_PORT;
+	dr.request = USB_REQ_SET_FEATURE;
+	dr.value = feature;
+	dr.index = port;
+	dr.length = 0;
+
+	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr,
+		NULL, 0);
+}
+
+static int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_DIR_IN | USB_RT_HUB;
+	dr.request = USB_REQ_GET_STATUS;
+	dr.value = 0;
+	dr.index = 0;
+	dr.length = 4;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr,
+		data, 4);
+}
+
+static int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_DIR_IN | USB_RT_PORT;
+	dr.request = USB_REQ_GET_STATUS;
+	dr.value = 0;
+	dr.index = port;
+	dr.length = 4;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr,
+		data, 4);
+}
 
 /*
  * A irq handler returns non-zero to indicate to
@@ -42,13 +110,13 @@
 	struct usb_hub *hub = dev_id;
 	unsigned long flags;
 
-	if (waitqueue_active(&usb_hub_wait)) {
+	if (waitqueue_active(&khubd_wait)) {
 		/* Add the hub to the event queue */
 		spin_lock_irqsave(&hub_event_lock, flags);
 		if (hub->event_list.next == &hub->event_list) {
 			list_add(&hub->event_list, &hub_event_list);
 			/* Wake up khubd */
-			wake_up(&usb_hub_wait);
+			wake_up(&khubd_wait);
 		}
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 	}
@@ -68,83 +136,63 @@
 		return;
 
 	hub->nports = dev->maxchild = hubdescriptor[2];
-	printk("hub: %d-port%s detected\n", hub->nports,
+	printk(KERN_INFO "hub: %d-port%s detected\n", hub->nports,
 		(hub->nports == 1) ? "" : "s");
 
 	charac = (hubdescriptor[4] << 8) + hubdescriptor[3];
 	switch (charac & HUB_CHAR_LPSM) {
 		case 0x00:
-			printk("hub: ganged power switching\n");
+			printk(KERN_INFO "hub: ganged power switching\n");
 			break;
 		case 0x01:
-			printk("hub: individual port power switching\n");
+			printk(KERN_INFO "hub: individual port power switching\n");
 			break;
 		case 0x02:
 		case 0x03:
-			printk("hub: unknown reserved power switching mode\n");
+			printk(KERN_INFO "hub: unknown reserved power switching mode\n");
 			break;
 	}
 
 	if (charac & HUB_CHAR_COMPOUND)
-		printk("hub: part of a compound device\n");
+		printk(KERN_INFO "hub: part of a compound device\n");
 	else
-		printk("hub: standalone hub\n");
+		printk(KERN_INFO "hub: standalone hub\n");
 
 	switch (charac & HUB_CHAR_OCPM) {
 		case 0x00:
-			printk("hub: global over current protection\n");
+			printk(KERN_INFO "hub: global over current protection\n");
 			break;
 		case 0x08:
-			printk("hub: individual port over current protection\n");
+			printk(KERN_INFO "hub: individual port over current protection\n");
 			break;
 		case 0x10:
 		case 0x18:
-			printk("hub: no over current protection\n");
+			printk(KERN_INFO "hub: no over current protection\n");
                         break;
 	}
 
-	printk("hub: power on to power good time: %dms\n",
+	printk(KERN_INFO "hub: power on to power good time: %dms\n",
 		hubdescriptor[5] * 2);
 
-	printk("hub: hub controller current requirement: %dmA\n",
+	printk(KERN_INFO "hub: hub controller current requirement: %dmA\n",
 		hubdescriptor[6]);
 
 	for (i = 0; i < dev->maxchild; i++)
-		printk("hub:  port %d is%s removable\n", i + 1,
+		printk(KERN_INFO "hub:  port %d is%s removable\n", i + 1,
 			hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8))
 			? " not" : "");
 
 	if (usb_get_hub_status(dev, buf))
 		return;
 
-	printk("hub: local power source is %s\n",
+	printk(KERN_INFO "hub: local power source is %s\n",
 		(buf[0] & 1) ? "lost (inactive)" : "good");
 
-	printk("hub: %sover current condition exists\n",
+	printk(KERN_INFO "hub: %sover current condition exists\n",
 		(buf[0] & 2) ? "" : "no ");
 
-#if 0
-	for (i = 0; i < hub->nports; i++) {
-		int portstat, portchange;
-		unsigned char portstatus[4];
-
-		if (usb_get_port_status(dev, i + 1, portstatus))
-			return;
-		portstat = (portstatus[1] << 8) + portstatus[0];
-		portchange = (portstatus[3] << 8) + portstatus[2];
-
-		printk("hub: port %d status\n", i + 1);
-		printk("hub:  %sdevice present\n", (portstat & 1) ? "" : "no ");
-		printk("hub:  %s\n", (portstat & 2) ? "enabled" : "disabled");
-		printk("hub:  %ssuspended\n", (portstat & 4) ? "" : "not ");
-		printk("hub:  %sover current\n", (portstat & 8) ? "" : "not ");
-		printk("hub:  has %spower\n", (portstat & 0x100) ? "" : "no ");
-		printk("hub:  %s speed\n", (portstat & 0x200) ? "low" : "full");
-	}
-#endif
-
 	/* Enable power to the ports */
-	printk("enabling power on all ports\n");
+	printk(KERN_INFO "hub: enabling power on all ports\n");
 	for (i = 0; i < hub->nports; i++)
 		usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
 }
@@ -180,7 +228,7 @@
 	endpoint = &interface->endpoint[0];
 
 	/* Output endpoint? Curiousier and curiousier.. */
-	if (!(endpoint->bEndpointAddress & 0x80))
+	if (!(endpoint->bEndpointAddress & USB_DIR_IN))
 		return -1;
 
 	/* If it's not an interrupt endpoint, we'd better punt! */
@@ -188,10 +236,10 @@
 		return -1;
 
 	/* We found a hub */
-	printk("USB hub found\n");
+	printk(KERN_INFO "USB hub found\n");
 
 	if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
-		printk("couldn't kmalloc hub struct\n");
+		printk(KERN_ERR "couldn't kmalloc hub struct\n");
 		return -1;
 	}
 
@@ -205,15 +253,16 @@
 	/* Record the new hub's existence */
 	spin_lock_irqsave(&hub_list_lock, flags);
 	INIT_LIST_HEAD(&hub->hub_list);
-	list_add(&hub->hub_list, &all_hubs_list);
+	list_add(&hub->hub_list, &hub_list);
 	spin_unlock_irqrestore(&hub_list_lock, flags);
 
 	usb_hub_configure(hub);
 
-	hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+	hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev,
+		endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
 
 	/* Wake up khubd */
-	wake_up(&usb_hub_wait);
+	wake_up(&khubd_wait);
 
 	return 0;
 }
@@ -246,40 +295,51 @@
 	unsigned char buf[4];
 	unsigned short portstatus, portchange;
 
+	/* Disconnect anything that may have been there */
 	usb_disconnect(&hub->children[port]);
 
+	/* Reset the port */
 	usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
 
 	wait_ms(50);	/* FIXME: This is from the *BSD stack, thanks! :) */
 
+	/* Check status */
 	if (usb_get_port_status(hub, port + 1, buf)) {
-		printk("get_port_status failed\n");
+		printk(KERN_ERR "get_port_status failed\n");
 		return;
 	}
 
 	portstatus = le16_to_cpup((unsigned short *)buf + 0);
 	portchange = le16_to_cpup((unsigned short *)buf + 1);
 
+	/* If it's not in CONNECT and ENABLE state, we're done */
 	if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
-		(!(portstatus & USB_PORT_STAT_ENABLE))) {
+	    (!(portstatus & USB_PORT_STAT_ENABLE)))
 		/* We're done now, we already disconnected the device */
-		/* printk("not connected/enabled\n"); */
 		return;
-	}
 
+	/* Allocate a new device struct for it */
 	usb = hub->bus->op->allocate(hub);
 	if (!usb) {
-		printk("couldn't allocate usb_device\n");
+		printk(KERN_ERR "couldn't allocate usb_device\n");
 		return;
 	}
 
-	usb_connect(usb);
-
 	usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
 
 	hub->children[port] = usb;
 
-	usb_new_device(usb);
+	/* Find a new device ID for it */
+	usb_connect(usb);
+
+	/* Run it through the hoops (find a driver, etc) */
+	if (usb_new_device(usb)) {
+		/* Woops, disable the port */
+		printk(KERN_DEBUG "hub: disabling malfunctioning port %d\n",
+			port + 1);
+		usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
+		usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_POWER);
+	}
 }
 
 static void usb_hub_events(void)
@@ -306,7 +366,7 @@
 
 		for (i = 0; i < hub->nports; i++) {
 			if (usb_get_port_status(dev, i + 1, buf)) {
-				printk("get_port_status failed\n");
+				printk(KERN_ERR "get_port_status failed\n");
 				continue;
 			}
 
@@ -314,7 +374,8 @@
 			portchange = le16_to_cpup((unsigned short *)buf + 1);
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				printk("hub: port %d connection change\n", i + 1);
+				printk(KERN_INFO "hub: port %d connection change\n",
+					i + 1);
 
 				usb_clear_port_feature(dev, i + 1,
 					USB_PORT_FEAT_C_CONNECTION);
@@ -323,46 +384,29 @@
 			}
 
 			if (portchange & USB_PORT_STAT_C_ENABLE) {
-				printk("hub: port %d enable change\n", i + 1);
+				printk(KERN_INFO "hub: port %d enable change\n",
+					i + 1);
 				usb_clear_port_feature(dev, i + 1,
 					USB_PORT_FEAT_C_ENABLE);
 			}
 
 			if (portchange & USB_PORT_STAT_C_SUSPEND)
-				printk("hub: port %d suspend change\n", i + 1);
+				printk(KERN_INFO "hub: port %d suspend change\n",
+					i + 1);
 
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT)
-				printk("hub: port %d over-current change\n", i + 1);
+				printk(KERN_INFO "hub: port %d over-current change\n",
+					i + 1);
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				printk("hub: port %d reset change\n", i + 1);
+				printk(KERN_INFO "hub: port %d reset change\n",
+					i + 1);
 				usb_clear_port_feature(dev, i + 1,
 					USB_PORT_FEAT_C_RESET);
 			}
 
-#if 0
-			if (!portchange)
-				continue;
-
-			if (usb_get_port_status(dev, i + 1, buf))
-				return;
-
-			portstatus = (buf[1] << 8) + buf[0];
-			portchange = (buf[3] << 8) + buf[2];
-
-			printk("hub: port %d status\n", i + 1);
-			printk("hub:  %sdevice present\n", (portstatus & 1) ? "" : "no ");
-			printk("hub:  %s\n", (portstatus & 2) ? "enabled" : "disabled");
-			printk("hub:  %ssuspended\n", (portstatus & 4) ? "" : "not ");
-			printk("hub:  %sover current\n", (portstatus & 8) ? "" : "not ");
-			printk("hub:  has %spower\n", (portstatus & 0x100) ? "" : "no ");
-			printk("hub:  %s speed\n", (portstatus & 0x200) ? "low" : "full");
-#endif
 		}
 		tmp = next;
-#if 0
-		wait_ms(1000);
-#endif
         }
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -370,9 +414,11 @@
 
 static int usb_hub_thread(void *__hub)
 {
+/*
 	MOD_INC_USE_COUNT;
+*/
 	
-	printk(KERN_INFO "USB hub driver registered\n");
+	khubd_running = 1;
 
 	lock_kernel();
 
@@ -389,13 +435,16 @@
 
 	/* Send me a signal to get me die (for debugging) */
 	do {
-		interruptible_sleep_on(&usb_hub_wait);
 		usb_hub_events();
+		interruptible_sleep_on(&khubd_wait);
 	} while (!signal_pending(current));
 
+/*
 	MOD_DEC_USE_COUNT;
+*/
 
 	printk("usb_hub_thread exiting\n");
+	khubd_running = 0;
 
 	return 0;
 }
@@ -414,24 +463,44 @@
 {
 	int pid;
 
-	INIT_LIST_HEAD(&hub_event_list);
-	INIT_LIST_HEAD(&all_hubs_list);
-
 	usb_register(&hub_driver);
-	pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	printk(KERN_INFO "USB hub driver registered\n");
+
+	pid = kernel_thread(usb_hub_thread, NULL,
+		CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	if (pid >= 0) {
 		khubd_pid = pid;
+
 		return 0;
 	}
 
 	/* Fall through if kernel_thread failed */
 	usb_deregister(&hub_driver);
 
-	return 0;
+	return 1;
 }
 
 void usb_hub_cleanup(void)
 {
+	struct list_head *next, *tmp, *head = &hub_list;
+	struct usb_hub *hub;
+	unsigned long flags, flags2;
+	int ret;
+
+	/* Kill the thread */
+	ret = kill_proc(khubd_pid, SIGTERM, 1);
+	if (!ret) {
+		int count = 10;
+
+		while (khubd_running && --count) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+
+		if (!count)
+			printk(KERN_ERR "hub: giving up on killing khubd\n");
+	}
+
 	/*
 	 * Hub resources are freed for us by usb_deregister.  It
 	 * usb_driver_purge on every device which in turn calls that
@@ -443,11 +512,14 @@
 } /* usb_hub_cleanup() */
 
 #ifdef MODULE
-int init_module(void){
+int init_module(void)
+{
 	return usb_hub_init();
 }
 
-void cleanup_module(void){
+void cleanup_module(void)
+{
 	usb_hub_cleanup();
 }
 #endif
+
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.3.12/linux/drivers/usb/ohci-hcd.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/ohci-hcd.c	Thu Aug  5 15:11:52 1999
@@ -1449,14 +1449,14 @@
  
 static int start_ohci(struct pci_dev *dev)
 {
-	unsigned int mem_base = dev->base_address[0];
+	unsigned int mem_base = dev->resource[0].flags;
 
 	/* If its OHCI, its memory */
 	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
 		return -ENODEV;
 
 	/* Get the memory address and map it for IO */
-	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+	mem_base = dev->resource[0].start;
 
 	/* 
 	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.12/linux/drivers/usb/ohci.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/ohci.c	Mon Aug  9 11:27:39 1999
@@ -2607,14 +2607,14 @@
  */
 static int init_ohci(struct pci_dev *dev)
 {
-	unsigned long mem_base = dev->base_address[0];
+	unsigned long mem_base = dev->resource[0].flags;
 	
 	/* If its OHCI, its memory */
 	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
 		return -ENODEV;
 
 	/* Get the memory address and map it for IO */
-	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+	mem_base = dev->resource[0].start;
 
 	/* no interrupt won't work... */
 	if (dev->irq == 0) {
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.12/linux/drivers/usb/printer.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/printer.c	Mon Aug  2 14:31:40 1999
@@ -241,7 +241,7 @@
 			return -EIO;
 
 		if (this_read) {
-			if (copy_to_user(buffer, p->obuf, this_read))
+			if (copy_to_user(buffer, buf, this_read))
 				return -EFAULT;
 			count -= this_read;
 			read_count += this_read;
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/uhci-debug.c linux/drivers/usb/uhci-debug.c
--- v2.3.12/linux/drivers/usb/uhci-debug.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/uhci-debug.c	Sat Aug  7 13:01:44 1999
@@ -115,12 +115,12 @@
 
 #define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
 
-struct uhci_td * uhci_link_to_td(unsigned int link)
+struct uhci_td *uhci_link_to_td(unsigned int link)
 {
-	if (link & 1)
+	if (link & UHCI_PTR_TERM)
 		return NULL;
 
-	return bus_to_virt(link & ~15);
+	return bus_to_virt(link & ~UHCI_PTR_BITS);
 }
 
 void show_queue(struct uhci_qh *qh)
@@ -128,18 +128,24 @@
 	struct uhci_td *td;
 	int i = 0;
 
-#if 0
-	printk("    link = %p, element = %p\n", qh->link, qh->element);
-#endif
-	if(!(qh->element & ~0xF)) {
-		printk("    td 0 = NULL\n");
+	if (qh->element & UHCI_PTR_QH)
+		printk("      Element points to QH?\n");
+
+	if (qh->element & UHCI_PTR_DEPTH)
+		printk("      Depth traverse\n");
+
+	if (qh->element & UHCI_PTR_TERM)
+		printk("      Terminate\n");
+
+	if (!(qh->element & ~UHCI_PTR_BITS)) {
+		printk("      td 0 = NULL\n");
 		return;
 	}
 
 	for(td = uhci_link_to_td(qh->element); td; 
 	    td = uhci_link_to_td(td->link)) {
-		printk("    td %d = %p\n", i++, td);
-		printk("    ");
+		printk("      td %d = %p\n", i++, td);
+		printk("      ");
 		show_td(td);
 	}
 }
@@ -147,39 +153,39 @@
 int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
 	int j;
-	struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
-	for (j = 0; j < UHCI_MAXQH; j++)
-		if (qh == root_hub->qh + j)
+
+	for (j = 0; j < UHCI_NUM_SKELQH; j++)
+		if (qh == uhci->skelqh + j)
 			return 1;
 
 	return 0;
 }
 
-static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4",
-				 "interrupt8", "interrupt16", "interrupt32",
-				 "interrupt64", "interrupt128", "interrupt256",
-				 "control", "bulk0", "bulk1", "bulk2", "bulk3",
-				 "unused", "unused"};
+static const char *qh_names[] = {"interrupt2", "interrupt4", "interrupt8",
+				 "interrupt16", "interrupt32", "interrupt64",
+				 "interrupt128", "interrupt256", "control",
+				 "bulk"};
 
 void show_queues(struct uhci *uhci)
 {
 	int i;
 	struct uhci_qh *qh;
-	struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
 
-	for (i = 0; i < UHCI_MAXQH; ++i) {
-		printk("  %s:\n", qh_names[i]);
-#if 0
-		printk("  qh #%d, %p\n", i, virt_to_bus(root_hub->qh + i));
-		show_queue(uhci->root_hub->qh + i);
-#endif
+	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+		printk("  %s: [%p] (%08X) (%08X)\n", qh_names[i],
+			&uhci->skelqh[i],
+			uhci->skelqh[i].link, uhci->skelqh[i].element);
 
-		qh = uhci_link_to_qh(root_hub->qh[i].link);
+		qh = uhci_link_to_qh(uhci->skelqh[i].link);
 		for (; qh; qh = uhci_link_to_qh(qh->link)) {
 			if (is_skeleton_qh(uhci, qh))
 				break;
 
+			printk("    [%p] (%08X) (%08x)\n",
+				qh, qh->link, qh->element);
+
 			show_queue(qh);
 		}
 	}
 }
+
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.12/linux/drivers/usb/uhci.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/uhci.c	Mon Aug  9 11:27:39 1999
@@ -2,6 +2,7 @@
  * Universal Host Controller Interface driver for USB.
  *
  * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
  *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
@@ -54,32 +55,40 @@
 
 static DECLARE_WAIT_QUEUE_HEAD(uhci_configure);
 
+static kmem_cache_t *uhci_td_cachep;
+static kmem_cache_t *uhci_qh_cachep;
+
+static LIST_HEAD(uhci_list);
+
+#define UHCI_DEBUG
+
 /*
  * Map status to standard result codes
  */
 static int uhci_map_status(int status, int dir_out)
 {
-    if (!status)
-    	    return USB_ST_NOERROR;
-    if (status & 0x02)				/* Bitstuff error*/
-    	    return USB_ST_BITSTUFF;
-    if (status & 0x04)	{			/* CRC/Timeout */
-	if (dir_out)
-    	    return USB_ST_NORESPONSE;
-	else
-	    return USB_ST_CRC;
-    }
-    if (status & 0x08)				/* NAK */
-    	    return USB_ST_TIMEOUT;
-    if (status & 0x10)				/* Babble */
-    	    return USB_ST_STALL;
-    if (status & 0x20)				/* Buffer error */
-    	    return USB_ST_BUFFERUNDERRUN;
-    if (status & 0x40)				/* Stalled */
-    	    return USB_ST_STALL;
-    if (status & 0x80)				/* Active */
-    	    return USB_ST_NOERROR;
-    return USB_ST_INTERNALERROR;
+	if (!status)
+		return USB_ST_NOERROR;
+	if (status & 0x02)				/* Bitstuff error*/
+		return USB_ST_BITSTUFF;
+	if (status & 0x04)	{			/* CRC/Timeout */
+		if (dir_out)
+    			return USB_ST_NORESPONSE;
+		else
+			return USB_ST_CRC;
+	}
+	if (status & 0x08)				/* NAK */
+		return USB_ST_TIMEOUT;
+	if (status & 0x10)				/* Babble */
+		return USB_ST_STALL;
+	if (status & 0x20)				/* Buffer error */
+		return USB_ST_BUFFERUNDERRUN;
+	if (status & 0x40)				/* Stalled */
+		return USB_ST_STALL;
+	if (status & 0x80)				/* Active */
+		return USB_ST_NOERROR;
+
+	return USB_ST_INTERNALERROR;
 }
 /*
  * Return the result of a TD..
@@ -87,9 +96,14 @@
 static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval)
 {
 	unsigned int status;
-	struct uhci_td *tmp = td->first;
+	struct uhci_td *tmp;
+
+	if (!td->qh)
+		tmp = td;
+	else
+		tmp = uhci_ptr_to_virt(td->qh->element);
 
-	if(rval)
+	if (rval)
 		*rval = 0;
 
 	/* locate the first failing td, if any */
@@ -99,52 +113,54 @@
 		if (status) {
 			/* must reset the toggle on first error */
     			if (uhci_debug) {
-			    printk("Set toggle from %x rval %ld\n", (unsigned int)tmp, rval ? *rval : 0);
+				printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
+					(unsigned int)tmp, rval ? *rval : 0);
 			}
-			usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
+			usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info),
+				usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
 			break;
 		} else {
-		    if(rval)
+		    if (rval)
 			*rval += (tmp->status & 0x3ff) + 1;
 		}
-		if ((tmp->link & 1) || (tmp->link & 2))
+		if ((tmp->link & UHCI_PTR_TERM) ||
+		    (tmp->link & UHCI_PTR_QH))
 			break;
-		tmp = bus_to_virt(tmp->link & ~0xF);
+		tmp = uhci_ptr_to_virt(tmp->link);
 	} while (1);
 
-
 	if (!status)
     		return USB_ST_NOERROR;
 
 	/* Some debugging code */
-	if (uhci_debug /* && (!usb_pipeendpoint(tmp->info) || !(status & 0x08))*/ ) {
-		int i = 10;
+	if (uhci_debug) {
+		int count = 10;
 
-		tmp = td->first;
-		printk("uhci_td_result() failed with status %x\n", status);
-		//show_status(dev->uhci);
+		if (!td->qh)
+			tmp = td;
+		else
+			tmp = uhci_ptr_to_virt(td->qh->element);
+		printk(KERN_DEBUG "uhci_td_result() failed with status %x\n",
+			status);
 		do {
 			show_td(tmp);
-			if ((tmp->link & 1) || (tmp->link & 2))
-				break;
-			tmp = bus_to_virt(tmp->link & ~0xF);
-			if (!--i)
+			if ((tmp->link & UHCI_PTR_TERM) ||
+			    (tmp->link & UHCI_PTR_QH))
 				break;
-		} while (1);
+			tmp = uhci_ptr_to_virt(tmp->link);
+		} while (--count);
 	}
 
 	if (status & 0x40) {
-	    /* endpoint has stalled - mark it halted */
-
-	    usb_endpoint_halt(dev->usb, usb_pipeendpoint(tmp->info));
-	    return USB_ST_STALL;
-
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(dev->usb, usb_pipeendpoint(tmp->info));
+		return USB_ST_STALL;
 	}
 
 	if (status == 0x80) {
-	    /* still active */
-	    if (!rval)
-		return USB_ST_DATAUNDERRUN;
+		/* still active */
+		if (!rval)
+			return USB_ST_DATAUNDERRUN;
 	}
 	return uhci_map_status(status, usb_pipeout(tmp->info));		
 }
@@ -163,7 +179,7 @@
 static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last)
 {
 	unsigned int link = qh->element;
-	unsigned int new = 4 | virt_to_bus(first);
+	unsigned int new = virt_to_bus(first) | UHCI_PTR_DEPTH;
 
 	for (;;) {
 		unsigned char success;
@@ -175,9 +191,9 @@
 			:"m" (qh->element), "1" (link), "r" (new)
 			:"memory");
 		if (success) {
-			/* Was there a successor entry? Fix it's backpointer.. */
-			if ((link & 1) == 0) {
-				struct uhci_td *next = bus_to_virt(link & ~15);
+			/* Was there a successor entry? Fix it's backpointer */
+			if ((link & UHCI_PTR_TERM) == 0) {
+				struct uhci_td *next = uhci_ptr_to_virt(link);
 				next->backptr = &last->link;
 			}
 			break;
@@ -193,23 +209,22 @@
 static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh)
 {
 	newqh->link = qh->link;
-	qh->link = virt_to_bus(newqh) | 2;
+	qh->link = virt_to_bus(newqh) | UHCI_PTR_QH;
 }
 
 static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh)
 {
-	unsigned int remphys = virt_to_bus(remqh);
 	struct uhci_qh *lqh = qh;
 
-	while ((lqh->link & ~0xF) != remphys) {
-		if (lqh->link & 1)
+	while (uhci_ptr_to_virt(lqh->link) != remqh) {
+		if (lqh->link & UHCI_PTR_TERM)
 			break;
 
-		lqh = bus_to_virt(lqh->link & ~0xF);
+		lqh = uhci_ptr_to_virt(lqh->link);
 	}
 
-	if (lqh->link & 1) {
-		printk("couldn't find qh in chain!\n");
+	if (lqh->link & UHCI_PTR_TERM) {
+		printk(KERN_DEBUG "couldn't find qh in chain!\n");
 		return;
 	}
 
@@ -244,8 +259,8 @@
 	 * so we can always just look at that and fix up the backpointer
 	 * of any next element..
 	 */
-	if (!(link & 1)) {
-		struct uhci_td *next = bus_to_virt(link & ~15);
+	if (!(link & UHCI_PTR_TERM)) {
+		struct uhci_td *next = uhci_ptr_to_virt(link);
 		next->backptr = backptr;
 	}
 
@@ -262,60 +277,67 @@
 		:"memory");
 }
 
-static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev)
+static struct uhci_td *uhci_td_alloc(struct uhci_device *dev)
 {
-	struct uhci_qh *qh;
-	int inuse;
+	struct uhci_td *td;
 
-	qh = dev->qh;
-	for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++)
-		;
+	td = kmem_cache_alloc(uhci_td_cachep, SLAB_KERNEL);
+	if (!td)
+		return NULL;
 
-	if (!inuse)
-		return(qh);
+#ifdef UHCI_DEBUG
+	if ((__u32)td & UHCI_PTR_BITS)
+		printk("qh not 16 byte aligned!\n");
+#endif
 
-	printk("ran out of qh's for dev %p\n", dev);
-	return(NULL);
-}
+	td->link = UHCI_PTR_TERM;
+	td->buffer = 0;
 
-static void uhci_qh_deallocate(struct uhci_qh *qh)
-{
-//	if (qh->element != 1)
-//		printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
+	td->backptr = NULL;
+	td->qh = NULL;
+	td->dev_id = NULL;
+	td->dev = dev;
+	td->flags = 0;
+	INIT_LIST_HEAD(&td->irq_list);
+	atomic_set(&td->refcnt, 1);
 
-	qh->element = 1;
-	qh->link = 1;
+	return td;
+}
 
-	clear_bit(0, &qh->inuse);
+static void uhci_td_free(struct uhci_td *td)
+{
+	if (atomic_dec_and_test(&td->refcnt))
+		kmem_cache_free(uhci_td_cachep, td);
 }
 
-static struct uhci_td *uhci_td_allocate(struct uhci_device *dev)
+static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev)
 {
-	struct uhci_td *td;
-	int inuse;
+	struct uhci_qh *qh;
 
-	td = dev->td;
-	for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++)
-		;
+	qh = kmem_cache_alloc(uhci_qh_cachep, SLAB_KERNEL);
+	if (!qh)
+		return NULL;
 
-	if (!inuse) {
-    		td->inuse = 1;
-		return(td);
-	}
+#ifdef UHCI_DEBUG
+	if ((__u32)qh & UHCI_PTR_BITS)
+		printk("qh not 16 byte aligned!\n");
+#endif
+
+	qh->element = UHCI_PTR_TERM;
+	qh->link = UHCI_PTR_TERM;
 
-	printk("ran out of td's for dev %p\n", dev);
-	return(NULL);
+	qh->dev = dev;
+	qh->skel = NULL;
+	init_waitqueue_head(&qh->wakeup);
+	atomic_set(&qh->refcnt, 1);
+
+	return qh;
 }
 
-/*
- * This MUST only be called when it has been removed from a QH already (or
- * the QH has been removed from the skeleton
- */
-static void uhci_td_deallocate(struct uhci_td *td)
+static void uhci_qh_free(struct uhci_qh *qh)
 {
-	td->link = 1;
-
-	clear_bit(0, &td->inuse);
+	if (atomic_dec_and_test(&qh->refcnt))
+		kmem_cache_free(uhci_qh_cachep, qh);
 }
 
 /*
@@ -344,6 +366,45 @@
 	spin_unlock_irqrestore(&irqlist_lock, flags);
 }
 
+/*
+ * This function removes and disallcoates all structures set up for an transfer.
+ * It takes the qh out of the skeleton, removes the tq and the td's.
+ * It only removes the associated interrupt handler if removeirq ist set.
+ * The *td argument is any td in the list of td's.
+ */
+static void uhci_remove_transfer(struct uhci_td *td, char removeirq)
+{
+	int maxcount = 1000;
+	struct uhci_td *curtd;
+	unsigned int nextlink;
+
+	if (!td->qh)
+		curtd = td;
+	else
+		curtd = uhci_ptr_to_virt(td->qh->element);
+
+	/* Remove it from the skeleton */
+	uhci_remove_qh(td->qh->skel, td->qh);
+	uhci_qh_free(td->qh);
+	do {
+		nextlink = curtd->link;
+
+		/* IOC? => remove handler */
+		if (removeirq && (td->status & TD_CTRL_IOC))
+			uhci_remove_irq_list(td);
+
+		uhci_remove_td(curtd);
+		uhci_td_free(curtd);
+		if (nextlink & UHCI_PTR_TERM)	/* Tail? */
+			break;
+
+		curtd = bus_to_virt(nextlink & ~UHCI_PTR_BITS);
+		if (!--maxcount) {
+			printk(KERN_ERR "runaway td's!?\n");
+			break;
+		}
+	} while (1);
+}
 
 /*
  * Request a interrupt handler..
@@ -351,101 +412,50 @@
  * Returns: a "handle pointer" that release_irq can use to stop this
  * interrupt.  (It's really a pointer to the TD).
  */
-static void* uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+static void *uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
-	struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
-	struct uhci_td *td = uhci_td_allocate(dev);
-	struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev);
-
+	struct uhci_td *td = uhci_td_alloc(dev);
+	struct uhci_qh *qh = uhci_qh_alloc(dev);
 	unsigned int destination, status;
 
-	/* Destination: pipe destination with INPUT */
-	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+	if (!td || !qh)
+		return NULL;
 
-	/* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
-	status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
+	/* Destination: pipe destination with INPUT */
+	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe);
 
-	if(interrupt_qh->element != 1)
-		printk("interrupt_qh->element = 0x%x\n", 
-		       interrupt_qh->element);
+	/* Infinite errors is 0, so no bits */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_IOC | TD_CTRL_ACTIVE |
+			TD_CTRL_SPD;
 
-	td->link = 1;
-	td->status = status;
+	td->link = UHCI_PTR_TERM;		/* Terminate */
+	td->status = status;			/* In */
 	td->info = destination | ((usb_maxpacket(usb_dev, pipe) - 1) << 21) |
-		(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);
+		(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe),
+		usb_pipeout(pipe)) << 19);
 	td->buffer = virt_to_bus(dev->data);
-	td->first = td;
-	td->qh = interrupt_qh;
-	td->dev = usb_dev;
+	td->qh = qh;
+	td->dev = dev;
 
 	/* if period 0, insert into fast q */
-
 	if (period == 0) {
-		td->inuse |= 2;
-		interrupt_qh->skel = &root_hub->skel_int2_qh;
+		td->flags |= UHCI_TD_REMOVE;
+		qh->skel = &dev->uhci->skel_int2_qh;
 	} else
-		interrupt_qh->skel = &root_hub->skel_int8_qh;
+		qh->skel = &dev->uhci->skel_int8_qh;
 
 	uhci_add_irq_list(dev->uhci, td, handler, dev_id);
 
-	uhci_insert_td_in_qh(interrupt_qh, td);
+	uhci_insert_td_in_qh(qh, td);
 
 	/* Add it into the skeleton */
-	uhci_insert_qh(interrupt_qh->skel, interrupt_qh);
+	uhci_insert_qh(qh->skel, qh);
 
-	return (void*)td;
+	return (void *)td;
 }
 
 /*
- * Remove running irq td from queues
- *
- * This function is not used anymore.
- */
-#if 0
-static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
-{
-    struct uhci_device *dev = usb_to_uhci(usb_dev);
-    struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
-    struct uhci_td *td;
-    struct uhci_qh *interrupt_qh;
-    unsigned long flags;
-    struct list_head *head = &dev->uhci->interrupt_list;
-    struct list_head *tmp;
-
-    spin_lock_irqsave(&irqlist_lock, flags);
-
-    /* find the TD in the interrupt list */
-
-    tmp = head->next;
-    while (tmp != head) {
-	td = list_entry(tmp, struct uhci_td, irq_list);
-	if (td->dev_id == dev_id && td->completed == handler) {
-
-	    /* found the right one - let's remove it */
-
-	    /* notify removal */
-
-	    td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
-
-	    /* this is DANGEROUS - not sure whether this is right */
-
-	    list_del(&td->irq_list);
-	    uhci_remove_td(td);
-	    interrupt_qh = td->qh;
-	    uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
-	    uhci_td_deallocate(td);
-	    uhci_qh_deallocate(interrupt_qh);
-	    spin_unlock_irqrestore(&irqlist_lock, flags);
-	    return USB_ST_NOERROR;
-	}
-    }
-    spin_unlock_irqrestore(&irqlist_lock, flags);
-    return USB_ST_INTERNALERROR;
-}
-#endif
-
-/*
  * Release an interrupt handler previously allocated using
  * uhci_request_irq.  This function does no validity checking, so make
  * sure you're not releasing an already released handle as it may be
@@ -453,45 +463,40 @@
  *
  * This function can NOT be called from an interrupt.
  */
-int uhci_release_irq(void* handle)
+int uhci_release_irq(void *handle)
 {
 	struct uhci_td *td;
-	struct uhci_qh *interrupt_qh;
-	unsigned long flags;
+	struct uhci_qh *qh;
 
 #ifdef UHCI_DEBUG
-	printk("usb-uhci: Releasing irq handle %p\n", handle);
+	printk(KERN_DEBUG "usb-uhci: releasing irq handle %p\n", handle);
 #endif
 
-	td = (struct uhci_td*)handle;
-	if (td == NULL)
+	td = (struct uhci_td *)handle;
+	if (!td)
 		return USB_ST_INTERNALERROR;
 
 	/* Remove it from the internal irq_list */
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_del(&td->irq_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
+	uhci_remove_irq_list(td);
 
 	/* Remove the interrupt TD and QH */
 	uhci_remove_td(td);
-	interrupt_qh = td->qh;
-	uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
+	qh = td->qh;
+	uhci_remove_qh(qh->skel, qh);
 
 	if (td->completed != NULL)
 		td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
 
 	/* Free the TD and QH */
-	uhci_td_deallocate(td);
-	uhci_qh_deallocate(interrupt_qh);
+	uhci_td_free(td);
+	uhci_qh_free(qh);
 
 	return USB_ST_NOERROR;
 } /* uhci_release_irq() */
 
-
 /*
- * Isochronous thread operations
+ * Isochronous operations
  */
-
 static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
 {
 	struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
@@ -499,18 +504,19 @@
 	int i, totlen = 0;
 
 	for (i = 0; i < isodesc->num; i++) {
-		char *cdata = bus_to_virt(isodesc->td[i].buffer & ~0xF);
-		int n = (isodesc->td[i].status + 1) & 0x7FF;
+		struct uhci_td *td = &isodesc->td[i];
+		char *cdata = uhci_ptr_to_virt(td->buffer);
+		int n = (td->status + 1) & 0x7FF;
 
 		if ((cdata != data) && (n))
 			memmove(data, cdata, n);
 
-#if 0
-if (n && n != 960)
-	printk("underrun: %d %d\n", i, n);
+#ifdef UHCI_DEBUG
+		/* Debugging */
+		if ((td->status >> 16) & 0xFF)
+			printk(KERN_DEBUG "error: %d %X\n", i,
+				(td->status >> 16));
 #endif
-if ((isodesc->td[i].status >> 16) & 0xFF)
-	printk("error: %d %X\n", i, (isodesc->td[i].status >> 16));
 
 		data += n;
 		totlen += n;
@@ -526,14 +532,22 @@
 	struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
 	int i;
 
-	if ((isodesc->frame < 0) || (isodesc->frame > 1023))
+	if ((isodesc->frame < 0) || (isodesc->frame > 1023)) {
+		printk(KERN_ERR "illegal frame number %d\n", isodesc->frame);
 		return 1;
+	}
+
+	/* FIXME: Use uhci_remove_td */
 
 	/* Remove from previous frames */
 	for (i = 0; i < isodesc->num; i++) {
+		struct uhci_td *td = &isodesc->td[i];
+
 		/* Turn off Active and IOC bits */
-		isodesc->td[i].status &= ~(3 << 23);
-		uhci->fl->frame[(isodesc->frame + i) % 1024] = isodesc->td[i].link;
+		td->status &= ~(3 << 23);
+		td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
+		
+		uhci->fl->frame[(isodesc->frame + i) % 1024] = td->link;
 	}
 
 	isodesc->frame = -1;
@@ -551,43 +565,36 @@
 	int frame, i;
 
 	if (isodesc->frame != -1) {
-		printk("isoc queue not removed\n");
+		printk(KERN_ERR "isoc queue not removed\n");
 		uhci_unschedule_isochronous(usb_dev, isodesc);
 	}
 
 	/* Insert TD into list */
 	if (!pisodesc) {
+		/* It's not guaranteed to be 1-1024 */
 		frame = inw(uhci->io_addr + USBFRNUM) % 1024;
+
 		/* HACK: Start 2 frames from now */
 		frame = (frame + 2) % 1024;
 	} else
 		frame = (pisodesc->endframe + 1) % 1024;
 
-#if 0
-printk("scheduling first at frame %d\n", frame);
-#endif
-
 	for (i = 0; i < isodesc->num; i++) {
+		struct uhci_td *td = &isodesc->td[i];
+
 		/* Active */
-		isodesc->td[i].status |= (1 << 23);
-		isodesc->td[i].backptr = &uhci->fl->frame[(frame + i) % 1024];
-		isodesc->td[i].link = uhci->fl->frame[(frame + i) % 1024];
-		uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(&isodesc->td[i]);
+		td->status |= TD_CTRL_ACTIVE;
+		td->backptr = &uhci->fl->frame[(frame + i) % 1024];
+		td->link = uhci->fl->frame[(frame + i) % 1024];
+		uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(td);
 	}
 
-#if 0
-printk("last at frame %d\n", (frame + i - 1) % 1024);
-#endif
-
-	/* Interrupt */
-	isodesc->td[i - 1].status |= (1 << 24);
+	/* IOC on the last TD */
+	isodesc->td[i - 1].status |= TD_CTRL_IOC;
 
 	isodesc->frame = frame;
 	isodesc->endframe = (frame + isodesc->num - 1) % 1024;
 
-#if 0
-	return uhci_td_result(dev, td[num - 1]);
-#endif
 	return 0;
 }
 
@@ -604,20 +611,21 @@
 
 	isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL);
 	if (!isodesc) {
-		printk("Couldn't allocate isodesc!\n");
+		printk(KERN_ERR "Couldn't allocate isodesc!\n");
 		return NULL;
 	}
+
 	memset(isodesc, 0, sizeof(*isodesc));
 
 	/* Carefully work around the non contiguous pages */
-	isodesc->num = (len / PAGE_SIZE) * (PAGE_SIZE / maxsze);
+	isodesc->num = len / maxsze;
 	isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL);
 	isodesc->frame = isodesc->endframe = -1;
 	isodesc->data = data;
 	isodesc->maxsze = maxsze;
 	
 	if (!isodesc->td) {
-		printk("Couldn't allocate td's\n");
+		printk(KERN_ERR "couldn't allocate td's\n");
 		kfree(isodesc);
 		return NULL;
 	}
@@ -634,10 +642,9 @@
 
 		/* The "pipe" thing contains the destination in bits 8--18 */
 		destination = (pipe & PIPE_DEVEP_MASK)
-			| usb_packetid (pipe);	/* add IN or OUT */
+			| usb_packetid (pipe);  /* add IN or OUT */
 
-		/* Status:    slow/fast,       Active,       Isochronous */
-		status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 25);
+		status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOS;
 
 		/*
 		 * Build the TD for the control request
@@ -645,21 +652,14 @@
 		td->status = status;
 		td->info = destination | ((maxsze - 1) << 21);
 		td->buffer = virt_to_bus(data);
-		td->first = td;
 		td->backptr = NULL;
 
 		i++;
 
 		data += maxsze;
-
-		if (((int)data % PAGE_SIZE) + maxsze >= PAGE_SIZE)
-			data = (char *)(((int)data + maxsze) & ~(PAGE_SIZE - 1));
-		
 		len -= maxsze;
 	} while (i < isodesc->num);
 
-	/* IOC on the last TD */
-	td->status |= (1 << 24);
 	uhci_add_irq_list(dev->uhci, td, completed, dev_id);
 
 	return isodesc;
@@ -688,11 +688,16 @@
  * We need to remove the TD from the lists (both interrupt
  * list and TD lists) by hand if something bad happens!
  */
-static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
 
-static int uhci_control_completed(int status, void *buffer, int len, void *dev_id)
+static int uhci_generic_completed(int status, void *buffer, int len, void *dev_id)
 {
-	wake_up(&control_wakeup);
+	wait_queue_head_t *wakeup = (wait_queue_head_t *)dev_id;
+
+	if (waitqueue_active(wakeup))
+		wake_up(wakeup);
+	else
+		printk("waitqueue empty!\n");
+
 	return 0;			/* Don't re-instate */
 }
 
@@ -700,62 +705,52 @@
 static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev);
-	struct uhci_td *curtd;
-	struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
+	struct uhci_qh *qh = uhci_qh_alloc(dev);
+
+	if (!qh)
+		return -1;
+
 	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&control_wakeup, &wait);
+	add_wait_queue(&qh->wakeup, &wait);
 
-	uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL);
+	uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup);
 	
+#if 0
 	/* FIXME: This is kinda kludged */
 	/* Walk the TD list and update the QH pointer */
 	{
-	int maxcount = 100;
+	struct uhci_td *curtd;
+	int count = 100;
 
 	curtd = first;
 	do {
 		curtd->qh = ctrl_qh;
-		if (curtd->link & 1)
+		if (curtd->link & TD_CTRL_TERM)
 			break;
 
-		curtd = bus_to_virt(curtd->link & ~0xF);
-		if (!--maxcount) {
-			printk("runaway tds!\n");
-			break;
-		}
-	} while (1);
+		curtd = uhci_ptr_to_virt(curtd->link);
+	} while (--count);
+	if (!count)
+		printk(KERN_DEBUG "runaway tds!\n");
 	}
+#endif
 
-	uhci_insert_tds_in_qh(ctrl_qh, first, last);
+	uhci_insert_tds_in_qh(qh, first, last);
 
 	/* Add it into the skeleton */
-	uhci_insert_qh(&root_hub->skel_control_qh, ctrl_qh);
+	uhci_insert_qh(&dev->uhci->skel_control_qh, qh);
 
-//	control should be full here...	
-//	printk("control\n");
-//	show_status(dev->uhci);
-//	show_queues(dev->uhci);
+	schedule_timeout(HZ * 5);	/* 5 seconds */
 
-	schedule_timeout(HZ*5);
-
-//	control should be empty here...	
-//	show_status(dev->uhci);
-//	show_queues(dev->uhci);
-
-	remove_wait_queue(&control_wakeup, &wait);
+	remove_wait_queue(&qh->wakeup, &wait);
 
 	/* Clean up in case it failed.. */
 	uhci_remove_irq_list(last);
 
-#if 0
-	printk("Looking for tds [%p, %p]\n", dev->control_td, td);
-#endif
-
 	/* Remove it from the skeleton */
-	uhci_remove_qh(&root_hub->skel_control_qh, ctrl_qh);
+	uhci_remove_qh(&dev->uhci->skel_control_qh, qh);
 
-	uhci_qh_deallocate(ctrl_qh);
+	uhci_qh_free(qh);
 
 	return uhci_td_result(dev, last, NULL);
 }
@@ -786,19 +781,19 @@
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_td *first, *td, *prevtd;
 	unsigned long destination, status;
-	int ret;
+	int ret, count;
 	int maxsze = usb_maxpacket(usb_dev, pipe);
+	__u32 nextlink;
 
-	if (len > maxsze * 29)
-		printk("Warning, too much data for a control packet, crashing\n");
-
-	first = td = uhci_td_allocate(dev);
+	first = td = uhci_td_alloc(dev);
+	if (!td)
+		return -ENOMEM;
 
 	/* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
 	destination = (pipe & PIPE_DEVEP_MASK) | 0x2D;
 
-	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
-	status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
+	/* 3 errors */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | (3 << 27);
 
 	/*
 	 * Build the TD for the control request
@@ -806,7 +801,6 @@
 	td->status = status;				/* Try forever */
 	td->info = destination | (7 << 21);		/* 8 bytes of data */
 	td->buffer = virt_to_bus(cmd);
-	td->first = td;
 
 	/*
 	 * If direction is "send", change the frame from SETUP (0x2D)
@@ -817,8 +811,11 @@
 		destination ^= (0xE1 ^ 0x69);		/* IN -> OUT */
 
 	prevtd = td;
-	td = uhci_td_allocate(dev);
-	prevtd->link = 4 | virt_to_bus(td);
+	td = uhci_td_alloc(dev);
+	if (!td)
+		return -ENOMEM;
+
+	prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
 
 	/*
 	 * Build the DATA TD's
@@ -834,18 +831,18 @@
 		destination ^= 1 << 19;
 	
 		td->status = status;					/* Status */
-		td->info = destination | ((pktsze-1) << 21);		/* pktsze bytes of data */
+		td->info = destination | ((pktsze - 1) << 21);		/* pktsze bytes of data */
 		td->buffer = virt_to_bus(data);
-		td->first = first;
 		td->backptr = &prevtd->link;
 
 		data += pktsze;
 		len -= pktsze;
 
 		prevtd = td;
-		td = uhci_td_allocate(dev);
-		prevtd->link = 4 | virt_to_bus(td);			/* Update previous TD */
-
+		td = uhci_td_alloc(dev);
+		if (!td)
+			return -ENOMEM;
+		prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;	/* Update previous TD */
 	}
 
 	/*
@@ -854,47 +851,40 @@
 	destination ^= (0xE1 ^ 0x69);			/* OUT -> IN */
 	destination |= 1 << 19;				/* End in Data1 */
 
-	td->backptr = &prevtd->link;
-	td->status = (status /* & ~(3 << 27) */) | (1 << 24);	/* no limit on final packet */
+	td->status = status | TD_CTRL_IOC;			/* no limit on errors on final packet */
 	td->info = destination | (UHCI_NULL_DATA_SIZE << 21);	/* 0 bytes of data */
 	td->buffer = 0;
-	td->first = first;
-	td->link = 1;					/* Terminate */
-
+	td->backptr = &prevtd->link;
+	td->link = UHCI_PTR_TERM;			/* Terminate */
 
 	/* Start it up.. */
 	ret = uhci_run_control(dev, first, td);
 
-	{
-		int maxcount = 100;
-		struct uhci_td *curtd = first;
-		unsigned int nextlink;
+	count = 100;
+	td = first;
+	do {
+		nextlink = td->link;
+		uhci_remove_td(td);
+		uhci_td_free(td);
 
-		do {
-			nextlink = curtd->link;
-			uhci_remove_td(curtd);
-			uhci_td_deallocate(curtd);
-			if (nextlink & 1)	/* Tail? */
-				break;
+		if (nextlink & UHCI_PTR_TERM)	/* Tail? */
+			break;
 
-			curtd = bus_to_virt(nextlink & ~0xF);
-			if (!--maxcount) {
-				printk("runaway td's!?\n");
-				break;
-			}
-		} while (1);
-	}
+		td = uhci_ptr_to_virt(nextlink);
+	} while (--count);
+
+	if (!count)
+		printk(KERN_ERR "runaway td's!?\n");
 
 	if (uhci_debug && ret) {
 		__u8 *p = (__u8 *)cmd;
 
-		printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
+		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]);
 	}
 	return ret;
 }
 
-
 /*
  * Bulk thread operations: we just mark the last TD
  * in a bulk thread as an interrupt TD, and wake up
@@ -903,74 +893,56 @@
  * We need to remove the TD from the lists (both interrupt
  * list and TD lists) by hand if something bad happens!
  */
-static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
-
-static int uhci_bulk_completed(int status, void *buffer, int len, void *dev_id)
-{
-	wake_up(&bulk_wakeup);
-	return 0;			/* Don't re-instate */
-}
 
 /* td points to the last td in the list, which interrupts on completion */
 static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
-	struct uhci_td *curtd;
-	struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
+	struct uhci_qh *qh = uhci_qh_alloc(dev);
+
+	if (!qh)
+		return -ENOMEM;
 
 	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&bulk_wakeup, &wait);
+	add_wait_queue(&qh->wakeup, &wait);
 
-	uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL);
+	uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup);
 	
+#if 0
 	/* FIXME: This is kinda kludged */
 	/* Walk the TD list and update the QH pointer */
 	{
-	int maxcount = 100;
+	struct uhci_td *curtd;
+	int count = 100;
 
 	curtd = first;
 	do {
 		curtd->qh = bulk_qh;
-		if (curtd->link & 1)
+		if (curtd->link & UHCI_PTR_TERM)
 			break;
 
-		curtd = bus_to_virt(curtd->link & ~0xF);
-		if (!--maxcount) {
-			printk("runaway tds!\n");
-			break;
-		}
-	} while (1);
+		curtd = uhci_ptr_to_virt(curtd->link);
+	} while (--count);
+	if (!count)
+		printk(KERN_ERR "runaway tds!\n");
 	}
+#endif
 
-	uhci_insert_tds_in_qh(bulk_qh, first, last);
+	uhci_insert_tds_in_qh(qh, first, last);
 
 	/* Add it into the skeleton */
-	uhci_insert_qh(&root_hub->skel_bulk0_qh, bulk_qh);
+	uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh);
 
-//	now we're in the queue... but don't ask WHAT is in there ;-(
-//	printk("bulk\n");
-//	show_status(dev->uhci);
-//	show_queues(dev->uhci);
-
-	schedule_timeout(HZ*5);
-//	show_status(dev->uhci);
-//	show_queues(dev->uhci);
+	schedule_timeout(HZ*5);		/* 5 seconds */
 
-	//show_queue(first->qh);
-	remove_wait_queue(&bulk_wakeup, &wait);
+	remove_wait_queue(&qh->wakeup, &wait);
 
 	/* Clean up in case it failed.. */
 	uhci_remove_irq_list(last);
 
-#if 0
-	printk("Looking for tds [%p, %p]\n", dev->control_td, td);
-#endif
+	uhci_remove_qh(&dev->uhci->skel_bulk_qh, qh);
 
-	/* Remove it from the skeleton */
-	uhci_remove_qh(&root_hub->skel_bulk0_qh, bulk_qh);
-
-	uhci_qh_deallocate(bulk_qh);
+	uhci_qh_free(qh);
 
 	return uhci_td_result(dev, last, rval);
 }
@@ -983,13 +955,6 @@
  *
  * A bulk message is only built up from
  * the data phase
- *
- * The data phase can be an arbitrary number of TD's
- * although we currently had better not have more than
- * 31 TD's here.
- *
- * 31 TD's is a minimum of 248 bytes worth of bulk
- * information.
  */
 static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
 {
@@ -1003,19 +968,19 @@
 	    usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80)))
 		return USB_ST_STALL;
 
-	if (len > maxsze * 31)
-		printk("Warning, too much data for a bulk packet, crashing (%d/%d)\n", len, maxsze);
-
 	/* The "pipe" thing contains the destination in bits 8--18 */
 	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
 
-	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
-	status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
+	/* 3 errors */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | (3 << 27);
 
 	/*
 	 * Build the TDs for the bulk request
 	 */
-        first = td = uhci_td_allocate(dev);
+        first = td = uhci_td_alloc(dev);
+	if (!td)
+		return -ENOMEM;
+
         prevtd = first; //This is fake, but at least it's not NULL
 	while (len > 0) {
 		/* Build the TD for control status */
@@ -1029,22 +994,25 @@
 			 (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
 		td->buffer = virt_to_bus(data);
 		td->backptr = &prevtd->link;
-		td->first = first;
 
 		data += maxsze;
 		len -= maxsze;
 
 		if (len > 0) {
 			prevtd = td;
-			td = uhci_td_allocate(dev);
-			prevtd->link = 4 | virt_to_bus(td);			/* Update previous TD */
+			td = uhci_td_alloc(dev);
+			if (!td)
+				return -ENOMEM;
+
+			prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;/* Update previous TD */
 		}
 
 		/* Alternate Data0/1 (start with Data0) */
 		usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 	}
+
 	td->link = 1;				/* Terminate */
-	td->status |= (1 << 24);		/* IOC */
+	td->status |= TD_CTRL_IOC;
 
 	/* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
 
@@ -1052,43 +1020,120 @@
 	ret = uhci_run_bulk(dev, first, td, rval);
 
 	{
-		int maxcount = 100;
+		int count = 100;
 		struct uhci_td *curtd = first;
 		unsigned int nextlink;
 
 		do {
 			nextlink = curtd->link;
 			uhci_remove_td(curtd);
-			uhci_td_deallocate(curtd);
-			if (nextlink & 1)	/* Tail? */
-				break;
+			uhci_td_free(curtd);
 
-			curtd = bus_to_virt(nextlink & ~0xF);
-			if (!--maxcount) {
-				printk("runaway td's!?\n");
+			if (nextlink & UHCI_PTR_TERM)	/* Tail? */
 				break;
-			}
-		} while (1);
+
+			curtd = uhci_ptr_to_virt(nextlink);
+		} while (--count);
+
+		if (!count)
+			printk(KERN_DEBUG "runaway td's!?\n");
 	}
 
 	return ret;
 }
 
-static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
+static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
+{
+	struct uhci_device *dev = usb_to_uhci(usb_dev);
+	struct uhci *uhci = dev->uhci;
+	struct uhci_td *first, *td, *prevtd;
+	struct uhci_qh *bulk_qh = uhci_qh_alloc(dev);
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(usb_dev, pipe);
+
+	/* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
+	destination = (pipe & 0x0007ff00) | usb_packetid(pipe);
+
+	/* Infinite errors is 0 */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD;
+
+	/* Build the TDs for the bulk request */
+	first = td = uhci_td_alloc(dev);
+	prevtd = td;
+	while (len > 0) {
+		/* Build the TD for control status */
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td->status = status;                                    /* Status */
+		td->info = destination | ((pktsze-1) << 21) |
+			(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
+		td->buffer = virt_to_bus(data);
+		td->backptr = &prevtd->link;
+		td->qh = bulk_qh;
+		td->dev = dev;
+		data += pktsze;
+		len -= pktsze;
+
+		if (len > 0) {
+			prevtd = td;
+			td = uhci_td_alloc(dev);
+			prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
+		}
+
+		/* Alternate Data0/1 */
+		usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+	}
+
+	first->backptr = NULL;
+	td->link = 1;                           /* Terminate */
+	td->status = status | TD_CTRL_IOC;	/* IOC */
+
+	uhci_add_irq_list(dev->uhci, td, handler, dev_id);
+
+	uhci_insert_tds_in_qh(bulk_qh, first, td);
+
+	bulk_qh->skel = &uhci->skel_bulk_qh;
+	uhci_insert_qh(&uhci->skel_bulk_qh, bulk_qh);
+
+	/* Return last td for removal */
+	return td;
+}
+
+/*
+ *Remove a handler from a pipe. This terminates the transfer.
+ *We have some assumptions here:
+ * There is only one queue using this pipe. (the one we remove)
+ * Any data that is in the queue is useless for us, we throw it away.
+ */
+static int uhci_terminate_bulk(struct usb_device *dev, void * first)
+{
+	/* none found? there is nothing to remove! */
+	if (!first)
+		return 0;
+
+	uhci_remove_transfer(first,1);
+
+	return 1;
+}
+
+static struct usb_device *uhci_usb_alloc(struct usb_device *parent)
 {
 	struct usb_device *usb_dev;
 	struct uhci_device *dev;
-	int i;
 
+	/* Allocate the USB device */
 	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
 	if (!usb_dev)
 		return NULL;
 
 	memset(usb_dev, 0, sizeof(*usb_dev));
 
+	/* Allocate the UHCI device private data */
 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
-		usb_destroy_configuration(usb_dev);
 		kfree(usb_dev);
 		return NULL;
 	}
@@ -1106,49 +1151,12 @@
 		dev->uhci = usb_to_uhci(parent)->uhci;
 	}
 
-	/* Reset the QH's and TD's */
-	for (i = 0; i < UHCI_MAXQH; i++) {
-		dev->qh[i].link = 1;
-		dev->qh[i].element = 1;
-		dev->qh[i].inuse = 0;
-	}
-
-	for (i = 0; i < UHCI_MAXTD; i++) {
-		dev->td[i].link = 1;
-		dev->td[i].inuse = 0;
-	}
-
 	return usb_dev;
 }
 
-static int uhci_usb_deallocate(struct usb_device *usb_dev)
+static int uhci_usb_free(struct usb_device *usb_dev)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
-	int i;
-
-	/* There are UHCI_MAXTD preallocated tds */
-	for (i = 0; i < UHCI_MAXTD; ++i) {
-		struct uhci_td *td = dev->td + i;
-
-		if (td->inuse & 1) {
-			uhci_remove_td(td);
-
-			/* And remove it from the irq list, if it's active */
-			if (td->status & (1 << 23))
-				td->status &= ~(1 << 23);
-#if 0
-				uhci_remove_irq_list(td);
-#endif
-		}
-	}
-
-	/* Remove the td from any queues */
-	for (i = 0; i < UHCI_MAXQH; ++i) {
-		struct uhci_qh *qh = dev->qh + i;
-
-		if (qh->inuse & 1)
-			uhci_remove_qh(qh->skel, qh);
-	}
 
 	kfree(dev);
 	usb_destroy_configuration(usb_dev);
@@ -1158,12 +1166,14 @@
 }
 
 struct usb_operations uhci_device_operations = {
-	uhci_usb_allocate,
-	uhci_usb_deallocate,
+	uhci_usb_alloc,
+	uhci_usb_free,
 	uhci_control_msg,
 	uhci_bulk_msg,
 	uhci_request_irq,
 	uhci_release_irq,
+	uhci_request_bulk,
+	uhci_terminate_bulk,
 	uhci_allocate_isochronous,
 	uhci_delete_isochronous,
 	uhci_schedule_isochronous,
@@ -1200,7 +1210,6 @@
 
 }
 
-
 /*
  * This gets called if the connect status on the root
  * hub (and the root hub only) changes.
@@ -1210,8 +1219,11 @@
 	struct usb_device *usb_dev;
 	struct uhci_device *dev;
 	unsigned short status;
-	struct uhci_device *root_hub=usb_to_uhci(uhci->bus->root_hub);
-	printk("uhci_connect_change: called for %d\n", nr);
+	struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
+
+#ifdef UHCI_DEBUG
+	printk(KERN_INFO "uhci_connect_change: called for %d\n", nr);
+#endif
 
 	/*
 	 * Even if the status says we're connected,
@@ -1235,14 +1247,12 @@
 	 * Ok, we got a new connection. Allocate a device to it,
 	 * and find out what it wants to do..
 	 */
-	usb_dev = uhci_usb_allocate(root_hub->usb);
+	usb_dev = uhci_usb_alloc(root_hub->usb);
 	if (!usb_dev)
 		return;
 	
 	dev = usb_dev->hcpriv;
 
-	dev->uhci = uhci;
-
 	usb_connect(usb_dev);
 
 	root_hub->usb->children[nr] = usb_dev;
@@ -1258,7 +1268,13 @@
 	 * The rest is generic for any new USB attach, regardless of
 	 * hub type.
 	 */
-	usb_new_device(usb_dev);
+	if (usb_new_device(usb_dev)) {
+		unsigned short status = inw(port);
+
+		printk(KERN_INFO "uhci: disabling malfunctioning port %d\n",
+			nr + 1);
+		outw(status | USBPORTSC_PE, port);
+	}
 }
 
 /*
@@ -1268,7 +1284,7 @@
  */
 static void uhci_check_configuration(struct uhci *uhci)
 {
-	struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
+	struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
 	unsigned int io_addr = uhci->io_addr + USBPORTSC1;
 	int maxchild = root_hub->usb->maxchild;
 	int nr = 0;
@@ -1285,54 +1301,70 @@
 
 static void uhci_interrupt_notify(struct uhci *uhci)
 {
-	struct list_head *head = &uhci->interrupt_list;
-	struct list_head *tmp;
+	struct list_head *tmp, *head = &uhci->interrupt_list;
 	int status;
 
 	spin_lock(&irqlist_lock);
 	tmp = head->next;
 	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
-		struct list_head *next;
+		struct uhci_td *first, *td = list_entry(tmp,
+					struct uhci_td, irq_list);
 
-		next = tmp->next;
+		tmp = tmp->next;
 
-		if (!((status = td->status) & (1 << 23)) ||  /* No longer active? */
-		    ((td->qh->element & ~15) && 
-		      !((status = uhci_link_to_td(td->qh->element)->status) & (1 <<23)) &&
-		      (status & 0x760000) /* is in error state (Stall, db, babble, timeout, bitstuff) */)) {	
-			/* remove from IRQ list */
-			__list_del(tmp->prev, next);
-			INIT_LIST_HEAD(tmp);
-			if (td->completed(uhci_map_status(status, 0), bus_to_virt(td->buffer), -1, td->dev_id)) {
-				list_add(&td->irq_list, &uhci->interrupt_list);
-
-				if (!(td->status & (1 << 25))) {
-					struct uhci_qh *interrupt_qh = td->qh;
-
-					usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
-					td->info &= ~(1 << 19); /* clear data toggle */
-					td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */
-					td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24);	/* active */
-
-					/* Remove then readd? Is that necessary */
-					uhci_remove_td(td);
-					uhci_insert_td_in_qh(interrupt_qh, td);
-				}
-			} else if (td->inuse & 2) {
-				struct uhci_qh *interrupt_qh = td->qh;
-				/* marked for removal */
-				td->inuse &= ~2;
-				usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
-				uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
-				uhci_qh_deallocate(interrupt_qh);
-				uhci_td_deallocate(td);
+		/* We check the TD which had the IOC bit as well as the */
+		/*  first TD */
+		/* XXX: Shouldn't we check all of the TD's in the chain? */
+		if ((td->qh) && (td->qh->element & ~UHCI_PTR_BITS))
+			first = uhci_link_to_td(td->qh->element);
+		else
+			first = NULL;
+
+		/* If any of the error bits are set OR the active is NOT set */
+		/*  then we're interested in this TD */
+		status = td->status & 0xF60000;
+
+		if ((!(status ^ TD_CTRL_ACTIVE)) && (first) &&
+		    (!(first->status & TD_CTRL_ACTIVE)))
+			status = first->status & 0xF60000;
+
+		if (!(status ^ TD_CTRL_ACTIVE))
+			continue;
+
+
+		/* remove from IRQ list */
+		list_del(&td->irq_list);
+		INIT_LIST_HEAD(&td->irq_list);
+
+		if (td->completed(uhci_map_status(status, 0),
+		    bus_to_virt(td->buffer), -1, td->dev_id)) {
+			list_add(&td->irq_list, &uhci->interrupt_list);
+
+			/* Isochronous TD's don't need this */
+			if (!(td->status & TD_CTRL_IOS)) {
+				struct usb_device *usb_dev = td->dev->usb;
+
+				usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
+				td->info &= ~(1 << 19); /* clear data toggle */
+				td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */
+				td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+				/* The HC removes it, so readd it */
+				uhci_insert_td_in_qh(td->qh, td);
 			}
-			/* If completed wants to not reactivate, then it's */
-			/* responsible for free'ing the TD's and QH's */
-			/* or another function (such as run_control) */
-		} 
-		tmp = next;
+		} 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), usb_pipeout(td->info));
+			uhci_remove_qh(td->qh->skel, td->qh);
+			uhci_qh_free(td->qh);
+			uhci_td_free(td);
+		}
+
+		/* If completed does not wants to reactivate, then */
+		/* it's responsible for free'ing the TD's and QH's */
+		/* or another function (such as run_control) */
 	}
 	spin_unlock(&irqlist_lock);
 }
@@ -1348,8 +1380,9 @@
 static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr)
 {
 	if (waitqueue_active(&uhci_configure)) {
-		struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
+		struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
 		int ports = root_hub->usb->maxchild;
+
 		io_addr += USBPORTSC1;
 		do {
 			if (inw(io_addr) & USBPORTSC_CSC) {
@@ -1373,9 +1406,6 @@
 	status = inw(io_addr + USBSTS);
 	outw(status, io_addr + USBSTS);
 
-//	if ((status & ~0x21) != 0)
-//		printk("interrupt: %X\n", status);
-
 	/* Walk the list of pending TD's to see which ones completed.. */
 	uhci_interrupt_notify(uhci);
 
@@ -1393,16 +1423,23 @@
 static void uhci_init_ticktd(struct uhci *uhci)
 {
 	struct uhci_device *dev = usb_to_uhci(uhci->bus->root_hub);
-	struct uhci_td *td = uhci_td_allocate(dev);
+	struct uhci_td *td = uhci_td_alloc(dev);
 
-	td->link = 1;
-	td->status = (1 << 24);					/* interrupt on completion */
+	if (!td) {
+		printk(KERN_ERR "unable to allocate ticktd\n");
+		return;
+	}
+
+	/* Don't clobber the frame */
+	td->link = uhci->fl->frame[0];
+	td->status = TD_CTRL_IOC;
 	td->info = (15 << 21) | 0x7f69;				/* (ignored) input packet, 16 bytes, device 127 */
 	td->buffer = 0;
-	td->first = td;
 	td->qh = NULL;
 
 	uhci->fl->frame[0] = virt_to_bus(td);
+
+	uhci->ticktd = td;
 }
 
 static void reset_hc(struct uhci *uhci)
@@ -1410,9 +1447,9 @@
 	unsigned int io_addr = uhci->io_addr;
 
 	/* Global reset for 50ms */
-	outw(USBCMD_GRESET, io_addr+USBCMD);
+	outw(USBCMD_GRESET, io_addr + USBCMD);
 	wait_ms(50);
-	outw(0, io_addr+USBCMD);
+	outw(0, io_addr + USBCMD);
 	wait_ms(10);
 }
 
@@ -1432,13 +1469,15 @@
 	outw(USBCMD_HCRESET, io_addr + USBCMD);
 	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
 		if (!--timeout) {
-			printk("USBCMD_HCRESET timed out!\n");
+			printk(KERN_ERR "USBCMD_HCRESET timed out!\n");
 			break;
 		}
 	}
 
-
+	/* Turn on all interrupts */
 	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+
+	/* Start at frame 0 */
 	outw(0, io_addr + USBFRNUM);
 	outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
 
@@ -1463,6 +1502,9 @@
  * We could certainly have multiple queues of the same
  * type, and maybe we should. We could have per-device
  * queues, for example. We begin small.
+ *
+ * Queues are dynamically allocated for devices now,
+ * this code only sets up the skeleton queue
  */
 static struct uhci *alloc_uhci(unsigned int io_addr)
 {
@@ -1487,33 +1529,27 @@
 	if (!uhci->fl)
 		goto au_free_uhci;
 
-	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	bus = usb_alloc_bus(&uhci_device_operations);
 	if (!bus)
 		goto au_free_fl;
 
-	memset(bus, 0, sizeof(*bus));
-
 	uhci->bus = bus;
 	bus->hcpriv = uhci;
-	bus->op = &uhci_device_operations;
 
 	/*
-	 * We allocate a 8kB area for the UHCI hub. The area
-	 * is described by the uhci_device structure, and basically
-	 * contains everything needed for normal operation.
-	 *
-	 * The first page is the actual device descriptor for the
-	 * hub.
-	 *
-	 * The second page is used for the frame list.
+ 	 * Allocate the root_hub
 	 */
-	usb = uhci_usb_allocate(NULL);
+	usb = uhci_usb_alloc(NULL);
 	if (!usb)
 		goto au_free_bus;
 
 	usb->bus = bus;
+
 	dev = usb_to_uhci(usb);
-	uhci->bus->root_hub=uhci_to_usb(dev);
+	dev->uhci = uhci;
+
+	uhci->bus->root_hub = uhci_to_usb(dev);
+
 	/* Initialize the root hub */
 	/* UHCI specs says devices must have 2 ports, but goes on to say */
 	/* they may have more but give no way to determine how many they */
@@ -1521,29 +1557,20 @@
 	usb->maxchild = 2;
 	usb_init_root_hub(usb);
 
-	/*
-	 * Initialize the queues. They all start out empty,
-	 * linked to each other in the proper order.
-	 */
-	for (i = 1 ; i < 9; i++) {
-		dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh);
-		dev->qh[i].element = 1;
-	}
-	
-	dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh);
-	dev->skel_control_qh.element = 1;
-
-	dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh);
-	dev->skel_bulk0_qh.element = 1;
+	/* 8 Interrupt queues */
+	for (i = 0; i < 8; i++) {
+		struct uhci_qh *qh = &uhci->skelqh[i];
 
-	dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh);
-	dev->skel_bulk1_qh.element = 1;
+		qh->link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH;
+		qh->element = UHCI_PTR_TERM;
+	}
 
-	dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh);
-	dev->skel_bulk2_qh.element = 1;
+	uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) |
+		UHCI_PTR_QH;
+	uhci->skel_control_qh.element = UHCI_PTR_TERM;
 
-	dev->skel_bulk3_qh.link = 1;
-	dev->skel_bulk3_qh.element = 1;
+	uhci->skel_bulk_qh.link = UHCI_PTR_TERM;
+	uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
 
 	/*
 	 * Fill the frame list: make all entries point to
@@ -1554,7 +1581,7 @@
 	 * us a reasonable dynamic range for irq latencies.
 	 */
 	for (i = 0; i < 1024; i++) {
-		struct uhci_qh * irq = &dev->skel_int2_qh;
+		struct uhci_qh *irq = &uhci->skel_int2_qh;
 		if (i & 1) {
 			irq++;
 			if (i & 2) {
@@ -1576,7 +1603,7 @@
 				}
 			}
 		}
-		uhci->fl->frame[i] =  2 | virt_to_bus(irq);
+		uhci->fl->frame[i] =  virt_to_bus(irq) | UHCI_PTR_QH;
 	}
 
 	return uhci;
@@ -1586,15 +1613,14 @@
  */
 
 au_free_bus:
-	kfree (bus);
+	usb_free_bus(bus);
 au_free_fl:
-	free_page ((unsigned long)uhci->fl);
+	free_page((unsigned long)uhci->fl);
 au_free_uhci:
-	kfree (uhci);
+	kfree(uhci);
 	return NULL;
 }
 
-
 /*
  * De-allocate all resources..
  */
@@ -1605,51 +1631,44 @@
 		uhci->irq = -1;
 	}
 
-#if 0
-	if (uhci->bus->root_hub) {
-		uhci_usb_deallocate(uhci_to_usb(uhci->bus->root_hub));
-		uhci->bus->root_hub = NULL;
+	if (uhci->ticktd) {
+		uhci_td_free(uhci->ticktd);
+		uhci->ticktd = NULL;
 	}
-#endif
 
 	if (uhci->fl) {
 		free_page((unsigned long)uhci->fl);
 		uhci->fl = NULL;
 	}
 
-	kfree(uhci->bus);
+	usb_free_bus(uhci->bus);
 	kfree(uhci);
 }
 
 static int uhci_control_thread(void * __uhci)
 {
 	struct uhci *uhci = (struct uhci *)__uhci;
-	struct uhci_device * root_hub =usb_to_uhci(uhci->bus->root_hub);
+
+	uhci->control_running = 1;
 
 	lock_kernel();
-	request_region(uhci->io_addr, 32, "usb-uhci");
 
 	/*
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all our resources..
 	 */
-	printk("uhci_control_thread at %p\n", &uhci_control_thread);
 	exit_mm(current);
 	exit_files(current);
-	//exit_fs(current);
 
 	strcpy(current->comm, "uhci-control");
 
 	/*
 	 * Ok, all systems are go..
 	 */
-	start_hc(uhci);
-	usb_register_bus(uhci->bus);
-	for(;;) {
+	do {
 		siginfo_t info;
 		int unsigned long signr;
 
-		interruptible_sleep_on(&uhci_configure);
 #ifdef CONFIG_APM
 		if (apm_resume) {
 			apm_resume = 0;
@@ -1659,40 +1678,31 @@
 #endif
 		uhci_check_configuration(uhci);
 
-		if(signal_pending(current)) {
+		interruptible_sleep_on(&uhci_configure);
+
+		if (signal_pending(current)) {
 			/* sending SIGUSR1 makes us print out some info */
 			spin_lock_irq(&current->sigmask_lock);
 			signr = dequeue_signal(&current->blocked, &info);
 			spin_unlock_irq(&current->sigmask_lock);
 
-			if(signr == SIGUSR1) {
-				printk("UHCI queue dump:\n");
+			if (signr == SIGUSR1) {
+				printk(KERN_DEBUG "UHCI queue dump:\n");
 				show_queues(uhci);
 			} else if (signr == SIGUSR2) {
 				uhci_debug = !uhci_debug;
-				printk("UHCI debug toggle = %x\n", uhci_debug);
-			} else {
+				printk(KERN_DEBUG "UHCI debug toggle = %x\n",
+					uhci_debug);
+			} else
 				break;
-			}
 		}
-	}
+	} while (uhci->control_continue);
 
-	{
-	int i;
-	if(root_hub)
-		for(i = 0; i < root_hub->usb->maxchild; i++)
-			usb_disconnect(root_hub->usb->children + i);
-	}
-
-	usb_deregister_bus(uhci->bus);
-
-	reset_hc(uhci);
-	release_region(uhci->io_addr, 32);
-
-	release_uhci(uhci);
+/*
 	MOD_DEC_USE_COUNT;
+*/
 
-	printk("uhci_control_thread exiting\n");
+	uhci->control_running = 0;
 
 	return 0;
 }	
@@ -1710,21 +1720,37 @@
 	if (!uhci)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&uhci->uhci_list);
+	list_add(&uhci->uhci_list, &uhci_list);
+
+	request_region(uhci->io_addr, 32, "usb-uhci");
+
 	reset_hc(uhci);
 
+	usb_register_bus(uhci->bus);
+	start_hc(uhci);
+
+	uhci->control_continue = 1;
+
 	retval = -EBUSY;
-	if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) {
+	if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "uhci", uhci) == 0) {
 		int pid;
-		MOD_INC_USE_COUNT;
+
 		uhci->irq = irq;
 		pid = kernel_thread(uhci_control_thread, uhci,
 			CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-		if (pid >= 0)
-			return 0;
+		if (pid >= 0) {
+			uhci->control_pid = pid;
+
+			return(pid);
+		}
 
-		MOD_DEC_USE_COUNT;
 		retval = pid;
 	}
+
+	reset_hc(uhci);
+	release_region(uhci->io_addr, 32);
+
 	release_uhci(uhci);
 	return retval;
 }
@@ -1735,17 +1761,17 @@
 
 	/* Search for the IO base address.. */
 	for (i = 0; i < 6; i++) {
-		unsigned int io_addr = dev->base_address[i];
+		unsigned int io_addr = dev->resource[i].start;
 
 		/* IO address? */
-		if (!(io_addr & 1))
+		if (!(dev->resource[i].flags & 1))
 			continue;
 
-		io_addr &= PCI_BASE_ADDRESS_IO_MASK;
-
+#if 0
 		/* Is it already in use? */
 		if (check_region(io_addr, 32))
 			break;
+#endif
 
 		return found_uhci(dev->irq, io_addr);
 	}
@@ -1783,16 +1809,44 @@
 }
 #endif
 
-
 int uhci_init(void)
 {
 	int retval;
 	struct pci_dev *dev = NULL;
 	u8 type;
+	char *name;
+
+	/* FIXME: This is lame, but I guess it's better to leak memory than */
+	/* crash */
+	name = kmalloc(10, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	strcpy(name, "uhci_td");
+
+	uhci_td_cachep = kmem_cache_create(name,
+		sizeof(struct uhci_td), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!uhci_td_cachep)
+		return -ENOMEM;
+
+	name = kmalloc(10, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	strcpy(name, "uhci_qh");
+
+	uhci_qh_cachep = kmem_cache_create(name,
+		sizeof(struct uhci_qh), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!uhci_qh_cachep)
+		return -ENOMEM;
 
 	retval = -ENODEV;
 	for (;;) {
-		dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev);
+		dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
 		if (!dev)
 			break;
 		/* Is it UHCI */
@@ -1812,6 +1866,59 @@
 	return retval;
 }
 
+void uhci_cleanup(void)
+{
+	struct list_head *next, *tmp, *head = &uhci_list;
+	int ret, i;
+
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
+		struct uhci_device *root_hub = usb_to_uhci(uhci->bus->root_hub);
+
+		next = tmp->next;
+
+		list_del(&uhci->uhci_list);
+		INIT_LIST_HEAD(&uhci->uhci_list);
+
+		/* Check if the process is still running */
+		ret = kill_proc(uhci->control_pid, 0, 1);
+		if (!ret) {
+			int count = 10;
+
+			uhci->control_continue = 0;
+			wake_up(&uhci_configure);
+
+			while (uhci->control_running && --count) {
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(1);
+			}
+
+			if (!count)
+				printk(KERN_ERR "uhci: giving up on killing uhci-control\n");
+		}
+
+		if (root_hub)
+			for (i = 0; i < root_hub->usb->maxchild; i++)
+				usb_disconnect(root_hub->usb->children + i);
+
+		usb_deregister_bus(uhci->bus);
+
+		reset_hc(uhci);
+		release_region(uhci->io_addr, 32);
+
+		release_uhci(uhci);
+
+		tmp = next;
+	}
+
+	if (kmem_cache_destroy(uhci_qh_cachep))
+		printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+	if (kmem_cache_destroy(uhci_td_cachep))
+		printk(KERN_INFO "uhci: not all TD's were freed\n");
+}
+
 #ifdef MODULE
 int init_module(void)
 {
@@ -1823,5 +1930,7 @@
 #ifdef CONFIG_APM
 	apm_unregister_callback(&handle_apm_event);
 #endif
+	uhci_cleanup();
 }
 #endif //MODULE
+
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.12/linux/drivers/usb/uhci.h	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/uhci.h	Sat Aug  7 13:01:44 1999
@@ -55,17 +55,44 @@
 
 #define UHCI_NULL_DATA_SIZE	0x7ff	/* for UHCI controller TD */
 
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
 struct uhci_qh {
-	unsigned int link;	/* Next queue */
-	unsigned int element;	/* Queue element pointer */
-	int inuse;		/* Inuse? */
-	struct uhci_qh *skel;	/* Skeleton head */
+	/* Hardware fields */
+	__u32 link;				/* Next queue */
+	__u32 element;				/* Queue element pointer */
+
+	/* Software fields */
+	atomic_t refcnt;			/* Reference counting */
+	struct uhci_device *dev;		/* The owning device */
+	struct uhci_qh *skel;			/* Skeleton head */
+
+	wait_queue_head_t wakeup;
 } __attribute__((aligned(16)));
 
 struct uhci_framelist {
-	unsigned int frame[1024];
+	__u32 frame[1024];
 } __attribute__((aligned(4096)));
 
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIME		(1 << 18)	/* CTC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+
+#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
+
+#define UHCI_TD_REMOVE		0x0001		/* Remove when done */
+
 /*
  * The documentation says "4 words for hardware, 4 words for software".
  *
@@ -77,7 +104,7 @@
  * On 64-bit machines we probably want to take advantage of the fact that
  * hw doesn't really care about the size of the sw-only area.
  *
- * Alas, not anymore, we have more than 4 words of software, woops
+ * Alas, not anymore, we have more than 4 words for software, woops
  */
 struct uhci_td {
 	/* Hardware fields */
@@ -87,25 +114,27 @@
 	__u32 buffer;
 
 	/* Software fields */
+	unsigned int *backptr;		/* Where to remove this from.. */
 	struct list_head irq_list;	/* Active interrupt list.. */
+
 	usb_device_irq completed;	/* Completion handler routine */
-	unsigned int *backptr;		/* Where to remove this from.. */
 	void *dev_id;
-	int inuse;			/* Inuse? (b0) Remove (b1)*/
-	struct uhci_qh *qh;
-	struct uhci_td *first;
-	struct usb_device *dev;		/* the owning device */
-} __attribute__((aligned(32)));
+
+	atomic_t refcnt;		/* Reference counting */
+	struct uhci_device *dev;	/* The owning device */
+	struct uhci_qh *qh;		/* QH this TD is a part of (ignored for Isochronous) */
+	int flags;			/* Remove, etc */
+} __attribute__((aligned(16)));
 
 struct uhci_iso_td {
-	int num;
-	char *data;
-	int maxsze;
+	int num;			/* Total number of TD's */
+	char *data;			/* Beginning of buffer */
+	int maxsze;			/* Maximum size of each data block */
 
-	struct uhci_td *td;
+	struct uhci_td *td;		/* Pointer to first TD */
 
-	int frame;
-	int endframe;
+	int frame;			/* Beginning frame */
+	int endframe;			/* End frame */
 };
 
 /*
@@ -117,17 +146,21 @@
  */
 struct uhci;
 
+#if 0
 #define UHCI_MAXTD	64
 
 #define UHCI_MAXQH	16
+#endif
 
 /* The usb device part must be first! */
 struct uhci_device {
 	struct usb_device	*usb;
 
 	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];
 };
@@ -136,16 +169,6 @@
 #define usb_to_uhci(usb)	((struct uhci_device *)(usb)->hcpriv)
 
 /*
- * The root hub pre-allocated QH's and TD's have
- * some special global uses..
- */
-#if 0
-#define control_td	td		/* Td's 0-30 */
-/* This is only for the root hub's TD list */
-#define tick_td		td[31]
-#endif
-
-/*
  * There are various standard queues. We set up several different
  * queues for each of the three basic queue types: interrupt,
  * control, and bulk.
@@ -180,37 +203,25 @@
  * transfers in QH's and all of their pictures don't have that either) but
  * other than that, that is what we're doing now
  *
- * To keep with Linus' nomenclature, this is called the qh skeleton. These
- * labels (below) are only signficant to the root hub's qh's
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
  */
-#define skel_iso_qh		qh[0]
+#define UHCI_NUM_SKELQH		10
 
-#define skel_int2_qh		qh[1]
-#define skel_int4_qh		qh[2]
-#define skel_int8_qh		qh[3]
-#define skel_int16_qh		qh[4]
-#define skel_int32_qh		qh[5]
-#define skel_int64_qh		qh[6]
-#define skel_int128_qh		qh[7]
-#define skel_int256_qh		qh[8]
-
-#define skel_control_qh		qh[9]
-
-#define skel_bulk0_qh		qh[10]
-#define skel_bulk1_qh		qh[11]
-#define skel_bulk2_qh		qh[12]
-#define skel_bulk3_qh		qh[13]
+#define skel_int2_qh		skelqh[0]
+#define skel_int4_qh		skelqh[1]
+#define skel_int8_qh		skelqh[2]
+#define skel_int16_qh		skelqh[3]
+#define skel_int32_qh		skelqh[4]
+#define skel_int64_qh		skelqh[5]
+#define skel_int128_qh		skelqh[6]
+#define skel_int256_qh		skelqh[7]
 
-/*
- * These are significant to the devices allocation of QH's
- */
-#if 0
-#define iso_qh			qh[0]
-#define int_qh			qh[1]	/* We have 2 "common" interrupt QH's */
-#define control_qh		qh[3]
-#define bulk_qh			qh[4]	/* We have 4 "common" bulk QH's */
-#define extra_qh		qh[8]	/* The rest, anything goes */
-#endif
+#define skel_control_qh		skelqh[8]
+
+#define skel_bulk_qh		skelqh[9]
 
 /*
  * This describes the full uhci information.
@@ -222,14 +233,20 @@
 	int irq;
 	unsigned int io_addr;
 
+	int control_pid;
+	int control_running;
+	int control_continue;
+
+	struct list_head uhci_list;
+
 	struct usb_bus *bus;
 
-#if 0
-	/* These are "standard" QH's for the entire bus */
-	struct uhci_qh qh[UHCI_MAXQH];
-#endif
+	struct uhci_qh skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
+
 	struct uhci_framelist *fl;		/* Frame list */
 	struct list_head interrupt_list;	/* List of interrupt-active TD's for this uhci */
+
+	struct uhci_td *ticktd;
 };
 
 /* needed for the debugging code */
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.12/linux/drivers/usb/usb.c	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/usb.c	Mon Aug  9 11:27:39 1999
@@ -51,40 +51,49 @@
 
 int usb_register(struct usb_driver *new_driver)
 {
-	struct list_head *tmp = usb_bus_list.next;
+	struct list_head *tmp;
+
+	printk("usbcore: Registering new driver %s\n", new_driver->name);
+
 	/* Add it to the list of known drivers */
 	list_add(&new_driver->driver_list, &usb_driver_list);
 
 	/*
-         * We go through all existing devices, and see if any of them would
-         * be acceptable to the new driver.. This is done using a depth-first
-         * search for devices without a registered driver already, then 
+	 * We go through all existing devices, and see if any of them would
+	 * be acceptable to the new driver.. This is done using a depth-first
+	 * search for devices without a registered driver already, then 
 	 * running 'probe' with each of the drivers registered on every one 
 	 * of these.
 	 */
-        while (tmp!= &usb_bus_list) {
-		struct usb_bus * bus = list_entry(tmp,struct
-			usb_bus,bus_list);
-	        tmp=tmp->next;  
+	tmp = usb_bus_list.next;
+	while (tmp != &usb_bus_list) {
+		struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
+
+	        tmp = tmp->next;
 		usb_check_support(bus->root_hub);
-        }
+	}
 	return 0;
 }
 
 void usb_deregister(struct usb_driver *driver)
 {
-      struct list_head *tmp = usb_bus_list.next;
-      /*first we remove the driver, to be sure it doesn't get used by
-       *another thread while we are stepping through removing entries
-       */
+	struct list_head *tmp;
+
+	printk("usbcore: Deregistering driver %s\n", driver->name);
+
+	/*
+	 * first we remove the driver, to be sure it doesn't get used by
+	 * another thread while we are stepping through removing entries
+	 */
 	list_del(&driver->driver_list);
-      printk("usbcore: deregistering driver\n");
-      while (tmp!= &usb_bus_list) {
-              struct usb_bus * bus = list_entry(tmp,struct 
-            		usb_bus,bus_list);
-              tmp=tmp->next;
-              usb_driver_purge(driver,bus->root_hub);
-      }
+
+	tmp = usb_bus_list.next;
+	while (tmp != &usb_bus_list) {
+		struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
+
+		tmp = tmp->next;
+		usb_driver_purge(driver, bus->root_hub);
+	}
 }
 
 /* This function is part of a depth-first search down the device tree,
@@ -93,45 +102,82 @@
 void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev)
 {
        int i;
-       if (dev==NULL){
-               printk("null device being passed in!!!\n");
-               return;
-       }
-       for (i=0;i<USB_MAXCHILDREN;i++)
-               if (dev->children[i]!=NULL)
-                       usb_driver_purge(driver,dev->children[i]);
-       /*now we check this device*/
-       if(dev->driver==driver) {
-               /*
-                * Note: this is not the correct way to do this, this
-                * uninitializes and reinitializes EVERY driver
-                */
-               printk("disconnecting driverless device\n");
-               dev->driver->disconnect(dev);
-               dev->driver=NULL;
-               /* This will go back through the list looking for a driver
-                * that can handle the device
-		*/
-               usb_device_descriptor(dev);
-      }
+
+	if (!dev) {
+		printk(KERN_ERR "usbcore: null device being purged!!!\n");
+		return;
+	}
+
+	for (i=0; i<USB_MAXCHILDREN; i++)
+		if (dev->children[i])
+			usb_driver_purge(driver, dev->children[i]);
+
+	/* now we check this device */
+	if (dev->driver == driver) {
+		/*
+		 * Note: this is not the correct way to do this, this
+		 * uninitializes and reinitializes EVERY driver
+		 */
+		printk(KERN_INFO "disconnect driverless device %d\n",
+			dev->devnum);
+		dev->driver->disconnect(dev);
+		dev->driver = NULL;
+
+		/*
+		 * This will go back through the list looking for a driver
+		 * that can handle the device
+		 */
+		usb_find_driver(dev);
+	}
 }
 
 /*
  * New functions for (de)registering a controller
  */
+struct usb_bus *usb_alloc_bus(struct usb_operations *op)
+{
+	struct usb_bus *bus;
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	memset(&bus->devmap, 0, sizeof(struct usb_devmap));
+
+	bus->op = op;
+	bus->root_hub = NULL;
+	bus->hcpriv = NULL;
+
+	INIT_LIST_HEAD(&bus->bus_list);
+
+	return bus;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+	if (!bus)
+		return;
+
+	if (bus->bus_list.next != &bus->bus_list)
+		printk(KERN_ERR "usbcore: freeing non-empty bus\n");
+
+	kfree(bus);
+}
+
 void usb_register_bus(struct usb_bus *new_bus)
 {
-      /* Add it to the list of buses */
-      list_add(&new_bus->bus_list, &usb_bus_list);
-      printk("New bus registered\n");
+	/* Add it to the list of buses */
+	list_add(&new_bus->bus_list, &usb_bus_list);
+	printk("New USB bus registered\n");
 }
 
 void usb_deregister_bus(struct usb_bus *bus)
 {
-        /* NOTE: make sure that all the devices are removed by the
-         * controller code, as well as having it call this when cleaning
+	/*
+	 * NOTE: make sure that all the devices are removed by the
+	 * controller code, as well as having it call this when cleaning
 	 * itself up
-         */
+	 */
 	list_del(&bus->bus_list);
 }
 
@@ -141,18 +187,20 @@
  */
 void usb_check_support(struct usb_device *dev)
 {
-      int i;
-      if (dev==NULL)
-      {
-              printk("null device being passed in!!!\n");
-              return;
-      }
-      for (i=0;i<USB_MAXCHILDREN;i++)
-              if (dev->children[i]!=NULL)
-                      usb_check_support(dev->children[i]);
-      /*now we check this device*/
-      if (dev->driver==NULL)
-	      usb_device_descriptor(dev);
+	int i;
+
+	if (!dev) {
+		printk(KERN_ERR "usbcore: null device being checked!!!\n");
+		return;
+	}
+
+	for (i=0; i<USB_MAXCHILDREN; i++)
+		if (dev->children[i])
+			usb_check_support(dev->children[i]);
+
+	/* now we check this device */
+	if (!dev->driver && dev->devnum > 0)
+		usb_find_driver(dev);
 }
 /*
  * This entrypoint gets called for each new device.
@@ -161,7 +209,7 @@
  * looking for one that will accept this device as
  * his..
  */
-int usb_device_descriptor(struct usb_device *dev)
+int usb_find_driver(struct usb_device *dev)
 {
 	struct list_head *tmp = usb_driver_list.next;
 
@@ -174,6 +222,7 @@
 		dev->driver = driver;
 		return 1;
 	}
+
 	/*
 	 * Ok, no driver accepted the device, so show the info
 	 * for debugging..
@@ -243,8 +292,7 @@
 	if (len <= 0)
 		return -1;
 
-	if (n_len < 2 || n_len > len)
-	{
+	if (n_len < 2 || n_len > len) {
 		int i;
 		printk("Short descriptor. (%d, %d):\n", len, n_len);
 		for (i = 0; i < len; ++i)
@@ -272,8 +320,7 @@
 	parsed += ptr[parsed];
 	len -= parsed;
 
-	while((i = usb_check_descriptor(ptr+parsed, len, 0x25))>=0)
-	{
+	while((i = usb_check_descriptor(ptr+parsed, len, 0x25)) >= 0) {
 		usb_audio_endpoint(endpoint, ptr+parsed+i);
 		len -= ptr[parsed+i];
 		parsed += ptr[parsed+i];
@@ -295,23 +342,20 @@
 	len -= ptr[parsed];
 	parsed += ptr[parsed];
 
-	while((i=usb_check_descriptor(ptr+parsed, len, 0x24))>=0)
-	{
+	while((i=usb_check_descriptor(ptr+parsed, len, 0x24)) >= 0) {
 		usb_audio_interface(interface, ptr+parsed+i);
 		len -= ptr[parsed+i];
 		parsed += ptr[parsed+i];
 	}
 	
-	if (interface->bNumEndpoints > USB_MAXENDPOINTS)
-	{
+	if (interface->bNumEndpoints > USB_MAXENDPOINTS) {
 		printk(KERN_WARNING "usb: too many endpoints.\n");
 		return -1;
 	}
 
 	interface->endpoint = (struct usb_endpoint_descriptor *)
 		kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
-	if(interface->endpoint==NULL)
-	{
+	if (!interface->endpoint) {
 		printk(KERN_WARNING "usb: out of memory.\n");
 		return -1;	
 	}
@@ -323,7 +367,8 @@
 //			len -= 9;
 //		}
 		retval = usb_parse_endpoint(dev, interface->endpoint + i, ptr + parsed, len);
-		if (retval < 0) return retval;
+		if (retval < 0)
+			return retval;
 		parsed += retval;
 		len -= retval;
 	}
@@ -345,13 +390,7 @@
 	parsed += *ptr;
 	le16_to_cpus(&config->wTotalLength);
 
-	if (config->MaxPower == 200) {
-		printk("bNumInterfaces kludge\n");
-		config->bNumInterfaces += 3;
-	}
-
-	if (config->bNumInterfaces > USB_MAXINTERFACES)
-	{
+	if (config->bNumInterfaces > USB_MAXINTERFACES) {
 		printk(KERN_WARNING "usb: too many interfaces.\n");
 		return -1;
 
@@ -359,17 +398,16 @@
 
 	config->altsetting = (struct usb_alternate_setting *)
 	        kmalloc(USB_MAXALTSETTING * sizeof(struct usb_alternate_setting), GFP_KERNEL);
-	if (config->altsetting == NULL) {
-	  printk(KERN_WARNING "usb: out of memory.\n");
-	  return -1;
+	if (!config->altsetting) {
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;
 	}
 	config->act_altsetting = 0;
 	config->num_altsetting = 1;
 
 	config->altsetting->interface = (struct usb_interface_descriptor *)
 		kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
-	if(config->altsetting->interface==NULL)
-	{
+	if (!config->altsetting->interface) {
 		printk(KERN_WARNING "usb: out of memory.\n");
 		return -1;	
 	}
@@ -389,26 +427,26 @@
 
 	// now parse for additional alternate settings
 	for (j = 1; j < USB_MAXALTSETTING; j++) {
-	  retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9);
-	  if (retval) 
-	    break;
-	  config->num_altsetting++;
-	  as = config->altsetting + j;
-	  as->interface = (struct usb_interface_descriptor *)
-	    kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
-	  if (as->interface == NULL) {
-	    printk(KERN_WARNING "usb: out of memory.\n");
-	    return -1;
-	  }
-	  memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor));
-	  for (i = 0; i < config->bNumInterfaces; i++) {
-	    retval = usb_parse_interface(dev, as->interface + i, 
+		retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9);
+		if (retval) 
+			break;
+		config->num_altsetting++;
+		as = config->altsetting + j;
+		as->interface = (struct usb_interface_descriptor *)
+			kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
+		if (!as->interface) {
+			printk(KERN_WARNING "usb: out of memory.\n");
+			return -1;
+		}
+		memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor));
+		for (i = 0; i < config->bNumInterfaces; i++) {
+			retval = usb_parse_interface(dev, as->interface + i, 
 					 ptr + parsed, len);
-	    if (retval < 0)
-	      return parsed;
-	    parsed += retval;
-	    len -= retval;
-	  }
+			if (retval < 0)
+				return parsed;
+			parsed += retval;
+			len -= retval;
+		}
 	}
 	return parsed;
 }
@@ -418,16 +456,14 @@
 	int i;
 	unsigned char *ptr = __buf;
 
-	if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
-	{
+	if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
 		printk(KERN_WARNING "usb: too many configurations.\n");
 		return -1;
 	}
 
 	dev->config = (struct usb_config_descriptor *)
 		kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL);
-	if(dev->config==NULL)
-	{
+	if (!dev->config) {
 		printk(KERN_WARNING "usb: out of memory.\n");
 		return -1;	
 	}
@@ -451,21 +487,18 @@
 	struct usb_alternate_setting *as;
 	struct usb_interface_descriptor *ifp;
 	
-	if(dev->config==NULL)
+	if (!dev->config)
 		return;
 
-	for(c = 0; c < dev->descriptor.bNumConfigurations; c++)
-	{
+	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
 		cf = &dev->config[c];
-		if (cf->altsetting == NULL)
+		if (!cf->altsetting)
 		        break;
-		for (a = 0; a < cf->num_altsetting; a++)
-		{
+		for (a = 0; a < cf->num_altsetting; a++) {
 		        as = &cf->altsetting[a];
 			if (as->interface == NULL)
 			        break;
-			for(i=0;i<cf->bNumInterfaces;i++)
-			{
+			for(i=0;i<cf->bNumInterfaces;i++) {
 			        ifp = &as->interface[i];
 				if(ifp->endpoint==NULL)
 				       break;
@@ -609,45 +642,6 @@
 	return ret;
 }
 
-int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
-{
-	devrequest dr;
-
-	dr.requesttype = USB_RT_HUB | 0x80;
-	dr.request = USB_REQ_GET_DESCRIPTOR;
-	dr.value = (USB_DT_HUB << 8);
-	dr.index = 0;
-	dr.length = size;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size);
-}
-
-int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
-{
-	devrequest dr;
-
-	dr.requesttype = USB_RT_PORT;
-	dr.request = USB_REQ_CLEAR_FEATURE;
-	dr.value = feature;
-	dr.index = port;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
-}
-
-int usb_set_port_feature(struct usb_device *dev, int port, int feature)
-{
-	devrequest dr;
-
-	dr.requesttype = USB_RT_PORT;
-	dr.request = USB_REQ_SET_FEATURE;
-	dr.value = feature;
-	dr.index = port;
-	dr.length = 0;
-
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
-}
-
 int usb_get_status (struct usb_device *dev, int type, int target, void *data)
 {
 	devrequest dr;
@@ -661,32 +655,6 @@
 	return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2);
 }
 
-int usb_get_hub_status(struct usb_device *dev, void *data)
-{
-	devrequest dr;
-
-	dr.requesttype = USB_RT_HUB | 0x80;
-	dr.request = USB_REQ_GET_STATUS;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 4;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
-}
-
-int usb_get_port_status(struct usb_device *dev, int port, void *data)
-{
-	devrequest dr;
-
-	dr.requesttype = USB_RT_PORT | 0x80;
-	dr.request = USB_REQ_GET_STATUS;
-	dr.value = 0;
-	dr.index = port;
-	dr.length = 4;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
-}
-
 int usb_get_protocol(struct usb_device *dev)
 {
 	unsigned char buf[8];
@@ -741,21 +709,19 @@
 static void usb_set_maxpacket(struct usb_device *dev)
 {
 	int i;
-	struct usb_endpoint_descriptor *ep;
 	int act_as = dev->actconfig->act_altsetting;
 	struct usb_alternate_setting *as = dev->actconfig->altsetting + act_as;
-	struct usb_interface_descriptor *ip = as->interface;
 
 	for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
-		if (as->interface[i].bInterfaceNumber == dev->ifnum) {
-			ip = &as->interface[i];
-			break;
+		struct usb_interface_descriptor *ip = &as->interface[i];
+		struct usb_endpoint_descriptor *ep = ip->endpoint;
+		int e;
+
+		for (e=0; e<ip->bNumEndpoints; e++) {
+			dev->epmaxpacket[ep[e].bEndpointAddress & 0x0f] =
+				ep[e].wMaxPacketSize;
 		}
 	}
-	ep = ip->endpoint;
-	for (i=0; i<ip->bNumEndpoints; i++) {
-		dev->epmaxpacket[ep[i].bEndpointAddress & 0x0f] = ep[i].wMaxPacketSize;
-	}
 }
 
 int usb_clear_halt(struct usb_device *dev, int endp)
@@ -776,9 +742,8 @@
 	result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
 
 	/* dont clear if failed */
-	if (result) {
+	if (result)
 	    return result;
-	}
 
 #if 1	/* lets be really tough */
 	dr.requesttype = 0x80 | USB_RT_ENDPOINT;
@@ -788,12 +753,10 @@
 
 	result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2);
 
-	if (result) {
+	if (result)
 	    return result;
-	}
-	if (status & 1) {
+	if (status & 1)
 	    return 1;		/* still halted */
-	}
 #endif
 	usb_endpoint_running(dev, endp & 0x0f);
 
@@ -1014,37 +977,27 @@
  * and is in the default state. We need to identify the thing and
  * get the ball rolling..
  */
-void usb_new_device(struct usb_device *dev)
+int usb_new_device(struct usb_device *dev)
 {
-	int addr, i;
+	int addr;
 
-	printk("USB new device connect, assigned device number %d\n",
+	printk(KERN_INFO "USB new device connect, assigned device number %d\n",
 		dev->devnum);
 
 	dev->maxpacketsize = 0;		/* Default to 8 byte max packet size */
         dev->epmaxpacket[0] = 8;
 
+	/* We still haven't set the Address yet */
 	addr = dev->devnum;
 	dev->devnum = 0;
 
-#if 1
 	/* Slow devices */
-	for (i = 0; i < 5; i++) {
-		if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
-			break;
-
-		printk("get_descriptor failed, waiting\n");
-		wait_ms(200);
-	}
-	if (i == 5) {
-		printk("giving up\n");
-		return;
+	if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) {
+		printk(KERN_ERR "USB device not responding, giving up\n");
+		dev->devnum = -1;
+		return 1;
 	}
-#endif
 
-#if 0
-	printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
-#endif
 	dev->epmaxpacket[0] = dev->descriptor.bMaxPacketSize0;
 	switch (dev->descriptor.bMaxPacketSize0) {
 		case 8: dev->maxpacketsize = 0; break;
@@ -1052,36 +1005,29 @@
 		case 32: dev->maxpacketsize = 2; break;
 		case 64: dev->maxpacketsize = 3; break;
 	}
-#if 0
-	printk("dev->mps: %d\n", dev->maxpacketsize);
-#endif
 
 	dev->devnum = addr;
 
-#if 1
 	if (usb_set_address(dev)) {
-		printk("Unable to set address\n");
-		/* FIXME: We should disable the port */
-		return;
+		printk(KERN_ERR "USB device not accepting new address\n");
+		dev->devnum = -1;
+		return 1;
 	}
-#else
-	usb_set_address(dev);
-#endif
 
 	wait_ms(10);	/* Let the SET_ADDRESS settle */
 
 	if (usb_get_device_descriptor(dev)) {
-		printk("Unable to get device descriptor\n");
-		return;
+		printk(KERN_ERR "Unable to get device descriptor\n");
+		dev->devnum = -1;
+		return 1;
 	}
 
 	if (usb_get_configuration(dev)) {
-		printk("Unable to get configuration\n");
-		return;
+		printk(KERN_ERR "Unable to get configuration\n");
+		dev->devnum = -1;
+		return 1;
 	}
 
-	/* usb_get_stringtable(dev); */
-
 	dev->actconfig = dev->config;
 	dev->ifnum = 0;
 	usb_set_maxpacket(dev);
@@ -1090,20 +1036,16 @@
 	usb_show_string(dev, "Product", dev->descriptor.iProduct);
 	usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
 
-#if 0
-	printk("Vendor: %X\n", dev->descriptor.idVendor);
-	printk("Product: %X\n", dev->descriptor.idProduct);
-#endif
-
-	if (usb_device_descriptor(dev)==0)
-	{
+	if (!usb_find_driver(dev)) {
 		/*
 		 * Ok, no driver accepted the device, so show the info for
 		 * debugging
 		 */
-		printk ("Unknown new USB device:\n");
+		printk(KERN_DEBUG "Unknown new USB device:\n");
 		usb_show_device(dev);
 	}
+
+	return 0;
 }
 
 void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
@@ -1111,6 +1053,15 @@
 	return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
 }
 
+void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
+{
+	return dev->bus->op->request_bulk(dev, pipe, handler, data, len, dev_id);
+}
+
+int usb_terminate_bulk(struct usb_device *dev, void *first)
+{
+	return dev->bus->op->terminate_bulk(dev, first);
+}
 
 void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
 {
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.12/linux/drivers/usb/usb.h	Wed Jul 28 14:47:42 1999
+++ linux/drivers/usb/usb.h	Mon Aug  9 11:27:39 1999
@@ -290,6 +290,9 @@
 	int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
 	void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
 	int (*release_irq)(void* handle);
+	void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq,
+ void *, int, void *);
+	int (*terminate_bulk)(struct usb_device *, void *);
 	void *(*alloc_isoc)(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id);
 	void (*delete_isoc)(struct usb_device *dev, void *_isodesc);
 	int (*sched_isoc)(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
@@ -346,17 +349,22 @@
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
+extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
+extern void usb_free_bus(struct usb_bus *);
 extern void usb_register_bus(struct usb_bus *);
 extern void usb_deregister_bus(struct usb_bus *);
 
 extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
 extern int usb_release_irq(struct usb_device *dev, void *handle);
 
+extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
+extern int usb_terminate_bulk(struct usb_device *, void *);
+
 extern void usb_init_root_hub(struct usb_device *dev);
 extern void usb_connect(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
 
-extern int usb_device_descriptor(struct usb_device *dev);
+extern int usb_find_driver(struct usb_device *dev);
 void usb_check_support(struct usb_device *);
 void usb_driver_purge(struct usb_driver *,struct usb_device *);
 extern int  usb_parse_configuration(struct usb_device *dev, void *buf, int len);
@@ -453,17 +461,12 @@
 /*
  * Send and receive control messages..
  */
-void usb_new_device(struct usb_device *dev);
+int usb_new_device(struct usb_device *dev);
 int usb_set_address(struct usb_device *dev);
 int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned
 char descindex, void *buf, int size);
 int usb_get_device_descriptor(struct usb_device *dev);
-int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size);
-int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
-int usb_set_port_feature(struct usb_device *dev, int port, int feature);
 int usb_get_status (struct usb_device *dev, int type, int target, void *data);
-int usb_get_hub_status(struct usb_device *dev, void *data);
-int usb_get_port_status(struct usb_device *dev, int port, void *data);
 int usb_get_protocol(struct usb_device *dev);
 int usb_set_protocol(struct usb_device *dev, int protocol);
 int usb_set_interface(struct usb_device *dev, int interface, int alternate);
diff -u --recursive --new-file v2.3.12/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c
--- v2.3.12/linux/drivers/usb/uss720.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/uss720.c	Mon Aug  9 12:15:53 1999
@@ -0,0 +1,678 @@
+/*****************************************************************************/
+
+/*
+ *	uss720.c  --  USS720 USB Parport Cable.
+ *
+ *	Copyright (C) 1999
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	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.
+ *
+ *  Based on parport_pc.c
+ *
+ *  History:
+ *   0.1  04.08.99  Created
+ *   0.2  07.08.99  Some fixes mainly suggested by Tim Waugh
+ *                  Interrupt handling currently disabled because
+ *                  usb_request_irq crashes somewhere within ohci.c
+ *                  for no apparent reason (that is for me, anyway)
+ *                  ECP currently untested
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/parport.h>
+#include <linux/init.h>
+
+#include "usb.h"
+
+/* --------------------------------------------------------------------- */
+
+struct parport_uss720_private {
+	struct usb_device *usbdev;
+	void *irqhandle;
+        unsigned char reg[7];  /* USB registers */
+};
+
+/* --------------------------------------------------------------------- */
+
+static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	static const unsigned char regindex[9] = {
+		4, 0, 1, 5, 5, 0, 2, 3, 6
+	};
+        devrequest dr;
+        int ret;
+
+	if (!usbdev)
+		return -1;
+        dr.requesttype = 0xc0;
+        dr.request = 3;
+        dr.value = ((unsigned int)reg) << 8;
+        dr.index = 0;
+        dr.length = 7;
+        ret = usbdev->bus->op->control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), &dr, priv->reg, 7);
+        if (ret) {
+                printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x\n",
+		       (unsigned int)reg, ret);
+        } else {
+#if 0
+                printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n",
+		       (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
+		       (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4],
+		       (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]);
+#endif
+		/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+		if (priv->reg[2] & priv->reg[1] & 0x10)
+			parport_generic_irq(0, pp, NULL);
+	}
+	if (val)
+		*val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
+	return ret;
+}
+
+static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+        devrequest dr;
+        int ret;
+
+	if (!usbdev)
+		return -1;
+        dr.requesttype = 0x40;
+        dr.request = 4;
+        dr.value = (((unsigned int)reg) << 8) | val;
+        dr.index = 0;
+        dr.length = 0;
+        ret = usbdev->bus->op->control_msg(usbdev, usb_sndctrlpipe(usbdev,0), &dr, NULL, 0);
+        if (ret) {
+                printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 
+		       (unsigned int)reg, (unsigned int)val, ret);
+        } else {
+#if 0
+                printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n", 
+		       (unsigned int)reg, (unsigned int)val);
+#endif
+        }
+	return ret;
+}
+
+/* --------------------------------------------------------------------- */
+
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *pp, int m)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	int mode;
+
+	if (get_1284_register(pp, 6, NULL))
+		return -EIO;
+	/* Bits <7:5> contain the mode. */
+	mode = (priv->reg[2] >> 5) & 0x7;
+	if (mode == m)
+		return 0;
+	/* We have to go through mode 000 or 001 */
+	if (mode > ECR_PS2 && m > ECR_PS2)
+		if (change_mode(pp, ECR_PS2))
+			return -EIO;
+
+	if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {
+		/* This mode resets the FIFO, so we may
+		 * have to wait for it to drain first. */
+		long expire = jiffies + pp->physport->cad->timeout;
+		switch (mode) {
+		case ECR_PPF: /* Parallel Port FIFO mode */
+		case ECR_ECP: /* ECP Parallel Port mode */
+			/* Poll slowly. */
+			for (;;) {
+				if (get_1284_register(pp, 6, NULL))
+					return -EIO;
+				if (priv->reg[2] & 0x01)
+					break;
+				if (time_after_eq (jiffies, expire))
+					/* The FIFO is stuck. */
+					return -EBUSY;
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout((HZ + 99) / 100);
+				if (signal_pending (current))
+					break;
+			}
+		}
+	}
+	/* Set the mode. */
+	if (set_1284_register(pp, 6, m << 5))
+		return -EIO;
+	return 0;
+}
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ */
+static int clear_epp_timeout(struct parport *pp)
+{
+	unsigned char stat;
+
+	if (get_1284_register(pp, 1, &stat))
+		return 1;
+	return stat & 1;
+}
+
+/*
+ * Access functions.
+ */
+
+static void parport_uss720_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
+{
+	struct parport *pp = (struct parport *)dev_id;
+	struct parport_uss720_private *priv = pp->private_data;	
+
+	if (usbstatus != USB_ST_NOERROR || len < 4 || !buffer)
+		return 1;
+	memcpy(priv->reg, buffer, 4);
+	/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+	if (priv->reg[2] & priv->reg[1] & 0x10)
+		parport_generic_irq(0, pp, NULL);
+	return 1;
+}
+
+static void parport_uss720_write_data(struct parport *pp, unsigned char d)
+{
+	set_1284_register(pp, 0, d);
+}
+
+static unsigned char parport_uss720_read_data(struct parport *pp)
+{
+	unsigned char ret;
+
+	if (get_1284_register(pp, 0, &ret))
+		return 0;
+	return ret;
+}
+
+static void parport_uss720_write_control(struct parport *pp, unsigned char d)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+
+	d = (d & 0xf) | (priv->reg[1] & 0xf0);
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static unsigned char parport_uss720_read_control(struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	return priv->reg[1] & 0xf; /* Use soft copy */
+}
+
+static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	mask &= 0x0f;
+	val &= 0x0f;
+	d = (priv->reg[1] & (~mask)) ^ val;
+	if (set_1284_register(pp, 2, d))
+		return 0;
+	priv->reg[1] = d;
+	return d & 0xf;
+}
+
+static unsigned char parport_uss720_read_status(struct parport *pp)
+{
+	unsigned char ret;
+
+	if (get_1284_register(pp, 1, &ret))
+		return 0;
+	return ret & 0xf8;
+}
+
+static void parport_uss720_disable_irq(struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] & ~0x10;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_enable_irq(struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] | 0x10;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_data_forward (struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] & ~0x20;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_data_reverse (struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] | 0x20;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s)
+{
+	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+	s->u.pc.ecr = 0x24;
+}
+
+static void parport_uss720_save_state(struct parport *pp, struct parport_state *s)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+
+	if (get_1284_register(pp, 2, NULL))
+		return;
+	s->u.pc.ctr = priv->reg[1];
+	s->u.pc.ecr = priv->reg[2];
+}
+
+static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
+{
+	set_1284_register(pp, 2, s->u.pc.ctr);
+	set_1284_register(pp, 6, s->u.pc.ecr);
+	get_1284_register(pp, 2, NULL);
+}
+
+static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t got = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; got < length; got++) {
+		if (get_1284_register(pp, 4, (char *)buf))
+			break;
+		((char*)buf)++;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return got;
+}
+
+static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags)
+{
+#if 0
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t written = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; written < length; written++) {
+		if (set_1284_register(pp, 4, (char *)buf))
+			break;
+		((char*)buf)++;
+		if (get_1284_register(pp, 1, NULL))
+			break;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return written;
+#else
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	unsigned long rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buf, length, &rlen);
+	if (i)
+		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buf, length, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+#endif
+}
+
+static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t got = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; got < length; got++) {
+		if (get_1284_register(pp, 3, (char *)buf))
+			break;
+		((char*)buf)++;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return got;
+}
+
+static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t written = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; written < length; written++) {
+		if (set_1284_register(pp, 3, *(char *)buf))
+			break;
+		((char*)buf)++;
+		if (get_1284_register(pp, 1, NULL))
+			break;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return written;
+}
+
+static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	unsigned long rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_ECP))
+		return 0;
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+	if (i)
+		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+}
+
+static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	unsigned long rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_ECP))
+		return 0;
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen);
+	if (i)
+		printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %u rlen %lu\n", buffer, len, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+}
+
+static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+	size_t written = 0;
+
+	if (change_mode(pp, ECR_ECP))
+		return 0;
+	for (; written < len; written++) {
+		if (set_1284_register(pp, 5, *(char *)buffer))
+			break;
+		((char*)buffer)++;
+	}
+	change_mode(pp, ECR_PS2);
+	return written;
+}
+
+static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	unsigned long rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_PPF))
+		return 0;
+	i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+	if (i)
+		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+}
+
+void parport_uss720_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+void parport_uss720_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct parport_operations parport_uss720_ops = 
+{
+	parport_uss720_write_data,
+	parport_uss720_read_data,
+
+	parport_uss720_write_control,
+	parport_uss720_read_control,
+	parport_uss720_frob_control,
+
+	parport_uss720_read_status,
+
+	parport_uss720_enable_irq,
+	parport_uss720_disable_irq,
+
+	parport_uss720_data_forward,
+	parport_uss720_data_reverse,
+
+	parport_uss720_init_state,
+	parport_uss720_save_state,
+	parport_uss720_restore_state,
+
+	parport_uss720_inc_use_count,
+	parport_uss720_dec_use_count,
+
+	parport_uss720_epp_write_data,
+	parport_uss720_epp_read_data,
+	parport_uss720_epp_write_addr,
+	parport_uss720_epp_read_addr,
+
+	parport_uss720_ecp_write_data,
+	parport_uss720_ecp_read_data,
+	parport_uss720_ecp_write_addr,
+
+	parport_uss720_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int uss720_probe(struct usb_device *usbdev)
+{
+        struct usb_interface_descriptor *interface;
+        struct usb_endpoint_descriptor *endpoint;
+	struct parport_uss720_private *priv;
+	struct parport *pp;
+        int i;
+
+        printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
+               usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
+
+        if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) &&
+            (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001))
+                return -1;
+
+        /* We don't handle multiple configurations */
+        if (usbdev->descriptor.bNumConfigurations != 1)
+                return -1;
+
+        /* We don't handle multiple interfaces */
+        if (usbdev->config[0].bNumInterfaces != 1)
+                return -1;
+
+        /* We don't handle multiple interfaces */
+        if (usbdev->config[0].num_altsetting != 3)
+                return -1;
+
+        printk(KERN_DEBUG "uss720: set configuration\n");
+        usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue);
+
+        i = usb_set_interface(usbdev, 0, 2);
+        printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
+
+        interface = &usbdev->config[0].altsetting[2].interface[0];
+
+        //printk(KERN_DEBUG "uss720: get interface\n");
+        //i = usb_get_interface(usbdev, 0);
+        //printk(KERN_DEBUG "uss720: is in alternate setting %d\n", i);
+
+	/*
+	 * Allocate parport interface 
+	 */
+	printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
+
+	if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
+		return -1;
+	if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
+		kfree(priv);
+		return -1;
+	}
+	pp->private_data = priv;
+        usbdev->private = pp;
+	priv->usbdev = usbdev;
+	pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
+
+        /* set the USS720 control register to manual mode, no ECP compression, enable all ints */
+        set_1284_register(pp, 7, 0x00);
+	set_1284_register(pp, 6, 0x30);  /* PS/2 mode */
+	set_1284_register(pp, 2, 0x0c);
+        /* debugging */
+        get_1284_register(pp, 0, NULL);
+        printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n",
+               priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+
+        endpoint = &interface->endpoint[2];
+	printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->bEndpointAddress, endpoint->bInterval);
+#if 0
+        priv->irqhandle = usb_request_irq(usbdev, usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress),
+					  uss720_irq, endpoint->bInterval, pp);
+#endif
+        parport_proc_register(pp);
+        parport_announce_port(pp);
+
+	MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static void uss720_disconnect(struct usb_device *usbdev)
+{
+	struct parport *pp = (struct parport *)usbdev->private;
+	struct parport_uss720_private *priv = pp->private_data;
+
+#if 0
+	usb_release_irq(usbdev, priv->irqhandle);
+#endif
+        usbdev->private = NULL;
+        priv->usbdev = NULL;
+	parport_proc_unregister(pp);
+	parport_unregister_port(pp);
+	kfree(priv);
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver uss720_driver = {
+        "uss720",
+        uss720_probe,
+        uss720_disconnect,
+        { NULL, NULL }
+};
+
+/* --------------------------------------------------------------------- */
+
+#define __exit
+#define module_exit(x) void cleanup_module(void) { x(); }
+#define module_init(x) int init_module(void) { return x(); }
+
+/* --------------------------------------------------------------------- */
+
+static int __init uss720_init(void)
+{
+	usb_register(&uss720_driver);
+        printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.2 registered.\n"
+	       KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
+	return 0;
+}
+
+static void __exit uss720_cleanup(void)
+{
+	usb_deregister(&uss720_driver);
+}
+
+module_init(uss720_init);
+module_exit(uss720_cleanup);
+
+/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.12/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.12/linux/drivers/video/Config.in	Thu May 13 23:48:20 1999
+++ linux/drivers/video/Config.in	Mon Aug  9 11:56:25 1999
@@ -49,7 +49,7 @@
   fi
   if [ "$CONFIG_ATARI" = "y" ]; then
     bool 'Atari native chipset support' CONFIG_FB_ATARI
-    bool 'ATI Mach64 display support' CONFIG_FB_ATY
+    tristate 'ATI Mach64 display support' CONFIG_FB_ATY
   fi
   if [ "$CONFIG_PPC" = "y" ]; then
     bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
@@ -57,11 +57,12 @@
       bool 'Apple "control" display support' CONFIG_FB_CONTROL
       bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
       bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
-      bool 'ATI Mach64 display support' CONFIG_FB_ATY
+      tristate 'ATI Mach64 display support' CONFIG_FB_ATY
       bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
       bool 'Chips 65550 display support' CONFIG_FB_CT65550
       bool 'S3 Trio display support' CONFIG_FB_S3TRIO
     fi
+    tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
   fi
   if [ "$CONFIG_MAC" = "y" ]; then
     define_bool CONFIG_FB_MAC y
@@ -74,7 +75,7 @@
   fi
   if [ "$ARCH" = "i386" ]; then
     bool 'VESA VGA graphics console' CONFIG_FB_VESA
-    bool 'VGA 16-color graphics console' CONFIG_FB_VGA16
+    tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
     define_bool CONFIG_VIDEO_SELECT y
   fi
   if [ "$CONFIG_VISWS" = "y" ]; then
@@ -86,10 +87,10 @@
       if  [ "$CONFIG_FB_MATROX" != "n" ]; then
         bool '  Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
         bool '  Mystique support' CONFIG_FB_MATROX_MYSTIQUE
-        bool '  G100/G200 support' CONFIG_FB_MATROX_G100
+        bool '  G100/G200/G400 support' CONFIG_FB_MATROX_G100
         bool '  Multihead support' CONFIG_FB_MATROX_MULTIHEAD
       fi
-      bool 'ATI Mach64 display support' CONFIG_FB_ATY
+      tristate 'ATI Mach64 display support' CONFIG_FB_ATY
     fi
   fi
   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
@@ -120,7 +121,7 @@
     if [ "$CONFIG_PCI" != "n" ]; then
       bool 'PCI framebuffers' CONFIG_FB_PCI
       if [ "$CONFIG_FB_PCI" != "n" ]; then
-        bool '  ATI Mach64 display support' CONFIG_FB_ATY
+        tristate '  ATI Mach64 display support' CONFIG_FB_ATY
       fi
     fi
   fi
@@ -142,7 +143,7 @@
     tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
 #   tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
     tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
-    bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
+    tristate 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
     tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA
   else
     # Guess what we need
@@ -287,6 +288,10 @@
     fi
     if [ "$CONFIG_FB_VGA16" = "y" ]; then
       define_bool CONFIG_FBCON_VGA_PLANES y
+    else
+      if [ "$CONFIG_FB_VGA16" = "m" ]; then
+	define_bool CONFIG_FBCON_VGA_PLANES m
+      fi
     fi
     if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
       define_bool CONFIG_FBCON_VGA y
diff -u --recursive --new-file v2.3.12/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.12/linux/drivers/video/Makefile	Thu Jul  8 15:42:21 1999
+++ linux/drivers/video/Makefile	Mon Aug  9 11:39:37 1999
@@ -102,6 +102,10 @@
 
 ifeq ($(CONFIG_FB_ATY),y)
 L_OBJS += atyfb.o
+else
+  ifeq ($(CONFIG_FB_ATY),m)
+  M_OBJS += atyfb.o
+  endif
 endif
 
 ifeq ($(CONFIG_FB_IGA),y)
@@ -206,6 +210,10 @@
 
 ifeq ($(CONFIG_FB_VGA16),y)
 L_OBJS += vga16fb.o
+else
+  ifeq ($(CONFIG_FB_VGA16),m)
+  M_OBJS += vga16fb.o
+  endif
 endif
 
 ifeq ($(CONFIG_FB_VIRGE),y)
diff -u --recursive --new-file v2.3.12/linux/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c
--- v2.3.12/linux/drivers/video/S3triofb.c	Thu Oct  1 10:02:21 1998
+++ linux/drivers/video/S3triofb.c	Mon Aug  9 10:25:01 1999
@@ -288,7 +288,7 @@
     return -EINVAL;
 }
 
-__initfunc(void s3triofb_init(void))
+void __init s3triofb_init(void)
 {
 #ifdef __powerpc__
     /* We don't want to be called like this. */
@@ -298,7 +298,7 @@
 #endif /* !__powerpc__ */
 }
 
-__initfunc(void s3trio_resetaccel(void)) {
+void __init s3trio_resetaccel(void){
 
 
 #define EC01_ENH_ENB    0x0005
@@ -341,7 +341,7 @@
 	outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX,  0xbee8);
 }
 
-__initfunc(int s3trio_init(struct device_node *dp)) {
+int __init s3trio_init(struct device_node *dp){
 
     u_char bus, dev;
     unsigned int t32;
@@ -402,7 +402,7 @@
      *  We heavily rely on OF for the moment. This needs fixing.
      */
 
-__initfunc(void s3triofb_init_of(struct device_node *dp))
+void __init s3triofb_init_of(struct device_node *dp)
 {
     int i, *pp, len;
     unsigned long address;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.3.12/linux/drivers/video/acornfb.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/video/acornfb.c	Mon Aug  9 10:25:01 1999
@@ -1429,8 +1429,8 @@
 	}
 };
 
-__initfunc(static int
-acornfb_lookup_timing(struct fb_var_screeninfo *var))
+static int __init 
+acornfb_lookup_timing(struct fb_var_screeninfo *var)
 {
 	const struct modex_params *x;
 	const struct modey_params *y;
@@ -1518,8 +1518,8 @@
 	return 0;
 }
 
-__initfunc(static void
-acornfb_init_fbinfo(void))
+static void __init 
+acornfb_init_fbinfo(void)
 {
 	static int first = 1;
 
@@ -1612,14 +1612,14 @@
  *	size can optionally be followed by 'M' or 'K' for
  *	MB or KB respectively.
  */
-__initfunc(static void
-acornfb_parse_font(char *opt))
+static void __init 
+acornfb_parse_font(char *opt)
 {
 	strcpy(fb_info.fontname, opt);
 }
 
-__initfunc(static void
-acornfb_parse_mon(char *opt))
+static void __init 
+acornfb_parse_mon(char *opt)
 {
 	fb_info.monspecs.hfmin = simple_strtoul(opt, &opt, 0);
 	if (*opt == '-')
@@ -1652,8 +1652,8 @@
 	init_var.height = simple_strtoul(opt + 1, NULL, 0);
 }
 
-__initfunc(static void
-acornfb_parse_montype(char *opt))
+static void __init 
+acornfb_parse_montype(char *opt)
 {
 	current_par.montype = -2;
 
@@ -1694,8 +1694,8 @@
 	}
 }
 
-__initfunc(static void
-acornfb_parse_dram(char *opt))
+static void __init 
+acornfb_parse_dram(char *opt)
 {
 	unsigned int size;
 
@@ -1728,8 +1728,8 @@
 	{ NULL, NULL }
 };
 
-__initfunc(void
-acornfb_setup(char *options, int *ints))
+void __init 
+acornfb_setup(char *options, int *ints)
 {
 	struct options *optp;
 	char *opt;
@@ -1765,8 +1765,8 @@
  * Detect type of monitor connected
  *  For now, we just assume SVGA
  */
-__initfunc(static int
-acornfb_detect_monitortype(void))
+static int __init 
+acornfb_detect_monitortype(void)
 {
 	return 4;
 }
@@ -1802,8 +1802,8 @@
 	printk("acornfb: freed %dK memory\n", mb_freed);
 }
 
-__initfunc(void
-acornfb_init(void))
+void __init 
+acornfb_init(void)
 {
 	unsigned long size;
 	u_int h_sync, v_sync;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/amifb.c linux/drivers/video/amifb.c
--- v2.3.12/linux/drivers/video/amifb.c	Tue Jan 19 10:47:48 1999
+++ linux/drivers/video/amifb.c	Mon Aug  9 10:25:01 1999
@@ -1259,8 +1259,7 @@
 	amifb_pan_display, amifb_ioctl
 };
 
-
-__initfunc(void amifb_setup(char *options, int *ints))
+void __init amifb_setup(char *options, int *ints)
 {
 	char *this_opt;
 	char mcap_spec[80];
@@ -1715,7 +1714,7 @@
 	 * Initialisation
 	 */
 
-__initfunc(void amifb_init(void))
+void __init amifb_init(void)
 {
 	int tag, i;
 	u_long chipptr;
@@ -2053,7 +2052,7 @@
 	 * Get a Video Mode
 	 */
 
-__initfunc(static void get_video_mode(const char *name))
+static void __init get_video_mode(const char *name)
 {
 	int i;
 
@@ -2070,7 +2069,7 @@
 	 *  Probe the Video Modes
 	 */
 
-__initfunc(static void check_default_mode(void))
+static void __init check_default_mode(void)
 {
 	struct amifb_par par;
 	int mode;
@@ -2090,7 +2089,7 @@
 	 * Allocate, Clear and Align a Block of Chip Memory
 	 */
 
-__initfunc(static u_long chipalloc(u_long size))
+static u_long __init chipalloc(u_long size)
 {
 	u_long ptr;
 
@@ -2107,7 +2106,7 @@
 	 * A strtok which returns empty strings, too
 	 */
 
-__initfunc(static char *strtoke(char *s,const char *ct))
+static char __init *strtoke(char *s,const char *ct)
 {
 	char *sbegin, *send;
 	static char *ssave = NULL;
@@ -3314,7 +3313,7 @@
 	 * Initialise the Copper Initialisation List
 	 */
 
-__initfunc(static void ami_init_copper(void))
+static void __init ami_init_copper(void)
 {
 	copins *cop = copdisplay.init;
 	u_long p;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/atafb.c linux/drivers/video/atafb.c
--- v2.3.12/linux/drivers/video/atafb.c	Thu Feb 25 10:02:11 1999
+++ linux/drivers/video/atafb.c	Mon Aug  9 11:39:38 1999
@@ -2745,7 +2745,7 @@
 		do_install_cmap(currcon, info);
 }
 
-__initfunc(void atafb_init(void))
+void __init atafb_init(void)
 {
 	int pad;
 	int detected_mode;
@@ -2828,9 +2828,12 @@
 		/* Map the video memory (physical address given) to somewhere
 		 * in the kernel address space.
 		 */
-		external_addr = ioremap_writethrough(external_addr, external_len);
+		external_addr =
+		  ioremap_writethrough((unsigned long)external_addr,
+				       external_len);
 		if (external_vgaiobase)
-			external_vgaiobase = ioremap(external_vgaiobase, 0x10000 );
+			external_vgaiobase =
+			  (unsigned long)ioremap(external_vgaiobase, 0x10000);
 		screen_base      =
 		real_screen_base = external_addr;
 		screen_len       = external_len & PAGE_MASK;
@@ -2892,7 +2895,7 @@
   return sbegin;
 }
 
-__initfunc(void atafb_setup( char *options, int *ints ))
+void __init atafb_setup( char *options, int *ints )
 {
     char *this_opt;
     int temp;
@@ -3069,7 +3072,7 @@
 	external_yres  = yres;
 	external_depth = depth;
 	external_pmode = planes;
-	external_addr  = addr;
+	external_addr  = (void *)addr;
 	external_len   = len;
 		
 	if (external_card_type == IS_MV300)
diff -u --recursive --new-file v2.3.12/linux/drivers/video/aty.h linux/drivers/video/aty.h
--- v2.3.12/linux/drivers/video/aty.h	Wed Nov 25 14:53:50 1998
+++ linux/drivers/video/aty.h	Mon Aug  9 11:39:37 1999
@@ -88,6 +88,8 @@
 #define MEM_VGA_WP_SEL		0x00B4	/* Dword offset 0_2D */
 #define MEM_VGA_RP_SEL		0x00B8	/* Dword offset 0_2E */
 
+#define I2C_CNTL_1		0x00BC	/* Dword offset 0_2F */
+
 #define DAC_REGS		0x00C0	/* Dword offset 0_30 */
 #define DAC_W_INDEX		0x00C0	/* Dword offset 0_30 */
 #define DAC_DATA		0x00C1	/* Dword offset 0_30 */
diff -u --recursive --new-file v2.3.12/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.12/linux/drivers/video/atyfb.c	Wed Jun  9 14:44:25 1999
+++ linux/drivers/video/atyfb.c	Mon Aug  9 11:40:29 1999
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.107 1999/06/08 19:59:03 geert Exp $
+/*  $Id: atyfb.c,v 1.109 1999/08/08 01:38:05 davem Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -72,8 +72,8 @@
 #ifdef __sparc__
 #include <asm/pbm.h>
 #include <asm/fbio.h>
-#include <asm/uaccess.h>
 #endif
+#include <asm/uaccess.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -136,6 +136,8 @@
     u8 pll_ext_cntl;
     u32 dsp_config;	/* Mach64 GTB DSP */
     u32 dsp_on_off;	/* Mach64 GTB DSP */
+    u8 mclk_post_div_real;
+    u8 vclk_post_div_real;
 };
 
 
@@ -189,6 +191,7 @@
 
 struct fb_info_aty {
     struct fb_info fb_info;
+    struct fb_info_aty *next;
     unsigned long ati_regbase_phys;
     unsigned long ati_regbase;
     unsigned long frame_buffer_phys;
@@ -340,16 +343,19 @@
 			   const struct pll_gx *pll);
 static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll);
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll);
-static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per,
+static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
 			     const struct fb_info_aty *info);
 static void aty_set_pll_ct(const struct fb_info_aty *info,
 			   const struct pll_ct *pll);
-static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
-		      u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
-		      u8 bpp, struct pll_ct *pll);
+static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			    struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
+		      struct pll_ct *pll);
+static void aty_calc_pll_ct(const struct fb_info_aty *info,
+			    struct pll_ct *pll);
 static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
 			     u8 bpp, struct pll_ct *pll);
-static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per,
+static u32 aty_pll_ct_to_var(const struct pll_ct *pll,
 			     const struct fb_info_aty *info);
 static void atyfb_set_par(const struct atyfb_par *par,
 			  struct fb_info_aty *info);
@@ -465,7 +471,7 @@
 };
 
 
-static inline u32 aty_ld_le32(volatile unsigned int regindex,
+static inline u32 aty_ld_le32(unsigned int regindex,
 			      const struct fb_info_aty *info)
 {
     unsigned long temp;
@@ -473,7 +479,7 @@
 
 #if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp));
+    asm("lwbrx %0,%1,%2" : "=r"(val) : "b" (regindex), "r" (temp));
 #elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
     asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
@@ -484,14 +490,14 @@
     return val;
 }
 
-static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
+static inline void aty_st_le32(unsigned int regindex, u32 val,
 			       const struct fb_info_aty *info)
 {
     unsigned long temp;
 
 #if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) :
+    asm("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) :
 	"memory");
 #elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
@@ -502,13 +508,13 @@
 #endif
 }
 
-static inline u8 aty_ld_8(volatile unsigned int regindex,
+static inline u8 aty_ld_8(unsigned int regindex,
 			  const struct fb_info_aty *info)
 {
     return *(volatile u8 *)(info->ati_regbase+regindex);
 }
 
-static inline void aty_st_8(volatile unsigned int regindex, u8 val,
+static inline void aty_st_8(unsigned int regindex, u8 val,
 			    const struct fb_info_aty *info)
 {
     *(volatile u8 *)(info->ati_regbase+regindex) = val;
@@ -941,8 +947,10 @@
 	}
 }
 
-__initfunc(static struct aty_cursor *
-aty_init_cursor(struct fb_info_aty *fb))
+static struct fb_info_aty *fb_list = NULL;
+
+static struct aty_cursor * __init 
+aty_init_cursor(struct fb_info_aty *fb)
 {
 	struct aty_cursor *cursor;
 	unsigned long addr;
@@ -1452,7 +1460,7 @@
 
     /* FIXME: ATI18818?? */
 
-static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per,
+static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
 			     const struct fb_info_aty *info)
 {
     u8 df, vco_div_count, ref_div_count;
@@ -1461,9 +1469,7 @@
     vco_div_count = pll->m & 0x3f;
     ref_div_count = pll->n;
 
-    *vclk_per = ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
-
-    return 0;
+    return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
 }
 
 
@@ -1495,16 +1501,15 @@
     }
 }
 
-static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
-		      u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
-		      u8 bpp, struct pll_ct *pll)
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
+		      struct pll_ct *pll)
 {
     u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
     u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
 
     /* xclocks_per_row<<11 */
-    xclks_per_row = (mclk_fb_div*vclk_post_div*64<<11)/
-		    (vclk_fb_div*mclk_post_div*bpp);
+    xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/
+		    (pll->vclk_fb_div*pll->mclk_post_div_real*bpp);
     if (xclks_per_row < (1<<11))
 	FAIL("Dotclock to high");
     if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID ||
@@ -1564,63 +1569,59 @@
     return 0;
 }
 
-static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
-			     u8 bpp, struct pll_ct *pll)
+static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			    struct pll_ct *pll)
 {
     u32 q, x;			/* x is a workaround for sparc64-linux-gcc */
-    u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
-    u8 mclk_fb_div, mclk_post_div, mpostdiv = 0;
-    u8 vclk_fb_div, vclk_post_div, vpostdiv = 0;
-    int err;
-
     x = x;			/* x is a workaround for sparc64-linux-gcc */
 
-    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
-
-    pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
+    pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
 
     /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
-    q = info->ref_clk_per*pll_ref_div*4/info->mclk_per;	/* actually 8*q */
+    q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;	/* actually 8*q */
     if (q < 16*8 || q > 255*8)
 	FAIL("mclk out of range");
     else if (q < 32*8)
-	mclk_post_div = 8;
+	pll->mclk_post_div_real = 8;
     else if (q < 64*8)
-	mclk_post_div = 4;
+	pll->mclk_post_div_real = 4;
     else if (q < 128*8)
-	mclk_post_div = 2;
+	pll->mclk_post_div_real = 2;
     else
-	mclk_post_div = 1;
-    mclk_fb_div = q*mclk_post_div/8;
+	pll->mclk_post_div_real = 1;
+    pll->mclk_fb_div = q*pll->mclk_post_div_real/8;
 
     /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
-    q = info->ref_clk_per*pll_ref_div*4/vclk_per;	/* actually 8*q */
+    q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per;	/* actually 8*q */
     if (q < 16*8 || q > 255*8)
 	FAIL("vclk out of range");
     else if (q < 32*8)
-	vclk_post_div = 8;
+	pll->vclk_post_div_real = 8;
     else if (q < 64*8)
-	vclk_post_div = 4;
+	pll->vclk_post_div_real = 4;
     else if (q < 128*8)
-	vclk_post_div = 2;
+	pll->vclk_post_div_real = 2;
     else
-	vclk_post_div = 1;
-    vclk_fb_div = q*vclk_post_div/8;
+	pll->vclk_post_div_real = 1;
+    pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
+    return 0;
+}
 
-    if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div,
-			  vclk_post_div, bpp, pll)))
-	return err;
+static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
+{
+    u8 mpostdiv = 0;
+    u8 vpostdiv = 0;
 
     if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
 	 (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) ||
 	 (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
 	 (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
 	 (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
-	pll_gen_cntl = 0x04;
+	pll->pll_gen_cntl = 0x04;
     else
-	pll_gen_cntl = 0x84;
+	pll->pll_gen_cntl = 0x84;
 
-    switch (mclk_post_div) {
+    switch (pll->mclk_post_div_real) {
 	case 1:
 	    mpostdiv = 0;
 	    break;
@@ -1637,61 +1638,64 @@
 	    mpostdiv = 3;
 	    break;
     }
-    pll_gen_cntl |= mpostdiv<<4;	/* mclk */
+    pll->pll_gen_cntl |= mpostdiv<<4;	/* mclk */
 
     if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
-	pll_ext_cntl = 0;
+	pll->pll_ext_cntl = 0;
     else
-    	pll_ext_cntl = mpostdiv;	/* xclk == mclk */
+    	pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */
 
-    switch (vclk_post_div) {
+    switch (pll->vclk_post_div_real) {
 	case 2:
 	    vpostdiv = 1;
 	    break;
 	case 3:
-	    pll_ext_cntl |= 0x10;
+	    pll->pll_ext_cntl |= 0x10;
 	case 1:
 	    vpostdiv = 0;
 	    break;
 	case 6:
-	    pll_ext_cntl |= 0x10;
+	    pll->pll_ext_cntl |= 0x10;
 	case 4:
 	    vpostdiv = 2;
 	    break;
 	case 12:
-	    pll_ext_cntl |= 0x10;
+	    pll->pll_ext_cntl |= 0x10;
 	case 8:
 	    vpostdiv = 3;
 	    break;
     }
-    vclk_post_div = vpostdiv;
 
-    pll->pll_ref_div = pll_ref_div;
-    pll->pll_gen_cntl = pll_gen_cntl;
-    pll->mclk_fb_div = mclk_fb_div;
-    pll->vclk_post_div = vclk_post_div;
-    pll->vclk_fb_div = vclk_fb_div;
-    pll->pll_ext_cntl = pll_ext_cntl;
+    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
+    pll->vclk_post_div = vpostdiv;
+}
+
+static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			     u8 bpp, struct pll_ct *pll)
+{
+    int err;
+
+    if ((err = aty_valid_pll_ct(info, vclk_per, pll)))
+	return err;
+    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
+	  Gx == ET_CHIP_ID ||
+	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {
+	if ((err = aty_dsp_gt(info, bpp, pll)))
+	    return err;
+    }
+    aty_calc_pll_ct(info, pll);
     return 0;
 }
 
-static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per,
+static u32 aty_pll_ct_to_var(const struct pll_ct *pll,
 			     const struct fb_info_aty *info)
 {
+    u32 ref_clk_per = info->ref_clk_per;
     u8 pll_ref_div = pll->pll_ref_div;
     u8 vclk_fb_div = pll->vclk_fb_div;
-    u8 vclk_post_div = pll->vclk_post_div;
-    u8 pll_ext_cntl = pll->pll_ext_cntl;
-    static u8 vclk_post_div_tab[] = {
-	1, 2, 4, 8,
-	3, 0, 6, 12
-    };
-    u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 2) |
-				    (vclk_post_div & 3)];
-    if (vpostdiv == 0)
-	return -EINVAL;
-    *vclk_per = pll_ref_div*vpostdiv*info->ref_clk_per/vclk_fb_div/2;
-    return 0;
+    u8 vclk_post_div = pll->vclk_post_div_real;
+
+    return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1739,7 +1743,7 @@
 					
     } else {
 	aty_set_pll_ct(info, &par->pll.ct);
-	i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
+	i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff;
 	if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
 	    i |= info->mem_refresh_rate << 20;
 	switch (par->crtc.bpp) {
@@ -1844,11 +1848,9 @@
     if ((err = aty_crtc_to_var(&par->crtc, var)))
 	return err;
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock, info);
+	var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info);
     else
-	err = aty_pll_ct_to_var(&par->pll.ct, &var->pixclock, info);
-    if (err)
-	return err;
+	var->pixclock = aty_pll_ct_to_var(&par->pll.ct, info);
 
     var->height = -1;
     var->width = -1;
@@ -2194,36 +2196,101 @@
 }
 
 
+#ifdef DEBUG
+#define ATYIO_CLKR		0x41545900	/* ATY\00 */
+#define ATYIO_CLKW		0x41545901	/* ATY\01 */
+
+struct atyclk {
+    u32 ref_clk_per;
+    u8 pll_ref_div;
+    u8 mclk_fb_div;
+    u8 mclk_post_div;		/* 1,2,3,4,8 */
+    u8 vclk_fb_div;
+    u8 vclk_post_div;		/* 1,2,3,4,6,8,12 */
+    u32 dsp_xclks_per_row;	/* 0-16383 */
+    u32 dsp_loop_latency;	/* 0-15 */
+    u32 dsp_precision;		/* 0-7 */
+    u32 dsp_on;			/* 0-2047 */
+    u32 dsp_off;		/* 0-2047 */
+};
+#endif
+
 static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info)
+		       u_long arg, int con, struct fb_info *info2)
 {
+    struct fb_info_aty *info = (struct fb_info_aty *)info2;
 #ifdef __sparc__
-    struct fb_info_aty *fb = (struct fb_info_aty *)info;
     struct fbtype fbtyp;
     struct display *disp;
     
     if (con >= 0)
     	disp = &fb_display[con];
     else
-        disp = info->disp;
+        disp = info2->disp;
+#endif
 
     switch (cmd) {
+#ifdef __sparc__
     case FBIOGTYPE:
 	fbtyp.fb_type = FBTYPE_PCI_GENERIC;
-	fbtyp.fb_width = fb->current_par.crtc.vxres;
-	fbtyp.fb_height = fb->current_par.crtc.vyres;
-	fbtyp.fb_depth = fb->current_par.crtc.bpp;
+	fbtyp.fb_width = info->current_par.crtc.vxres;
+	fbtyp.fb_height = info->current_par.crtc.vyres;
+	fbtyp.fb_depth = info->current_par.crtc.bpp;
 	fbtyp.fb_cmsize = disp->cmap.len;
-	fbtyp.fb_size = fb->total_vram;
+	fbtyp.fb_size = info->total_vram;
 	copy_to_user_ret((struct fbtype *)arg, &fbtyp, sizeof(fbtyp), -EFAULT);
 	break;
+#endif /* __sparc__ */
+#ifdef DEBUG
+    case ATYIO_CLKR:
+	if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+	    struct atyclk clk;
+	    struct pll_ct *pll = &info->current_par.pll.ct;
+	    u32 dsp_config = pll->dsp_config;
+	    u32 dsp_on_off = pll->dsp_on_off;
+	    clk.ref_clk_per = info->ref_clk_per;
+	    clk.pll_ref_div = pll->pll_ref_div;
+	    clk.mclk_fb_div = pll->mclk_fb_div;
+	    clk.mclk_post_div = pll->mclk_post_div_real;
+	    clk.vclk_fb_div = pll->vclk_fb_div;
+	    clk.vclk_post_div = pll->vclk_post_div_real;
+	    clk.dsp_xclks_per_row = dsp_config & 0x3fff;
+	    clk.dsp_loop_latency = (dsp_config>>16) & 0xf;
+	    clk.dsp_precision = (dsp_config>>20) & 7;
+	    clk.dsp_on = dsp_on_off & 0x7ff;
+	    clk.dsp_off = (dsp_on_off>>16) & 0x7ff;
+	    copy_to_user_ret((struct atyclk *)arg, &clk, sizeof(clk),
+			     -EFAULT);
+	} else
+	    return -EINVAL;
+	break;
+    case ATYIO_CLKW:
+	if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+	    struct atyclk clk;
+	    struct pll_ct *pll = &info->current_par.pll.ct;
+	    copy_from_user_ret(&clk, (struct atyclk *)arg, sizeof(clk),
+			       -EFAULT);
+	    info->ref_clk_per = clk.ref_clk_per;
+	    pll->pll_ref_div = clk.pll_ref_div;
+	    pll->mclk_fb_div = clk.mclk_fb_div;
+	    pll->mclk_post_div_real = clk.mclk_post_div;
+	    pll->vclk_fb_div = clk.vclk_fb_div;
+	    pll->vclk_post_div_real = clk.vclk_post_div;
+	    pll->dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
+			      ((clk.dsp_loop_latency & 0xf)<<16) |
+			      ((clk.dsp_precision & 7)<<20);
+	    pll->dsp_on_off = (clk.dsp_on & 0x7ff) |
+			      ((clk.dsp_off & 0x7ff)<<16);
+	    aty_calc_pll_ct(info, pll);
+	    aty_set_pll_ct(info, pll);
+	} else
+	    return -EINVAL;
+	break;
+#endif /* DEBUG */
     default:
 	return -EINVAL;
     }
     return 0;
-#else
-    return -EINVAL;
-#endif
 }
 
 #ifdef __sparc__
@@ -2424,7 +2491,7 @@
      *  Initialisation
      */
 
-__initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
+static int __init aty_init(struct fb_info_aty *info, const char *name)
 {
     u32 chip_id;
     u32 i;
@@ -2746,12 +2813,15 @@
     if (register_framebuffer(&info->fb_info) < 0)
 	return 0;
 
+    info->next = fb_list;
+    fb_list = info;
+
     printk("fb%d: %s frame buffer device on %s\n",
 	   GET_FB_IDX(info->fb_info.node), atyfb_name, name);
     return 1;
 }
 
-__initfunc(void atyfb_init(void))
+void __init atyfb_init(void)
 {
 #if defined(CONFIG_FB_OF)
     /* We don't want to be called like this. */
@@ -2779,6 +2849,7 @@
     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;
 
 	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
 	    if (!info) {
@@ -2787,12 +2858,12 @@
 	    }
 	    memset(info, 0, sizeof(struct fb_info_aty));
 
-	    addr = pdev->base_address[0];
-	    if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-		addr = pdev->base_address[1];
+	    rp = &pdev->resource[0];
+	    if (rp->flags & IORESOURCE_IOPORT)
+		    rp = &pdev->resource[1];
+	    addr = rp->start;
 	    if (!addr)
 		continue;
-	    addr &= PCI_BASE_ADDRESS_MEM_MASK;
 
 #ifdef __sparc__
 	    /*
@@ -2811,7 +2882,7 @@
 	     * Figure mmap addresses from PCI config space.
 	     * Split Framebuffer in big- and little-endian halfs.
 	     */
-	    for (i = 0; i < 6 && pdev->base_address[i]; i++)
+	    for (i = 0; i < 6 && pdev->resource[i].start; i++)
 		/* nothing */;
 	    j = i + 4;
 
@@ -2823,14 +2894,15 @@
 	    }
 	    memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
 
-	    for (i = 0, j = 2; i < 6 && pdev->base_address[i]; i++) {
+	    for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
+		struct resource *rp = &pdev->resource[i];
 		int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
 		unsigned long base;
 		u32 size, pbase;
 
-		base = pdev->base_address[i];
+		base = rp->start;
 
-		io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+		io = (rp->flags & IORESOURCE_IOPORT);
 
 		pci_read_config_dword(pdev, breg, &pbase);
 		pci_write_config_dword(pdev, breg, 0xffffffff);
@@ -3096,7 +3168,7 @@
 }
 
 #ifdef CONFIG_FB_OF
-__initfunc(void atyfb_of_init(struct device_node *dp))
+void __init atyfb_of_init(struct device_node *dp)
 {
     unsigned long addr;
     u8 bus, devfn;
@@ -3135,7 +3207,7 @@
 						   0x1000);
 
     if(! info->ati_regbase) {
-	    printk("atyfb_init: ioremap() returned NULL\n");
+	    printk("atyfb_of_init: ioremap() returned NULL\n");
 	    kfree(info);
 	    return;
     }
@@ -3162,7 +3234,7 @@
     info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
     if(! info->frame_buffer) {
-	    printk("atyfb_init: ioremap() returned NULL\n");
+	    printk("atyfb_of_init: ioremap() returned NULL\n");
 	    kfree(info);
 	    return;
     }
@@ -3180,7 +3252,7 @@
 #endif /* CONFIG_FB_OF */
 
 
-__initfunc(void atyfb_setup(char *options, int *ints))
+void __init atyfb_setup(char *options, int *ints)
 {
     char *this_opt;
 
@@ -3251,7 +3323,7 @@
 }
 
 #ifdef CONFIG_ATARI
-__initfunc(static int store_video_par(char *video_str, unsigned char m64_num))
+static int __init store_video_par(char *video_str, unsigned char m64_num)
 {
     char *p;
     unsigned long vmembase, size, guiregbase;
@@ -3280,7 +3352,7 @@
     return -1;
 }
 
-__initfunc(static char *strtoke(char *s, const char *ct))
+static char __init *strtoke(char *s, const char *ct)
 {
     static char *ssave = NULL;
     char *sbegin, *send;
@@ -3869,4 +3941,45 @@
     fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_aty32_clear_margins,
     FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
+#endif
+
+#ifdef MODULE
+int __init init_module(void)
+{
+    atyfb_init();
+    return fb_list ? 0 : -ENXIO;
+}
+
+void cleanup_module(void)
+{
+    while (fb_list) {
+	struct fb_info_aty *info = fb_list;
+	fb_list = info->next;
+
+	unregister_framebuffer(&info->fb_info);
+
+#ifndef __sparc__
+	if (info->ati_regbase)
+	    iounmap((void *)info->ati_regbase);
+	if (info->frame_buffer)
+	    iounmap((void *)info->frame_buffer);
+#ifdef __BIG_ENDIAN
+	if (info->cursor && info->cursor->ram)
+	    iounmap(info->cursor->ram);
+#endif
+#endif
+
+	if (info->cursor) {
+	    if (info->cursor->timer)
+		kfree(info->cursor->timer);
+	    kfree(info->cursor);
+	}
+#ifdef __sparc__
+	if (info->mmap_map)
+	    kfree(info->mmap_map);
+#endif
+	kfree(info);
+    }
+}
+
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/video/cgfourteenfb.c linux/drivers/video/cgfourteenfb.c
--- v2.3.12/linux/drivers/video/cgfourteenfb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/cgfourteenfb.c	Mon Aug  9 10:25:01 1999
@@ -288,19 +288,19 @@
 	return 0;
 }
 
-__initfunc(static unsigned long get_phys(unsigned long addr))
+static unsigned long __init get_phys(unsigned long addr)
 {
 	return __get_phys(addr);
 }
 
-__initfunc(static int get_iospace(unsigned long addr))
+static int __init get_iospace(unsigned long addr)
 {
 	return __get_iospace(addr);
 }
 
 static char idstring[60] __initdata = { 0 };
 
-__initfunc(char *cgfourteenfb_init(struct fb_info_sbusfb *fb))
+char __init *cgfourteenfb_init(struct fb_info_sbusfb *fb)
 {
 	struct fb_fix_screeninfo *fix = &fb->fix;
 	struct display *disp = &fb->disp;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- v2.3.12/linux/drivers/video/cgsixfb.c	Thu May 27 09:55:21 1999
+++ linux/drivers/video/cgsixfb.c	Mon Aug  9 10:25:01 1999
@@ -590,7 +590,7 @@
 
 static char idstring[70] __initdata = { 0 };
 
-__initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb))
+char __init *cgsixfb_init(struct fb_info_sbusfb *fb)
 {
 	struct fb_fix_screeninfo *fix = &fb->fix;
 	struct fb_var_screeninfo *var = &fb->var;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/cgthreefb.c linux/drivers/video/cgthreefb.c
--- v2.3.12/linux/drivers/video/cgthreefb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/cgthreefb.c	Mon Aug  9 10:25:01 1999
@@ -145,7 +145,7 @@
 
 static char idstring[60] __initdata = { 0 };
 
-__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb))
+char __init *cgthreefb_init(struct fb_info_sbusfb *fb)
 {
 	struct fb_fix_screeninfo *fix = &fb->fix;
 	struct display *disp = &fb->disp;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- v2.3.12/linux/drivers/video/chipsfb.c	Mon Jan  4 10:09:59 1999
+++ linux/drivers/video/chipsfb.c	Mon Aug  9 10:25:01 1999
@@ -525,7 +525,7 @@
 	{ 0xa8, 0x00 }
 };
 
-__initfunc(static void chips_hw_init(struct fb_info_chips *p))
+static void __init chips_hw_init(struct fb_info_chips *p)
 {
 	int i;
 
@@ -544,7 +544,7 @@
 		write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
 }
 
-__initfunc(static void init_chips(struct fb_info_chips *p))
+static void __init init_chips(struct fb_info_chips *p)
 {
 	int i;
 
@@ -645,7 +645,7 @@
 	all_chips = p;
 }
 
-__initfunc(void chips_init(void))
+void __init chips_init(void)
 {
 #ifndef CONFIG_FB_OF
 	struct device_node *dp;
@@ -656,7 +656,7 @@
 #endif /* CONFIG_FB_OF */
 }
 
-__initfunc(void chips_of_init(struct device_node *dp))
+void __init chips_of_init(struct device_node *dp)
 {
 	struct fb_info_chips *p;
 	unsigned long addr;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.3.12/linux/drivers/video/clgenfb.c	Thu Feb 25 10:02:11 1999
+++ linux/drivers/video/clgenfb.c	Mon Aug  9 10:25:01 1999
@@ -1467,7 +1467,7 @@
 /********************************************************************/
 /* clgenfb_init() - master initialization function                  */
 /********************************************************************/
-__initfunc(void clgenfb_init(void))
+void __init clgenfb_init(void)
 {
     const struct ConfigDev *cd  = NULL;
     const struct ConfigDev *cd2 = NULL;
@@ -1655,7 +1655,7 @@
 /* arguments to the video= bootstrap parameter. Right now, there */
 /* is nothing I do here.                                         */
 /*****************************************************************/
-__initfunc(void clgenfb_setup(char *options, int *ints))
+void __init clgenfb_setup(char *options, int *ints)
 {
 //    char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.3.12/linux/drivers/video/controlfb.c	Thu Feb 25 10:02:11 1999
+++ linux/drivers/video/controlfb.c	Mon Aug  9 10:25:01 1999
@@ -523,7 +523,7 @@
 }
 
 
-__initfunc(static void init_control(struct fb_info_control *p))
+static void __init init_control(struct fb_info_control *p)
 {
 	struct fb_par_control parstruct;
 	struct fb_par_control *par = &parstruct;
@@ -660,7 +660,7 @@
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
-__initfunc(void control_init(void))
+void __init control_init(void)
 {
 #ifndef CONFIG_FB_OF
 	struct device_node *dp;
@@ -671,7 +671,7 @@
 #endif /* CONFIG_FB_OF */
 }
 
-__initfunc(void control_of_init(struct device_node *dp))
+void __init control_of_init(struct device_node *dp)
 {
 	struct fb_info_control	*p;
 	unsigned long		addr, size;
@@ -1152,7 +1152,7 @@
 }
 
 /* Parse user speficied options (`video=controlfb:') */
-__initfunc(void control_setup(char *options, int *ints))
+void __init control_setup(char *options, int *ints)
 {
 	char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- v2.3.12/linux/drivers/video/creatorfb.c	Thu Apr 22 19:30:08 1999
+++ linux/drivers/video/creatorfb.c	Mon Aug  9 10:25:01 1999
@@ -637,7 +637,7 @@
 
 static char idstring[60] __initdata = { 0 };
 
-__initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb))
+char __init *creatorfb_init(struct fb_info_sbusfb *fb)
 {
 	struct fb_fix_screeninfo *fix = &fb->fix;
 	struct fb_var_screeninfo *var = &fb->var;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- v2.3.12/linux/drivers/video/cyber2000fb.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/video/cyber2000fb.c	Mon Aug  9 10:25:01 1999
@@ -1018,7 +1018,7 @@
 	}
 }
 
-__initfunc(void cyber2000fb_setup(char *options, int *ints))
+void __init cyber2000fb_setup(char *options, int *ints)
 {
 }
 
@@ -1035,8 +1035,8 @@
 	cyber2000fb_ioctl
 };
 
-__initfunc(static void
-cyber2000fb_init_fbinfo(void))
+static void __init 
+cyber2000fb_init_fbinfo(void)
 {
 	static int first = 1;
 
@@ -1138,7 +1138,7 @@
 /*
  *    Initialization
  */
-__initfunc(void cyber2000fb_init(void))
+void __init cyber2000fb_init(void)
 {
 	struct pci_dev *dev;
 	u_int h_sync, v_sync;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.3.12/linux/drivers/video/cyberfb.c	Tue Jan 19 10:47:48 1999
+++ linux/drivers/video/cyberfb.c	Mon Aug  9 11:39:38 1999
@@ -109,7 +109,10 @@
 
 #define arraysize(x)    (sizeof(x)/sizeof(*(x)))
 
-#define wb_64(reg,dat) (*((unsigned char volatile *)CyberRegs + reg) = dat)
+#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
+#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
+
+#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
 
 struct cyberfb_par {
 	struct fb_var_screeninfo var;
@@ -129,60 +132,32 @@
 
 
 /*
-*    Switch for Chipset Independency
-*/
-
-static struct fb_hwswitch {
-
-/* Initialisation */
-
-int (*init)(void);
-
-/* Display Control */
-
-int (*encode_fix)(struct fb_fix_screeninfo *fix, struct cyberfb_par *par);
-int (*decode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par);
-int (*encode_var)(struct fb_var_screeninfo *var, struct cyberfb_par *par);
-int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
-		 u_int *transp, struct fb_info *info);
-int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue,
-		 u_int transp, struct fb_info *info);
-void (*blank)(int blank);
-} *fbhw;
-
-
-/*
-*    Frame Buffer Name
-*/
+ *    Frame Buffer Name
+ */
 
 static char cyberfb_name[16] = "Cybervision";
 
 
 /*
-*    Cybervision Graphics Board
-*/
+ *    CyberVision Graphics Board
+ */
 
 static unsigned char Cyber_colour_table [256][3];
-static unsigned long CyberMem;
 static unsigned long CyberSize;
-static volatile char *CyberRegs;
+static volatile unsigned char *CyberBase;
+static volatile unsigned char *CyberMem;
+static volatile unsigned char *CyberRegs;
 static unsigned long CyberMem_phys;
 static unsigned long CyberRegs_phys;
-/* From cvision.c  for cvision_core.c */
-static unsigned long cv64_mem;
-static unsigned long cv64_fbmem;
-static volatile char *cv64_regs;
-static unsigned long cv64_size;
-#if 0
-static int cvision_custom_mode = 0;
-static int hbs, hbe, hss, hse, ht, vbs, vbe, vss, vse, vt;
-#endif
 
 /*
-*    Predefined Video Modes
-*/
+ *    Predefined Video Modes
+ */
 
-static struct fb_videomode cyberfb_predefined[] __initdata = {
+static struct {
+    const char *name;
+    struct fb_var_screeninfo var;
+} cyberfb_predefined[] __initdata = {
 	{ "640x480-8", {		/* Default 8 BPP mode (cyber8) */
 		640, 480, 640, 480, 0, 0, 8, 0,
 		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -251,17 +226,18 @@
 static int Cyberfb_inverse = 0;
 
 /*
-*    Some default modes
-*/
+ *    Some default modes
+ */
 
 #define CYBER8_DEFMODE     (0)
 #define CYBER16_DEFMODE    (1)
 
 static struct fb_var_screeninfo cyberfb_default;
+static int cyberfb_usermode __initdata = 0;
 
 /*
-*    Interface used by the world
-*/
+ *    Interface used by the world
+ */
 
 void cyberfb_setup(char *options, int *ints);
 
@@ -283,8 +259,8 @@
 			 u_long arg, int con, struct fb_info *info);
 
 /*
-*    Interface to the low level console driver
-*/
+ *    Interface to the low level console driver
+ */
 
 void cyberfb_init(void);
 static int Cyberfb_switch(int con, struct fb_info *info);
@@ -292,16 +268,16 @@
 static void Cyberfb_blank(int blank, struct fb_info *info);
 
 /*
-*    Text console acceleration
-*/
+ *    Text console acceleration
+ */
 
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_cyber8;
 #endif
 
 /*
-*    Accelerated Functions used by the low level console driver
-*/
+ *    Accelerated Functions used by the low level console driver
+ */
 
 static void Cyber_WaitQueue(u_short fifo);
 static void Cyber_WaitBlit(void);
@@ -310,11 +286,13 @@
 			 u_short mode);
 static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
 			   u_short mode, u_short color);
+#if 0
 static void Cyber_MoveCursor(u_short x, u_short y);
+#endif
 
 /*
-*   Hardware Specific Routines
-*/
+ *   Hardware Specific Routines
+ */
 
 static int Cyber_init(void);
 static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
@@ -327,11 +305,10 @@
 			   u_int *transp, struct fb_info *info);
 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			   u_int transp, struct fb_info *info);
-static void Cyber_blank(int blank);
 
 /*
-*    Internal routines
-*/
+ *    Internal routines
+ */
 
 static void cyberfb_get_par(struct cyberfb_par *par);
 static void cyberfb_set_par(struct cyberfb_par *par);
@@ -342,7 +319,7 @@
 
 /* For cvision_core.c */
 static unsigned short cv64_compute_clock(unsigned long);
-static int cv_has_4mb (volatile caddr_t);
+static int cv_has_4mb (volatile unsigned char *);
 static void cv64_board_init (void);
 static void cv64_load_video_mode (struct fb_var_screeninfo *);
 
@@ -351,16 +328,17 @@
 
 
 /*
-*    Initialization
-*
-*    Set the default video mode for this chipset. If a video mode was
-*    specified on the command line, it will override the default mode.
-*/
+ *    Initialization
+ *
+ *    Set the default video mode for this chipset. If a video mode was
+ *    specified on the command line, it will override the default mode.
+ */
 
 static int Cyber_init(void)
 {
+	volatile unsigned char *regs = CyberRegs;
+	volatile unsigned long *CursorBase;
 	int i;
-	volatile u_long *CursorBase;
 	DPRINTK("ENTER\n");
 
 /* Init local cmap as greyscale levels */
@@ -371,27 +349,25 @@
 	}
 
 /* Initialize the board and determine fbmem size */
-	cv64_board_init (); 
+	cv64_board_init(); 
 #ifdef CYBERFBDEBUG
 	DPRINTK("Register state after initing board\n");
 	cv64_dump();
 #endif
 /* Clear framebuffer memory */
 	DPRINTK("Clear framebuffer memory\n");
-	memset ((char *) cv64_fbmem, 0, cv64_size);
+	memset ((char *)CyberMem, 0, CyberSize);
 
 /* Disable hardware cursor */
 	DPRINTK("Disable HW cursor\n");
-	wb_64(S3_CRTC_ADR, S3_REG_LOCK2);
-	wb_64(S3_CRTC_DATA, 0xa0);
-	wb_64(S3_CRTC_ADR, S3_HGC_MODE);
-	wb_64(S3_CRTC_DATA, 0x00);
-	wb_64(S3_CRTC_ADR, S3_HWGC_DX);
-	wb_64(S3_CRTC_DATA, 0x00);
-	wb_64(S3_CRTC_ADR, S3_HWGC_DY);
-	wb_64(S3_CRTC_DATA, 0x00);
-
-	CyberSize = cv64_size;
+	wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2);
+	wb_64(regs, S3_CRTC_DATA, 0xa0);
+	wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE);
+	wb_64(regs, S3_CRTC_DATA, 0x00);
+	wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX);
+	wb_64(regs, S3_CRTC_DATA, 0x00);
+	wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY);
+	wb_64(regs, S3_CRTC_DATA, 0x00);
 
 /* Initialize hardware cursor */
 	DPRINTK("Init HW cursor\n");
@@ -420,9 +396,9 @@
 
 
 /*
-*    This function should fill in the `fix' structure based on the
-*    values in the `par' structure.
-*/
+ *    This function should fill in the `fix' structure based on the
+ *    values in the `par' structure.
+ */
 
 static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
 			    struct cyberfb_par *par)
@@ -546,19 +522,21 @@
 
 
 /*
-*    Set a single color register. Return != 0 for invalid regno.
-*/
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
 
 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			   u_int transp, struct fb_info *info)
 {
+	volatile unsigned char *regs = CyberRegs;
+
 	/*DPRINTK("ENTER\n");*/
 	if (regno > 255) {
 		DPRINTK("EXIT - Register # > 255\n");
 		return (1);
 	}
 
-	wb_64(0x3c8, (unsigned char) regno);
+	wb_64(regs, 0x3c8, (unsigned char) regno);
 
  	red >>= 10;
  	green >>= 10;
@@ -568,9 +546,9 @@
 	Cyber_colour_table [regno][1] = green;
 	Cyber_colour_table [regno][2] = blue;
 
-	wb_64(0x3c9, red);
-	wb_64(0x3c9, green);
-	wb_64(0x3c9, blue);
+	wb_64(regs, 0x3c9, red);
+	wb_64(regs, 0x3c9, green);
+	wb_64(regs, 0x3c9, blue);
 
 	/*DPRINTK("EXIT\n");*/
 	return (0);
@@ -611,29 +589,30 @@
 *           0 = restore fb cmap from local cmap
 */
 
-void Cyber_blank(int blank)
+void Cyberfb_blank(int blank, struct fb_info *info)
 {
+	volatile unsigned char *regs = CyberRegs;
 	int i;
 
 	DPRINTK("ENTER\n");
 #if 0
 /* Blank by turning gfx off */
-	gfx_on_off (1, cv64_regs);
+	gfx_on_off (1, regs);
 #else
 	if (blank) {
 		for (i = 0; i < 256; i++) {
-			wb_64(0x3c8, (unsigned char) i);
+			wb_64(regs, 0x3c8, (unsigned char) i);
 			/* ARB Pale red to detect this blanking method */
-			wb_64(0x3c9, 48); 
-			wb_64(0x3c9, 0);
-			wb_64(0x3c9, 0);
+			wb_64(regs, 0x3c9, 48); 
+			wb_64(regs, 0x3c9, 0);
+			wb_64(regs, 0x3c9, 0);
 		}
 	} else {
 		for (i = 0; i < 256; i++) {
-			wb_64(0x3c8, (unsigned char) i);
-			wb_64(0x3c9, Cyber_colour_table[i][0]);
-			wb_64(0x3c9, Cyber_colour_table[i][1]);
-			wb_64(0x3c9, Cyber_colour_table[i][2]);
+			wb_64(regs, 0x3c8, (unsigned char) i);
+			wb_64(regs, 0x3c9, Cyber_colour_table[i][0]);
+			wb_64(regs, 0x3c9, Cyber_colour_table[i][1]);
+			wb_64(regs, 0x3c9, Cyber_colour_table[i][2]);
 		}
 	}
 #endif
@@ -646,13 +625,12 @@
  */
 static void Cyber_WaitQueue (u_short fifo)
 {
-	u_short status;
+	unsigned short status;
 
 	DPRINTK("ENTER\n");
 	do {
 		status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
-	}
-	while (status & fifo);
+	} while (status & fifo);
 	DPRINTK("EXIT\n");
 }
 
@@ -661,13 +639,12 @@
  */
 static void Cyber_WaitBlit (void)
 {
-	u_short status;
+	unsigned short status;
 
 	DPRINTK("ENTER\n");
 	do {
 		status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
-	}
-	while (status & S3_HDW_BUSY);
+	} while (status & S3_HDW_BUSY);
 	DPRINTK("EXIT\n");
 }
 
@@ -678,6 +655,7 @@
 			  u_short desty, u_short width, u_short height,
 			  u_short mode)
 {
+	volatile unsigned char *regs = CyberRegs;
 	u_short blitcmd = S3_BITBLT;
 
 	DPRINTK("ENTER\n");
@@ -699,19 +677,19 @@
 
 	Cyber_WaitQueue (0x8000);
 
-	*((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
-	*((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0060 | mode);
+	*((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
+	*((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
 
-	*((u_short volatile *)(CyberRegs + S3_CUR_X)) = curx;
-	*((u_short volatile *)(CyberRegs + S3_CUR_Y)) = cury;
+	*((u_short volatile *)(regs + S3_CUR_X)) = curx;
+	*((u_short volatile *)(regs + S3_CUR_Y)) = cury;
 
-	*((u_short volatile *)(CyberRegs + S3_DESTX_DIASTP)) = destx;
-	*((u_short volatile *)(CyberRegs + S3_DESTY_AXSTP)) = desty;
+	*((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
+	*((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
 
-	*((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
-	*((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width  - 1;
+	*((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
+	*((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
 
-	*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
+	*((u_short volatile *)(regs + S3_CMD)) = blitcmd;
 	DPRINTK("EXIT\n");
 }
 
@@ -721,56 +699,52 @@
 static void Cyber_RectFill (u_short x, u_short y, u_short width,
 			    u_short height, u_short mode, u_short color)
 {
+	volatile unsigned char *regs = CyberRegs;
 	u_short blitcmd = S3_FILLEDRECT;
 
 	DPRINTK("ENTER\n");
 	Cyber_WaitQueue (0x8000);
 
-	*((u_short volatile *)(CyberRegs + S3_PIXEL_CNTL)) = 0xa000;
-	*((u_short volatile *)(CyberRegs + S3_FRGD_MIX)) = (0x0020 | mode);
+	*((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
+	*((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
 
-	*((u_short volatile *)(CyberRegs + S3_MULT_MISC)) = 0xe000;
-	*((u_short volatile *)(CyberRegs + S3_FRGD_COLOR)) = color;
+	*((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
+	*((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
 
-	*((u_short volatile *)(CyberRegs + S3_CUR_X)) = x;
-	*((u_short volatile *)(CyberRegs + S3_CUR_Y)) = y;
+	*((u_short volatile *)(regs + S3_CUR_X)) = x;
+	*((u_short volatile *)(regs + S3_CUR_Y)) = y;
 
-	*((u_short volatile *)(CyberRegs + S3_MIN_AXIS_PCNT)) = height - 1;
-	*((u_short volatile *)(CyberRegs + S3_MAJ_AXIS_PCNT)) = width  - 1;
+	*((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
+	*((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width  - 1;
 
-	*((u_short volatile *)(CyberRegs + S3_CMD)) = blitcmd;
+	*((u_short volatile *)(regs + S3_CMD)) = blitcmd;
 	DPRINTK("EXIT\n");
 }
 
+
+#if 0
 /**************************************************************
  * Move cursor to x, y
  */
 static void Cyber_MoveCursor (u_short x, u_short y)
 {
+	volatile unsigned char *regs = CyberRegs;
 	DPRINTK("ENTER\n");
-	*(CyberRegs + S3_CRTC_ADR)  = 0x39;
-	*(CyberRegs + S3_CRTC_DATA) = 0xa0;
+	*(regs + S3_CRTC_ADR)  = 0x39;
+	*(regs + S3_CRTC_DATA) = 0xa0;
 
-	*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGX_H;
-	*(CyberRegs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
-	*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGX_L;
-	*(CyberRegs + S3_CRTC_DATA) = (char)(x & 0x00ff);
-
-	*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGY_H;
-	*(CyberRegs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
-	*(CyberRegs + S3_CRTC_ADR)  = S3_HWGC_ORGY_L;
-	*(CyberRegs + S3_CRTC_DATA) = (char)(y & 0x00ff);
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGX_H;
+	*(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGX_L;
+	*(regs + S3_CRTC_DATA) = (char)(x & 0x00ff);
+
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGY_H;
+	*(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
+	*(regs + S3_CRTC_ADR)  = S3_HWGC_ORGY_L;
+	*(regs + S3_CRTC_DATA) = (char)(y & 0x00ff);
 	DPRINTK("EXIT\n");
 }
-
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-
-static struct fb_hwswitch Cyber_switch = {
-	Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var,
-	Cyber_getcolreg, Cyber_setcolreg, Cyber_blank
-};
+#endif
 
 
 /* -------------------- Generic routines ---------------------------------- */
@@ -786,7 +760,7 @@
 	if (current_par_valid) {
 		*par = current_par;
 	} else {
-		fbhw->decode_var(&cyberfb_default, par);
+		Cyber_decode_var(&cyberfb_default, par);
 	}
 	DPRINTK("EXIT\n");
 }
@@ -819,14 +793,14 @@
 	struct cyberfb_par par;
 
 	DPRINTK("ENTER\n");
-	if ((err = fbhw->decode_var(var, &par))) {
+	if ((err = Cyber_decode_var(var, &par))) {
 		DPRINTK("EXIT - decode_var failed\n");
 		return(err);
 	}
 	activate = var->activate;
 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
 		cyberfb_set_par(&par);
-	fbhw->encode_var(var, &par);
+	Cyber_encode_var(var, &par);
 	var->activate = activate;
 
 	cyber_set_video(var);
@@ -844,11 +818,11 @@
 	}
 	if (fb_display[con].cmap.len) {
 		DPRINTK("Use console cmap\n");
-		fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info);
+		fb_set_cmap(&fb_display[con].cmap, 1, Cyber_setcolreg, info);
 	} else {
 		DPRINTK("Use default cmap\n");
 		fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-			    1, fbhw->setcolreg, info);
+			    1, Cyber_setcolreg, info);
 	}
 	DPRINTK("EXIT\n");
 }
@@ -889,10 +863,10 @@
 	if (con == -1) {
 		cyberfb_get_par(&par);
 	} else {
-		error = fbhw->decode_var(&fb_display[con].var, &par);
+		error = Cyber_decode_var(&fb_display[con].var, &par);
 	}
 	DPRINTK("EXIT\n");
-	return(error ? error : fbhw->encode_fix(fix, &par));
+	return(error ? error : Cyber_encode_fix(fix, &par));
 }
 
 
@@ -909,7 +883,7 @@
 	DPRINTK("ENTER\n");
 	if (con == -1) {
 		cyberfb_get_par(&par);
-		error = fbhw->encode_var(var, &par);
+		error = Cyber_encode_var(var, &par);
 		disp.var = *var;   /* ++Andre: don't know if this is the right place */
 	} else {
 		*var = fb_display[con].var;
@@ -934,7 +908,7 @@
 	cyberfb_get_fix(&fix, con, info);
 	if (con == -1)
 		con = 0;
-	display->screen_base = phys_to_virt ((unsigned long) fix.smem_start);
+	display->screen_base = (unsigned char *)CyberMem;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -1014,7 +988,7 @@
 	DPRINTK("ENTER\n");
 	if (con == currcon) { /* current console? */
 		DPRINTK("EXIT - console is current console\n");
-		return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
+		return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info));
 	} else if (fb_display[con].cmap.len) { /* non default colormap? */
 		DPRINTK("Use console cmap\n");
 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
@@ -1048,7 +1022,7 @@
 	}
 	if (con == currcon) {		 /* current console? */
 		DPRINTK("EXIT - Current console\n");
-		return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info));
+		return(fb_set_cmap(cmap, kspc, Cyber_setcolreg, info));
 	} else {
 		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
 	}
@@ -1066,7 +1040,7 @@
 static int cyberfb_pan_display(struct fb_var_screeninfo *var, int con,
 			       struct fb_info *info)
 {
-	return(-EINVAL);
+	return -EINVAL;
 }
 
 
@@ -1077,7 +1051,7 @@
 static int cyberfb_ioctl(struct inode *inode, struct file *file,
 			 u_int cmd, u_long arg, int con, struct fb_info *info)
 {
-	return(-EINVAL);
+	return -EINVAL;
 }
 
 
@@ -1088,7 +1062,7 @@
 };
 
 
-__initfunc(void cyberfb_setup(char *options, int *ints))
+void __init cyberfb_setup(char *options, int *ints)
 {
 	char *this_opt;
 	DPRINTK("ENTER\n");
@@ -1109,8 +1083,10 @@
 			strcpy(fb_info.fontname, this_opt+5);
 		} else if (!strcmp (this_opt, "cyber8")) {
 			cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+			cyberfb_usermode = 1;
 		} else if (!strcmp (this_opt, "cyber16")) {
 			cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
+			cyberfb_usermode = 1;
 		} else get_video_mode(this_opt);
 	}
 
@@ -1125,7 +1101,7 @@
  *    Initialization
  */
 
-__initfunc(void cyberfb_init(void))
+void __init cyberfb_init(void)
 {
 	struct cyberfb_par par;
 	unsigned long board_addr;
@@ -1146,14 +1122,12 @@
 	DPRINTK("board_addr=%08lx\n", board_addr);
 	DPRINTK("board_size=%08lx\n", board_size);
 
-	cv64_mem = ioremap(board_addr, board_size);
-	cv64_regs = (volatile char *)(cv64_mem + 0x02000000);
-	cv64_fbmem = cv64_mem + 0x01400000;
-	DPRINTK("cv64_mem=%08lx cv64_regs=%08lx cv64_fbmem=%08lx\n",
-		cv64_mem, (long unsigned int)cv64_regs, cv64_fbmem);
+	CyberBase = ioremap(board_addr, board_size);
+	CyberRegs = CyberBase + 0x02000000;
+	CyberMem = CyberBase + 0x01400000;
+	DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
+		CyberBase, (long unsigned int)CyberRegs, CyberMem);
 
-	CyberMem = cv64_fbmem;
-	CyberRegs = cv64_regs;
 	CyberMem_phys = board_addr + 0x01400000;
 	CyberRegs_phys = CyberMem_phys + 0x00c00000;
 	DPRINTK("CyberMem=%08lx CyberRegs=%08lx\n", CyberMem,
@@ -1164,8 +1138,6 @@
 	cv64_dump();
 #endif
 
-	fbhw = &Cyber_switch;
-
 	strcpy(fb_info.modename, cyberfb_name);
 	fb_info.changevar = NULL;
 	fb_info.node = -1;
@@ -1175,9 +1147,14 @@
 	fb_info.updatevar = &Cyberfb_updatevar;
 	fb_info.blank = &Cyberfb_blank;
 
-	fbhw->init();
-	fbhw->decode_var(&cyberfb_default, &par);
-	fbhw->encode_var(&cyberfb_default, &par);
+	Cyber_init();
+	/* ++Andre: set cyberfb default mode */
+	if (!cyberfb_usermode) {
+		cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
+		DPRINTK("Use default cyber8 mode\n");
+	}
+	Cyber_decode_var(&cyberfb_default, &par);
+	Cyber_encode_var(&cyberfb_default, &par);
 
 	do_fb_set_var(&cyberfb_default, 1);
 	cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
@@ -1203,7 +1180,7 @@
         DPRINTK("ENTER\n");
 	/* Do we have to save the colormap? */
 	if (fb_display[currcon].cmap.len) {
-		fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg,
+		fb_get_cmap(&fb_display[currcon].cmap, 1, Cyber_getcolreg,
 			    info);
 	}
 
@@ -1231,22 +1208,10 @@
 
 
 /*
- *    Blank the display.
- */
-
-static void Cyberfb_blank(int blank, struct fb_info *info)
-{
-	DPRINTK("Enter\n");
-	fbhw->blank(blank);
-	DPRINTK("Exit\n");
-}
-
-
-/*
  *    Get a Video Mode
  */
 
-__initfunc(static int get_video_mode(const char *name))
+static int __init get_video_mode(const char *name)
 {
 	int i;
 
@@ -1254,13 +1219,11 @@
 	for (i = 0; i < NUM_TOTAL_MODES; i++) {
 		if (!strcmp(name, cyberfb_predefined[i].name)) {
 			cyberfb_default = cyberfb_predefined[i].var;
+			cyberfb_usermode = 1;
 			DPRINTK("EXIT - Matched predefined mode\n");
 			return(i);
 		}
 	}
-	/* ++Andre: set cyberfb default mode */
-	cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
-	DPRINTK("EXIT - Use default cyber8 mode\n");
 	return(0);
 }
 
@@ -1454,71 +1417,38 @@
 };
 
 /* -------------------- Hardware specific routines ------------------------- */
-#if 0
-/* ARB Generates 100 usec delay */
-inline void __cv_delay (unsigned long usecs)
-{
-	int k;
-	
-	for (k = 0; k < 1000; k++) {
-		asm volatile ("nop");
-	}
-}
-#endif
-
-/* Wait while Graphics Engine is busy */
-inline void GfxBusyWait (volatile caddr_t board)
-{
-	int test;
-	DPRINTK("ENTER\n");
-	
-	do {
-		test = vgar16 (board, ECR_GP_STAT);
-		asm volatile ("nop");
-	} while (test & (1 << 9));
-	DPRINTK("EXIT\n");
-}
-
-/* Wait for any of the 8 Trio32 FIFOs to be free */ 
-inline void GfxFifoWait (volatile caddr_t board)
-{
-	int test;
-	DPRINTK("ENTER\n");
-	
-	do {
-		test = vgar16 (board, ECR_GP_STAT);
-	} while (test & 0x0f);
-	DPRINTK("EXIT\n");
-}
 
 /* Read Attribute Controller Register=idx */
-inline unsigned char RAttr (volatile caddr_t board, short idx)
+inline unsigned char RAttr (volatile unsigned char *regs, short idx)
 {
-	vgaw (board, ACT_ADDRESS_W, idx);
+	wb_64 (regs, ACT_ADDRESS_W, idx);
+	mb();
 	udelay(100);
-	/* __cv_delay (0); */
-	return (vgar (board, ACT_ADDRESS_R));
+	return (rb_64(regs, ACT_ADDRESS_R));
 }
 
 /* Read Sequencer Register=idx */
-inline unsigned char RSeq (volatile caddr_t board, short idx)
+inline unsigned char RSeq (volatile unsigned char *regs, short idx)
 {
-	vgaw (board, SEQ_ADDRESS, idx);
-	return (vgar (board, SEQ_ADDRESS_R));
+	wb_64 (regs, SEQ_ADDRESS, idx);
+	mb();
+	return (rb_64(regs, SEQ_ADDRESS_R));
 }
 
 /* Read CRT Controller Register=idx */
-inline unsigned char RCrt (volatile caddr_t board, short idx)
+inline unsigned char RCrt (volatile unsigned char *regs, short idx)
 {
-	vgaw (board, CRT_ADDRESS, idx);
-	return (vgar (board, CRT_ADDRESS_R));
+	wb_64 (regs, CRT_ADDRESS, idx);
+	mb();
+	return (rb_64(regs, CRT_ADDRESS_R));
 }
 
 /* Read Graphics Controller Register=idx */
-inline unsigned char RGfx (volatile caddr_t board, short idx)
+inline unsigned char RGfx (volatile unsigned char *regs, short idx)
 {
-	vgaw (board, GCT_ADDRESS, idx);
-	return (vgar (board, GCT_ADDRESS_R));
+	wb_64 (regs, GCT_ADDRESS, idx);
+	mb();
+	return (rb_64(regs, GCT_ADDRESS_R));
 }
 
 /*
@@ -1526,13 +1456,13 @@
  */
 
 inline void cv64_write_port (unsigned short bits,
-			     volatile unsigned char *board)
+			     volatile unsigned char *base)
 {
 	volatile unsigned char *addr;
 	static unsigned char cvportbits = 0; /* Mirror port bits here */
 	DPRINTK("ENTER\n");
 
-	addr = board + 0x40001;
+	addr = base + 0x40001;
 	if (bits & 0x8000) {
 		cvportbits |= bits & 0xff; /* Set bits */
 		DPRINTK("Set bits: %04x\n", bits);
@@ -1542,7 +1472,7 @@
 		cvportbits &= bits; /* Clear bits */
 		DPRINTK("Clear bits: %04x\n", bits);
 	}
-	
+
 	*addr = cvportbits;
 	DPRINTK("EXIT\n");
 }
@@ -1572,7 +1502,7 @@
 /* Control screen display */
 /* toggle: 0 = on, 1 = off */
 /* board = registerbase */
-inline void gfx_on_off (int toggle, volatile unsigned char *board)
+inline void gfx_on_off(int toggle, volatile unsigned char *regs)
 {
 	int r;
 	DPRINTK("ENTER\n");
@@ -1581,10 +1511,10 @@
 	toggle = toggle << 5;
 	DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
 	
-	r = (int) RSeq ((volatile caddr_t) board, SEQ_ID_CLOCKING_MODE);
+	r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
 	r &= 0xdf;	/* Set bit 5 to 0 */
 	
-	WSeq (board, SEQ_ID_CLOCKING_MODE, r | toggle);
+	WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
 	DPRINTK("EXIT\n");
 }
 
@@ -1640,11 +1570,11 @@
 	return (erg);
 }
 
-static int cv_has_4mb (volatile caddr_t fb)
+static int cv_has_4mb (volatile unsigned char *fb)
 {
 	volatile unsigned long *tr, *tw;
 	DPRINTK("ENTER\n");
-	
+
 	/* write patterns in memory and test if they can be read */
 	tw = (volatile unsigned long *) fb;
 	tr = (volatile unsigned long *) (fb + 0x02000000);
@@ -1655,41 +1585,42 @@
 		DPRINTK("EXIT - <4MB\n");
 		return (0);
 	}
-	
+
 	/* upper memory region */
 	tw = (volatile unsigned long *) (fb + 0x00200000);
 	tr = (volatile unsigned long *) (fb + 0x02200000);
-	
+
 	*tw = 0x87654321;
-	
+
 	if (*tr != 0x87654321) {
 		DPRINTK("EXIT - <4MB\n");
 		return (0);
 	}
-	
+
 	*tw = 0xAAAAAAAA;
-	
+
 	if (*tr != 0xAAAAAAAA) {
 		DPRINTK("EXIT - <4MB\n");
 		return (0);
 	}
-	
+
 	*tw = 0x55555555;
-	
+
 	if (*tr != 0x55555555) {
 		DPRINTK("EXIT - <4MB\n");
 		return (0);
 	}
-	
+
 	DPRINTK("EXIT\n");
 	return (1);
 }
 
 static void cv64_board_init (void)
 {
+	volatile unsigned char *regs = CyberRegs;
 	int i;
-	unsigned char test;
 	unsigned int clockpar;
+	unsigned char test;
 	
 	DPRINTK("ENTER\n");
 
@@ -1698,259 +1629,252 @@
 	 */
 	/* Reset board */
 	for (i = 0; i < 6; i++) {
-		cv64_write_port (0xff, (volatile unsigned char *) cv64_mem);
+		cv64_write_port (0xff, CyberBase);
 	}
 	/* Return to operational mode */
-	cv64_write_port (0x8004, (volatile unsigned char *) cv64_mem);
+	cv64_write_port (0x8004, CyberBase);
 	
-  /*
-   * Generic (?) S3 chip wakeup
-   */
-  /* Disable I/O & memory decoders, video in setup mode */
-  vgaw (cv64_regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
-  /* Video responds to cmds, addrs & data */
-  vgaw (cv64_regs, SREG_OPTION_SELECT, 0x1);
-  /* Enable I/O & memory decoders, video in operational mode */
-  vgaw (cv64_regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
-  /* VGA color emulation, enable cpu access to display mem */ 
-  vgaw (cv64_regs, GREG_MISC_OUTPUT_W, 0x03);
-  /* Unlock S3 VGA regs */
-  WCrt (cv64_regs, CRT_ID_REGISTER_LOCK_1, 0x48); 
-  /* Unlock system control & extension registers */
-  WCrt (cv64_regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
+	/*
+	 * Generic (?) S3 chip wakeup
+	 */
+	/* Disable I/O & memory decoders, video in setup mode */
+	wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
+	/* Video responds to cmds, addrs & data */
+	wb_64 (regs, SREG_OPTION_SELECT, 0x1);
+	/* Enable I/O & memory decoders, video in operational mode */
+	wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
+	/* VGA color emulation, enable cpu access to display mem */ 
+	wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
+	/* Unlock S3 VGA regs */
+	WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48); 
+	/* Unlock system control & extension registers */
+	WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
 /* GRF - Enable interrupts */
-  /* Enable enhanced regs access, Ready cntl 0 wait states */
-  test = RCrt (cv64_regs, CRT_ID_SYSTEM_CONFIG);
-  test = test | 0x01;		/* enable enhaced register access */
-  test = test & 0xEF;		/* clear bit 4, 0 wait state */
-  WCrt (cv64_regs, CRT_ID_SYSTEM_CONFIG, test);
-  /*
-   * bit 0=1: Enable enhaced mode functions
-   * bit 2=0: Enhanced mode 8+ bits/pixel
-   * bit 4=1: Enable linear addressing
-   * bit 5=1: Enable MMIO
-   */
-  vgaw (cv64_regs, ECR_ADV_FUNC_CNTL, 0x31);
-  /*
-   * bit 0=1: Color emulation
-   * bit 1=1: Enable CPU access to display memory
-   * bit 5=1: Select high 64K memory page
-   */
+	/* Enable enhanced regs access, Ready cntl 0 wait states */
+	test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
+	test = test | 0x01;		/* enable enhanced register access */
+	test = test & 0xEF;		/* clear bit 4, 0 wait state */
+	WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
+	/*
+	 * bit 0=1: Enable enhaced mode functions
+	 * bit 2=0: Enhanced mode 8+ bits/pixel
+	 * bit 4=1: Enable linear addressing
+	 * bit 5=1: Enable MMIO
+	 */
+	wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
+	/*
+	 * bit 0=1: Color emulation
+	 * bit 1=1: Enable CPU access to display memory
+	 * bit 5=1: Select high 64K memory page
+	 */
 /* GRF - 0xE3 */
-  vgaw (cv64_regs, GREG_MISC_OUTPUT_W, 0x23);
+	wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
 	
-  /* Cpu base addr */
-  WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
+	/* Cpu base addr */
+	WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
 	
-  /* Reset. This does nothing on Trio, but standard VGA practice */
-  /* WSeq (cv64_regs, SEQ_ID_RESET, 0x03); */
-  /* Character clocks 8 dots wide */
-  WSeq (cv64_regs, SEQ_ID_CLOCKING_MODE, 0x01);
-  /* Enable cpu write to all color planes */
-  WSeq (cv64_regs, SEQ_ID_MAP_MASK, 0x0F);
-  /* Font table in 1st 8k of plane 2, font A=B disables swtich */
-  WSeq (cv64_regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
-  /* Allow mem access to 256kb */
-  WSeq (cv64_regs, SEQ_ID_MEMORY_MODE, 0x2);
-  /* Unlock S3 extensions to VGA Sequencer regs */
-  WSeq (cv64_regs, SEQ_ID_UNLOCK_EXT, 0x6);
-	
-  /* Enable 4MB fast page mode */
-  test = RSeq (cv64_regs, SEQ_ID_BUS_REQ_CNTL);
-  test = test | 1 << 6;
-  WSeq (cv64_regs, SEQ_ID_BUS_REQ_CNTL, test);
-	
-  /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
-  WSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
-	
-  /* Clear immediate clock load bit */
-  test = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2);
-  test = test & 0xDF;
-  /* If > 55MHz, enable 2 cycle memory write */
-  if (cv64_memclk >= 55000000) {
-    test |= 0x80;
-  }
-  WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, test);
+	/* Reset. This does nothing on Trio, but standard VGA practice */
+	/* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
+	/* Character clocks 8 dots wide */
+	WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
+	/* Enable cpu write to all color planes */
+	WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
+	/* Font table in 1st 8k of plane 2, font A=B disables swtich */
+	WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
+	/* Allow mem access to 256kb */
+	WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
+	/* Unlock S3 extensions to VGA Sequencer regs */
+	WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
+	
+	/* Enable 4MB fast page mode */
+	test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
+	test = test | 1 << 6;
+	WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
+	
+	/* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
+	WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
+
+	/* Clear immediate clock load bit */
+	test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+	test = test & 0xDF;
+	/* If > 55MHz, enable 2 cycle memory write */
+	if (cv64_memclk >= 55000000) {
+		test |= 0x80;
+	}
+	WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
+
+	/* Set MCLK value */
+	clockpar = cv64_compute_clock (cv64_memclk);
+	test = (clockpar & 0xFF00) >> 8;
+	WSeq (regs, SEQ_ID_MCLK_HI, test);
+	test = clockpar & 0xFF;
+	WSeq (regs, SEQ_ID_MCLK_LO, test);
+
+	/* Chip rev specific: Not in my Trio manual!!! */
+	if (RCrt (regs, CRT_ID_REVISION) == 0x10)
+		WSeq (regs, SEQ_ID_MORE_MAGIC, test);
+
+	/* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
+
+	/* Set DCLK value */
+	WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
+	WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
+
+	/* Load DCLK (and MCLK?) immediately */
+	test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
+	test = test | 0x22;
+	WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
+
+	/* Enable loading of DCLK */
+	test = rb_64(regs, GREG_MISC_OUTPUT_R);
+	test = test | 0x0C;
+	wb_64 (regs, GREG_MISC_OUTPUT_W, test);
+
+	/* Turn off immediate xCLK load */
+	WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
+
+	/* Horizontal character clock counts */
+	/* 8 LSB of 9 bits = total line - 5 */
+	WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
+	/* Active display line */
+	WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
+	/* Blank assertion start */
+	WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
+	/* Blank assertion end */
+	WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
+	/* HSYNC assertion start */
+	WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
+	/* HSYNC assertion end */
+	WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
+	WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
+	WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
+	WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
+	WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
+	WCrt (regs, CRT_ID_CURSOR_START, 0x00);
+	WCrt (regs, CRT_ID_CURSOR_END, 0x00);
+	WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
+	WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
+	WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
+	WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
+	WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
+	WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
+	WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
+	WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
+	WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
+	WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
+	WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
+	WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
+	WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
+	WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
+	WCrt (regs, CRT_ID_MISC_1, 0x35);
+	WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
+	WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
+	WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
+	WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
+
+	WGfx (regs, GCT_ID_SET_RESET, 0x0);
+	WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
+	WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
+	WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
+	WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
+	WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
+	WGfx (regs, GCT_ID_MISC, 0x01);
+	WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
+	WGfx (regs, GCT_ID_BITMASK, 0xFF);
+
+	/* Colors for text mode */
+	for (i = 0; i < 0xf; i++)
+		WAttr (regs, i, i);
+
+	WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
+	WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
+	WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
+	WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
+	WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
+
+	wb_64 (regs, VDAC_MASK, 0xFF);
+
+	*((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
+	*((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
+
+	/* Colors initially set to grayscale */
+
+	wb_64 (regs, VDAC_ADDRESS_W, 0);
+	for (i = 255; i >= 0; i--) {
+		wb_64(regs, VDAC_DATA, i);
+		wb_64(regs, VDAC_DATA, i);
+		wb_64(regs, VDAC_DATA, i);
+	}
+
+	/* GFx hardware cursor off */
+	WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
+
+	/* Set first to 4MB, so test will work */
+	WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
+	/* Find "correct" size of fbmem of Z3 board */
+	if (cv_has_4mb (CyberMem)) {
+		CyberSize = 1024 * 1024 * 4;
+		WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
+		DPRINTK("4MB board\n");
+	} else {
+		CyberSize = 1024 * 1024 * 2;
+		WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
+		DPRINTK("2MB board\n");
+	}
 
-  /* Set MCLK value */
-  clockpar = cv64_compute_clock (cv64_memclk);
-  test = (clockpar & 0xFF00) >> 8;
-  WSeq (cv64_regs, SEQ_ID_MCLK_HI, test);
-  test = clockpar & 0xFF;
-  WSeq (cv64_regs, SEQ_ID_MCLK_LO, test);
-
-  /* Chip rev specific: Not in my Trio manual!!! */
-  if (RCrt (cv64_regs, CRT_ID_REVISION) == 0x10)
-    WSeq (cv64_regs, SEQ_ID_MORE_MAGIC, test);
-	
-  /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
-
-  /* Set DCLK value */
-  WSeq (cv64_regs, SEQ_ID_DCLK_HI, 0x13);
-  WSeq (cv64_regs, SEQ_ID_DCLK_LO, 0x41);
-
-  /* Load DCLK (and MCLK?) immediately */
-  test = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2);
-  test = test | 0x22;
-  WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, test);
-
-  /* Enable loading of DCLK */
-  test = vgar (cv64_regs, GREG_MISC_OUTPUT_R);
-  test = test | 0x0C;
-  vgaw (cv64_regs, GREG_MISC_OUTPUT_W, test);
-
-  /* Turn off immediate xCLK load */
-  WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
-
-  /* Horizontal character clock counts */
-  /* 8 LSB of 9 bits = total line - 5 */
-  WCrt (cv64_regs, CRT_ID_HOR_TOTAL, 0x5F);
-  /* Active display line */
-  WCrt (cv64_regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
-  /* Blank assertion start */
-  WCrt (cv64_regs, CRT_ID_START_HOR_BLANK, 0x50);
-  /* Blank assertion end */
-  WCrt (cv64_regs, CRT_ID_END_HOR_BLANK, 0x82);
-  /* HSYNC assertion start */
-  WCrt (cv64_regs, CRT_ID_START_HOR_RETR, 0x54);
-  /* HSYNC assertion end */
-  WCrt (cv64_regs, CRT_ID_END_HOR_RETR, 0x80);
-  WCrt (cv64_regs, CRT_ID_VER_TOTAL, 0xBF);
-  WCrt (cv64_regs, CRT_ID_OVERFLOW, 0x1F);
-  WCrt (cv64_regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
-  WCrt (cv64_regs, CRT_ID_MAX_SCAN_LINE, 0x40);
-  WCrt (cv64_regs, CRT_ID_CURSOR_START, 0x00);
-  WCrt (cv64_regs, CRT_ID_CURSOR_END, 0x00);
-  WCrt (cv64_regs, CRT_ID_START_ADDR_HIGH, 0x00);
-  WCrt (cv64_regs, CRT_ID_START_ADDR_LOW, 0x00);
-  WCrt (cv64_regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
-  WCrt (cv64_regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
-  WCrt (cv64_regs, CRT_ID_START_VER_RETR, 0x9C);
-  WCrt (cv64_regs, CRT_ID_END_VER_RETR, 0x0E);
-  WCrt (cv64_regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
-  WCrt (cv64_regs, CRT_ID_SCREEN_OFFSET, 0x50);
-  WCrt (cv64_regs, CRT_ID_UNDERLINE_LOC, 0x00);
-  WCrt (cv64_regs, CRT_ID_START_VER_BLANK, 0x96);
-  WCrt (cv64_regs, CRT_ID_END_VER_BLANK, 0xB9);
-  WCrt (cv64_regs, CRT_ID_MODE_CONTROL, 0xE3);
-  WCrt (cv64_regs, CRT_ID_LINE_COMPARE, 0xFF);
-  WCrt (cv64_regs, CRT_ID_BACKWAD_COMP_3, 0x10);	/* FIFO enabled */
-  WCrt (cv64_regs, CRT_ID_MISC_1, 0x35);
-  WCrt (cv64_regs, CRT_ID_DISPLAY_FIFO, 0x5A);
-  WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
-  WCrt (cv64_regs, CRT_ID_LAW_POS_LO, 0x40);
-  WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
-  
-  WGfx (cv64_regs, GCT_ID_SET_RESET, 0x0);
-  WGfx (cv64_regs, GCT_ID_ENABLE_SET_RESET, 0x0);
-  WGfx (cv64_regs, GCT_ID_COLOR_COMPARE, 0x0);
-  WGfx (cv64_regs, GCT_ID_DATA_ROTATE, 0x0);
-  WGfx (cv64_regs, GCT_ID_READ_MAP_SELECT, 0x0);
-  WGfx (cv64_regs, GCT_ID_GRAPHICS_MODE, 0x40);
-  WGfx (cv64_regs, GCT_ID_MISC, 0x01);
-  WGfx (cv64_regs, GCT_ID_COLOR_XCARE, 0x0F);
-  WGfx (cv64_regs, GCT_ID_BITMASK, 0xFF);
-	
-  /* Colors for text mode */
-  for (i = 0; i < 0xf; i++)
-    WAttr (cv64_regs, i, i);
-	
-  WAttr (cv64_regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
-  WAttr (cv64_regs, ACT_ID_OVERSCAN_COLOR, 0x01);
-  WAttr (cv64_regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
-  WAttr (cv64_regs, ACT_ID_HOR_PEL_PANNING, 0x0);
-  WAttr (cv64_regs, ACT_ID_COLOR_SELECT, 0x0);
-	
-  vgaw (cv64_regs, VDAC_MASK, 0xFF);
-	
-  *((unsigned long *) (cv64_regs + ECR_FRGD_COLOR)) = 0xFF;
-  *((unsigned long *) (cv64_regs + ECR_BKGD_COLOR)) = 0;
-	
-  /* Colors initially set to grayscale */
-	
-  vgaw (cv64_regs, VDAC_ADDRESS_W, 0);
-  for (i = 255; i >= 0; i--) {
-    vgaw (cv64_regs, VDAC_DATA, i);
-    vgaw (cv64_regs, VDAC_DATA, i);
-    vgaw (cv64_regs, VDAC_DATA, i);
-  }
+	/* Initialize graphics engine */
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_FRGD_MIX, 0x27);
+	vgaw16 (regs, ECR_BKGD_MIX, 0x07);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
+	udelay(200);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
+	Cyber_WaitBlit();
+	udelay(200);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
+	Cyber_WaitBlit();
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
+	vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
+	vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+	vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
+	vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
+	vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
+	vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
+	vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
+	vgaw16 (regs, ECR_DRAW_CMD, 0x01);
 
-  /* GFx hardware cursor off */
-  WCrt (cv64_regs, CRT_ID_HWGC_MODE, 0x00);
+	Cyber_WaitBlit();
 
-  /* Set first to 4MB, so test will work */
-  WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x13);
-  /* Find "correct" size of fbmem of Z3 board */
-  if (cv_has_4mb ((volatile caddr_t) cv64_fbmem)) {
-    cv64_size = 1024 * 1024 * 4;
-    WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x13);
-    DPRINTK("4MB board\n");
-  } else {
-    cv64_size = 1024 * 1024 * 2;
-    WCrt (cv64_regs, CRT_ID_LAW_CNTL, 0x12);
-    DPRINTK("2MB board\n");
-  }
-	
-  /* Initialize graphics engine */
-  Cyber_WaitBlit();
-  /* GfxBusyWait (cv64_regs); */
-  vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x27);
-  vgaw16 (cv64_regs, ECR_BKGD_MIX, 0x07);
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x1000);
-  udelay(200);
-  /* __cv_delay (200000); */
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x2000);
-  Cyber_WaitBlit();
-  /* GfxBusyWait (cv64_regs); */
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x3FFF);
-  Cyber_WaitBlit();
-  /* GfxBusyWait (cv64_regs); */
-  udelay(200);
-  /* __cv_delay (200000); */
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x4FFF);
-  Cyber_WaitBlit();
-  /* GfxBusyWait (cv64_regs); */
-  vgaw16 (cv64_regs, ECR_BITPLANE_WRITE_MASK, ~0);
-  Cyber_WaitBlit();
-  /* GfxBusyWait (cv64_regs); */
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xE000);
-  vgaw16 (cv64_regs, ECR_CURRENT_Y_POS2, 0x00);
-  vgaw16 (cv64_regs, ECR_CURRENT_X_POS2, 0x00);
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000);
-  vgaw16 (cv64_regs, ECR_DEST_Y__AX_STEP, 0x00);
-  vgaw16 (cv64_regs, ECR_DEST_Y2__AX_STEP2, 0x00);
-  vgaw16 (cv64_regs, ECR_DEST_X__DIA_STEP, 0x00);
-  vgaw16 (cv64_regs, ECR_DEST_X2__DIA_STEP2, 0x00);
-  vgaw16 (cv64_regs, ECR_SHORT_STROKE, 0x00);
-  vgaw16 (cv64_regs, ECR_DRAW_CMD, 0x01);
-	
-  Cyber_WaitBlit();
-  /* GfxBusyWait (cv64_regs); */
-	
-  vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0x4FFF);
-  vgaw16 (cv64_regs, ECR_BKGD_COLOR, 0x01);
-  vgaw16 (cv64_regs, ECR_FRGD_COLOR, 0x00);
-	
-	
-  /* Enable video display (set bit 5) */
+	vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
+	vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
+	vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
+
+
+	/* Enable video display (set bit 5) */
 /* ARB - Would also seem to write to AR13.
  *       May want to use parts of WAttr to set JUST bit 5
  */
-  WAttr (cv64_regs, 0x33, 0);
+	WAttr (regs, 0x33, 0);
 	
 /* GRF - function code ended here */
 
-  /* Turn gfx on again */
-  gfx_on_off (0, cv64_regs);
-	
-  /* Pass-through */
-  cvscreen (0, (volatile unsigned char *) cv64_mem);
+	/* Turn gfx on again */
+	gfx_on_off (0, regs);
 
-  DPRINTK("EXIT\n");
+	/* Pass-through */
+	cvscreen (0, CyberBase);
+
+	DPRINTK("EXIT\n");
 }
 
 static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
 {
+  volatile unsigned char *regs = CyberRegs;
   int fx, fy;
   unsigned short mnr;
   unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
@@ -1977,7 +1901,7 @@
 
 /* GRF - Disable interrupts */	
 	
-  gfx_on_off (1, cv64_regs);
+  gfx_on_off (1, regs);
 	
   switch (video_mode->bits_per_pixel) {
   case 15:
@@ -2049,7 +1973,7 @@
     VT  = yres + vfront + vsync + vback - 2;
   }
 
-  vgaw (cv64_regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
+  wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
 	
   if (TEXT)
     HDE = ((video_mode->xres + fx - 1) / fx) - 1;
@@ -2058,15 +1982,15 @@
 	
   VDE = video_mode->yres - 1;
 
-  WCrt (cv64_regs, CRT_ID_HWGC_MODE, 0x00);
-  WCrt (cv64_regs, CRT_ID_EXT_DAC_CNTL, 0x00);
+  WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
+  WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
 	
-  WSeq (cv64_regs, SEQ_ID_MEMORY_MODE,
+  WSeq (regs, SEQ_ID_MEMORY_MODE,
 	(TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
-  WGfx (cv64_regs, GCT_ID_READ_MAP_SELECT, 0x00);
-  WSeq (cv64_regs, SEQ_ID_MAP_MASK,
+  WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
+  WSeq (regs, SEQ_ID_MAP_MASK,
 	(video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
-  WSeq (cv64_regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
+  WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
 	
   /* cv64_compute_clock accepts arguments in Hz */
   /* pixclock is in ps ... convert to Hz */
@@ -2081,11 +2005,11 @@
 #endif
 
   mnr = cv64_compute_clock (freq);
-  WSeq (cv64_regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
-  WSeq (cv64_regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
+  WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
+  WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
 	
   /* Load display parameters into board */
-  WCrt (cv64_regs, CRT_ID_EXT_HOR_OVF,
+  WCrt (regs, CRT_ID_EXT_HOR_OVF,
 	((HT & 0x100) ? 0x01 : 0x00) |
 	((HDE & 0x100) ? 0x02 : 0x00) |
 	((HBS & 0x100) ? 0x04 : 0x00) |
@@ -2095,7 +2019,7 @@
 	(((HT-5) & 0x100) ? 0x40 : 0x00)
 	);
 	
-  WCrt (cv64_regs, CRT_ID_EXT_VER_OVF,
+  WCrt (regs, CRT_ID_EXT_VER_OVF,
 	0x40 |
 	((VT & 0x400) ? 0x01 : 0x00) |
 	((VDE & 0x400) ? 0x02 : 0x00) |
@@ -2103,18 +2027,18 @@
 	((VSS & 0x400) ? 0x10 : 0x00)
 	);
 	
-  WCrt (cv64_regs, CRT_ID_HOR_TOTAL, HT);
-  WCrt (cv64_regs, CRT_ID_DISPLAY_FIFO, HT - 5);
-  WCrt (cv64_regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
-  WCrt (cv64_regs, CRT_ID_START_HOR_BLANK, HBS);
-  WCrt (cv64_regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
-  WCrt (cv64_regs, CRT_ID_START_HOR_RETR, HSS);
-  WCrt (cv64_regs, CRT_ID_END_HOR_RETR,
+  WCrt (regs, CRT_ID_HOR_TOTAL, HT);
+  WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
+  WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
+  WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
+  WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
+  WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
+  WCrt (regs, CRT_ID_END_HOR_RETR,
 	(HSE & 0x1F) |
 	((HBE & 0x20) ? 0x80 : 0x00)
 	);
-  WCrt (cv64_regs, CRT_ID_VER_TOTAL, VT);
-  WCrt (cv64_regs, CRT_ID_OVERFLOW,
+  WCrt (regs, CRT_ID_VER_TOTAL, VT);
+  WCrt (regs, CRT_ID_OVERFLOW,
 	0x10 |
 	((VT & 0x100) ? 0x01 : 0x00) |
 	((VDE & 0x100) ? 0x02 : 0x00) |
@@ -2124,65 +2048,65 @@
 	((VDE & 0x200) ? 0x40 : 0x00) |
 	((VSS & 0x200) ? 0x80 : 0x00)
 	);
-  WCrt (cv64_regs, CRT_ID_MAX_SCAN_LINE,
+  WCrt (regs, CRT_ID_MAX_SCAN_LINE,
 	0x40 |
 	(DBLSCAN ? 0x80 : 0x00) |
 	((VBS & 0x200) ? 0x20 : 0x00) |
 	(TEXT ? ((fy - 1) & 0x1F) : 0x00)
 	);
 	
-  WCrt (cv64_regs, CRT_ID_MODE_CONTROL, 0xE3);
+  WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
 
   /* Text cursor */
 	
   if (TEXT) {
 #if 1
-    WCrt (cv64_regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
-    WCrt (cv64_regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
+    WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
+    WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
 #else
-    WCrt (cv64_regs, CRT_ID_CURSOR_START, 0x00);
-    WCrt (cv64_regs, CRT_ID_CURSOR_END, fy & 0x1F);
+    WCrt (regs, CRT_ID_CURSOR_START, 0x00);
+    WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
 #endif
-    WCrt (cv64_regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
-    WCrt (cv64_regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
-    WCrt (cv64_regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
+    WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
+    WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
+    WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
   }
 	
-  WCrt (cv64_regs, CRT_ID_START_ADDR_HIGH, 0x00);
-  WCrt (cv64_regs, CRT_ID_START_ADDR_LOW, 0x00);
-  WCrt (cv64_regs, CRT_ID_START_VER_RETR, VSS);
-  WCrt (cv64_regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
-  WCrt (cv64_regs, CRT_ID_VER_DISP_ENA_END, VDE);
-  WCrt (cv64_regs, CRT_ID_START_VER_BLANK, VBS);
-  WCrt (cv64_regs, CRT_ID_END_VER_BLANK, VBE);
-  WCrt (cv64_regs, CRT_ID_LINE_COMPARE, 0xFF);
-  WCrt (cv64_regs, CRT_ID_LACE_RETR_START, HT / 2);
-  WCrt (cv64_regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
-  WGfx (cv64_regs, GCT_ID_GRAPHICS_MODE,
+  WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
+  WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
+  WCrt (regs, CRT_ID_START_VER_RETR, VSS);
+  WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
+  WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
+  WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
+  WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
+  WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
+  WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
+  WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
+  WGfx (regs, GCT_ID_GRAPHICS_MODE,
 	((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
-  WGfx (cv64_regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
-  WSeq (cv64_regs, SEQ_ID_MEMORY_MODE,
+  WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
+  WSeq (regs, SEQ_ID_MEMORY_MODE,
 	((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
 	
-  vgaw (cv64_regs, VDAC_MASK, 0xFF);
+  wb_64 (regs, VDAC_MASK, 0xFF);
 	
   /* Blank border */
-  test = RCrt (cv64_regs, CRT_ID_BACKWAD_COMP_2);
-  WCrt (cv64_regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
+  test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
+  WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
 	
-  sr15 = RSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2);
+  sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
   sr15 &= 0xEF;
-  sr18 = RSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL);
+  sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
   sr18 &= 0x7F;
   clock_mode = 0x00;
   cr50 = 0x00;
 	
-  test = RCrt (cv64_regs, CRT_ID_EXT_MISC_CNTL_2);
+  test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
   test &= 0xD;
 	
   /* Clear roxxler byte-swapping... */
-  cv64_write_port (0x0040, (volatile unsigned char *) cv64_mem);
-  cv64_write_port (0x0020, (volatile unsigned char *) cv64_mem);
+  cv64_write_port (0x0040, CyberBase);
+  cv64_write_port (0x0020, CyberBase);
 	
   switch (video_mode->bits_per_pixel) {
   case 1:
@@ -2201,14 +2125,14 @@
     break;
 		
   case 15:
-    cv64_write_port (0x8020, (volatile unsigned char *) cv64_mem);
+    cv64_write_port (0x8020, CyberBase);
     clock_mode = 0x30;
     HDE = video_mode->xres / 4;
     cr50 |= 0x10;
     break;
 		
   case 16:
-    cv64_write_port (0x8020, (volatile unsigned char *) cv64_mem);
+    cv64_write_port (0x8020, CyberBase);
     clock_mode = 0x50;
     HDE = video_mode->xres / 4;
     cr50 |= 0x10;
@@ -2216,24 +2140,24 @@
 		
   case 24:
   case 32:
-    cv64_write_port (0x8040, (volatile unsigned char *) cv64_mem);
+    cv64_write_port (0x8040, CyberBase);
     clock_mode = 0xD0;
     HDE = video_mode->xres / 2;
     cr50 |= 0x30;
     break;
   }
-	
-  WCrt (cv64_regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
-  WSeq (cv64_regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
-  WSeq (cv64_regs, SEQ_ID_RAMDAC_CNTL, sr18);
-  WCrt (cv64_regs, CRT_ID_SCREEN_OFFSET, HDE);
 
-  WCrt (cv64_regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
+  WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
+  WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
+  WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
+  WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
+
+  WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
 	
-  test = RCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_2);
+  test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
   test &= ~0x30;
   test |= (HDE >> 4) & 0x30;
-  WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_2, test);
+  WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
 	
   /* Set up graphics engine */
   switch (video_mode->xres) {
@@ -2265,17 +2189,14 @@
     break;
   }
 	
-  WCrt (cv64_regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
+  WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
 	
   udelay(100);
-  /* __cv_delay (100000); */
-  WAttr (cv64_regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
+  WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
   udelay(100);
-  /* __cv_delay (100000); */
-  WAttr (cv64_regs, ACT_ID_COLOR_PLANE_ENA,
+  WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
 	 (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
   udelay(100);
-  /* __cv_delay (100000); */
 	
   tfillm = (96 * (cv64_memclk / 1000)) / 240000;
 	
@@ -2304,10 +2225,9 @@
     m = 0x18;
   n = 0xFF;
 	
-  WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_2, m);
-  WCrt (cv64_regs, CRT_ID_EXT_MEM_CNTL_3, n);
+  WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
+  WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
   udelay(10);
-  /* __cv_delay (10000); */
 	
   /* Text initialization */
 	
@@ -2317,21 +2237,21 @@
 	
   if (CONSOLE) {
     int i;
-    vgaw (cv64_regs, VDAC_ADDRESS_W, 0);
+    wb_64 (regs, VDAC_ADDRESS_W, 0);
     for (i = 0; i < 4; i++) {
-      vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][0]);
-      vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][1]);
-      vgaw (cv64_regs, VDAC_DATA, cvconscolors [i][2]);
+      wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
+      wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
+      wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
     }
   }
 	
-  WAttr (cv64_regs, 0x33, 0);
+  WAttr (regs, 0x33, 0);
 	
   /* Turn gfx on again */
-  gfx_on_off (0, (volatile unsigned char *) cv64_regs);
+  gfx_on_off (0, (volatile unsigned char *) regs);
 	
   /* Pass-through */
-  cvscreen (0, (volatile unsigned char *) cv64_mem);
+  cvscreen (0, CyberBase);
 
 DPRINTK("EXIT\n");
 }
@@ -2339,6 +2259,7 @@
 void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
 		     u_short w, u_short h)
 {
+	volatile unsigned char *regs = CyberRegs;
 	unsigned short drawdir = 0;
 	
 	DPRINTK("ENTER\n");
@@ -2357,37 +2278,36 @@
 	}
 	
 	Cyber_WaitBlit();
-	/* GfxBusyWait (cv64_regs); */
-	vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000);
-	vgaw16 (cv64_regs, ECR_BKGD_MIX, 0x7);
-	vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x67);
-	vgaw16 (cv64_regs, ECR_BKGD_COLOR, 0x0);
-	vgaw16 (cv64_regs, ECR_FRGD_COLOR, 0x1);
-	vgaw16 (cv64_regs, ECR_BITPLANE_READ_MASK, 0x1);
-	vgaw16 (cv64_regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
-	vgaw16 (cv64_regs, ECR_CURRENT_Y_POS, sy);
-	vgaw16 (cv64_regs, ECR_CURRENT_X_POS, sx);
-	vgaw16 (cv64_regs, ECR_DEST_Y__AX_STEP, dy);
-	vgaw16 (cv64_regs, ECR_DEST_X__DIA_STEP, dx);
-	vgaw16 (cv64_regs, ECR_READ_REG_DATA, h - 1);
-	vgaw16 (cv64_regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
-	vgaw16 (cv64_regs, ECR_DRAW_CMD, 0xC051 | drawdir);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+	vgaw16 (regs, ECR_BKGD_MIX, 0x7);
+	vgaw16 (regs, ECR_FRGD_MIX, 0x67);
+	vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
+	vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
+	vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
+	vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
+	vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
+	vgaw16 (regs, ECR_CURRENT_X_POS, sx);
+	vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
+	vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
+	vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
+	vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
+	vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
 	DPRINTK("EXIT\n");
 }
 
 void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
 {
+	volatile unsigned char *regs = CyberRegs;
 	DPRINTK("ENTER\n");
 	Cyber_WaitBlit();
-	/* GfxBusyWait (cv64_regs); */
-	vgaw16 (cv64_regs, ECR_FRGD_MIX, 0x0027);
-	vgaw16 (cv64_regs, ECR_FRGD_COLOR, bg);
-	vgaw16 (cv64_regs, ECR_READ_REG_DATA, 0xA000);
-	vgaw16 (cv64_regs, ECR_CURRENT_Y_POS, dy);
-	vgaw16 (cv64_regs, ECR_CURRENT_X_POS, dx);
-	vgaw16 (cv64_regs, ECR_READ_REG_DATA, h - 1);
-	vgaw16 (cv64_regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
-	vgaw16 (cv64_regs, ECR_DRAW_CMD, 0x40B1);	
+	vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
+	vgaw16 (regs, ECR_FRGD_COLOR, bg);
+	vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
+	vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
+	vgaw16 (regs, ECR_CURRENT_X_POS, dx);
+	vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
+	vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
+	vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);	
 	DPRINTK("EXIT\n");
 }
 
@@ -2397,83 +2317,84 @@
  */
 static void cv64_dump (void)
 {
+	volatile unsigned char *regs = CyberRegs;
 	DPRINTK("ENTER\n");
         /* Dump the VGA setup values */
-	*(CyberRegs + S3_CRTC_ADR) = 0x00;
-	DPRINTK("CR00 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x01;
-	DPRINTK("CR01 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x02;
-	DPRINTK("CR02 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x03;
-	DPRINTK("CR03 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x04;
-	DPRINTK("CR04 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x05;
-	DPRINTK("CR05 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x06;
-	DPRINTK("CR06 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x07;
-	DPRINTK("CR07 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x08;
-	DPRINTK("CR08 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x09;
-	DPRINTK("CR09 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x10;
-	DPRINTK("CR10 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x11;
-	DPRINTK("CR11 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x12;
-	DPRINTK("CR12 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x13;
-	DPRINTK("CR13 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x15;
-	DPRINTK("CR15 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x16;
-	DPRINTK("CR16 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x36;
-	DPRINTK("CR36 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x37;
-	DPRINTK("CR37 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x42;
-	DPRINTK("CR42 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x43;
-	DPRINTK("CR43 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x50;
-	DPRINTK("CR50 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x51;
-	DPRINTK("CR51 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x53;
-	DPRINTK("CR53 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x58;
-	DPRINTK("CR58 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x59;
-	DPRINTK("CR59 = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x5A;
-	DPRINTK("CR5A = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x5D;
-	DPRINTK("CR5D = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	*(CyberRegs + S3_CRTC_ADR) = 0x5E;
-	DPRINTK("CR5E = %x\n", *(CyberRegs + S3_CRTC_DATA));
-	DPRINTK("MISC = %x\n", *(CyberRegs + GREG_MISC_OUTPUT_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x01;
-	DPRINTK("SR01 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x02;
-	DPRINTK("SR02 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x03;
-	DPRINTK("SR03 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x09;
-	DPRINTK("SR09 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x10;
-	DPRINTK("SR10 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x11;
-	DPRINTK("SR11 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x12;
-	DPRINTK("SR12 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x13;
-	DPRINTK("SR13 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
-	*(CyberRegs + SEQ_ADDRESS) = 0x15;
-	DPRINTK("SR15 = %x\n", *(CyberRegs + SEQ_ADDRESS_R));
+	*(regs + S3_CRTC_ADR) = 0x00;
+	DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x01;
+	DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x02;
+	DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x03;
+	DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x04;
+	DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x05;
+	DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x06;
+	DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x07;
+	DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x08;
+	DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x09;
+	DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x10;
+	DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x11;
+	DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x12;
+	DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x13;
+	DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x15;
+	DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x16;
+	DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x36;
+	DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x37;
+	DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x42;
+	DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x43;
+	DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x50;
+	DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x51;
+	DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x53;
+	DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x58;
+	DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x59;
+	DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x5A;
+	DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x5D;
+	DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
+	*(regs + S3_CRTC_ADR) = 0x5E;
+	DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
+	DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
+	*(regs + SEQ_ADDRESS) = 0x01;
+	DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x02;
+	DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x03;
+	DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x09;
+	DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x10;
+	DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x11;
+	DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x12;
+	DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x13;
+	DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
+	*(regs + SEQ_ADDRESS) = 0x15;
+	DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
 	
 	return;
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/video/cyberfb.h linux/drivers/video/cyberfb.h
--- v2.3.12/linux/drivers/video/cyberfb.h	Mon Dec 21 14:48:04 1998
+++ linux/drivers/video/cyberfb.h	Mon Aug  9 11:39:38 1999
@@ -128,26 +128,9 @@
 #define GRFBBOPset		0xf	/* 1 */
 
 
-/* Read VGA register */
-#define vgar(ba, reg) (*(((volatile caddr_t)ba)+reg))
-
-/* Write VGA register */
-#define vgaw(ba, reg, val) \
-*(((volatile caddr_t)ba)+reg) = ((val) & 0xff)
-
-/* Read 16 Bit VGA register */
-#define vgar16(ba, reg) (  *((unsigned short *) (((volatile caddr_t)ba)+reg)) )
-
 /* Write 16 Bit VGA register */
 #define vgaw16(ba, reg, val) \
-*((unsigned short *)  (((volatile caddr_t)ba)+reg)) = val
-
-/* Read 32 Bit VGA register */
-#define vgar32(ba, reg) (  *((unsigned long *) (((volatile caddr_t)ba)+reg)) )
-
-/* Write 32 Bit VGA register */
-#define vgaw32(ba, reg, val) \
-     *((unsigned long *)  (((volatile caddr_t)ba)+reg)) = val
+*((unsigned short *)  (((volatile unsigned char *)ba)+reg)) = val
 
 /*
  * Defines for the used register addresses (mw)
@@ -394,20 +377,20 @@
 
 
 #define WGfx(ba, idx, val) \
-do { vgaw(ba, GCT_ADDRESS, idx); vgaw(ba, GCT_ADDRESS_W , val); } while (0)
+do { wb_64(ba, GCT_ADDRESS, idx); wb_64(ba, GCT_ADDRESS_W , val); } while (0)
 
 #define WSeq(ba, idx, val) \
-do { vgaw(ba, SEQ_ADDRESS, idx); vgaw(ba, SEQ_ADDRESS_W , val); } while (0)
+do { wb_64(ba, SEQ_ADDRESS, idx); wb_64(ba, SEQ_ADDRESS_W , val); } while (0)
 
 #define WCrt(ba, idx, val) \
-do { vgaw(ba, CRT_ADDRESS, idx); vgaw(ba, CRT_ADDRESS_W , val); } while (0)
+do { wb_64(ba, CRT_ADDRESS, idx); wb_64(ba, CRT_ADDRESS_W , val); } while (0)
 
 #define WAttr(ba, idx, val) \
 do { \
   unsigned char tmp;\
-  tmp = vgar(ba, ACT_ADDRESS_RESET);\
-  vgaw(ba, ACT_ADDRESS_W, idx);\
-  vgaw(ba, ACT_ADDRESS_W, val);\
+  tmp = rb_64(ba, ACT_ADDRESS_RESET);\
+  wb_64(ba, ACT_ADDRESS_W, idx);\
+  wb_64(ba, ACT_ADDRESS_W, val);\
 } while (0)
 
 #define SetTextPlane(ba, m) \
@@ -420,21 +403,17 @@
      /* prototypes                        */
      /* --------------------------------- */
 
-/* in cvision_core.c */
-inline void __cv_delay(unsigned long usecs);
-inline void GfxBusyWait(volatile caddr_t board);
-inline void GfxFifoWait(volatile caddr_t board);
-inline unsigned char RAttr(volatile caddr_t board, short idx);
-inline unsigned char RSeq(volatile caddr_t board, short idx);
-inline unsigned char RCrt(volatile caddr_t board, short idx);
-inline unsigned char RGfx(volatile caddr_t board, short idx);
+inline unsigned char RAttr(volatile unsigned char * board, short idx);
+inline unsigned char RSeq(volatile unsigned char * board, short idx);
+inline unsigned char RCrt(volatile unsigned char * board, short idx);
+inline unsigned char RGfx(volatile unsigned char * board, short idx);
 inline void cv64_write_port(unsigned short bits,
 			    volatile unsigned char *board);
 inline void cvscreen(int toggle, volatile unsigned char *board);
 inline void gfx_on_off(int toggle, volatile unsigned char *board);
 #if 0
 unsigned short cv64_compute_clock(unsigned long freq);
-int cv_has_4mb(volatile caddr_t fb);
+int cv_has_4mb(volatile unsigned char * fb);
 void cv64_board_init(void);
 void cv64_load_video_mode(struct fb_var_screeninfo *video_mode);
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/video/dummycon.c linux/drivers/video/dummycon.c
--- v2.3.12/linux/drivers/video/dummycon.c	Tue May 11 16:30:45 1999
+++ linux/drivers/video/dummycon.c	Mon Aug  9 10:25:01 1999
@@ -25,7 +25,7 @@
 #define DUMMY_ROWS	25
 #endif
 
-__initfunc(static const char *dummycon_startup(void))
+static const char __init *dummycon_startup(void)
 {
     return "dummy device";
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.3.12/linux/drivers/video/fbcon.c	Fri May 14 12:49:28 1999
+++ linux/drivers/video/fbcon.c	Mon Aug  9 11:38:10 1999
@@ -215,7 +215,7 @@
 
 #ifdef CONFIG_MAC
 /*
- * On the Macintoy, there may or may not be a working VBL int. We need to prob
+ * On the Macintoy, there may or may not be a working VBL int. We need to probe
  */
 static int vbl_detected = 0;
 
@@ -1951,7 +1951,7 @@
     return n<0 ? d>>-n : d<<n;
 }
 
-__initfunc(static int fbcon_show_logo( void ))
+static int __init fbcon_show_logo( void )
 {
     struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
     int depth = p->var.bits_per_pixel;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.12/linux/drivers/video/fbmem.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/video/fbmem.c	Mon Aug  9 10:25:01 1999
@@ -619,8 +619,8 @@
 
 static struct proc_dir_entry *proc_fbmem;
 
-__initfunc(void
-fbmem_init(void))
+void __init 
+fbmem_init(void)
 {
 	int i;
 
@@ -679,7 +679,7 @@
      *  Command line options
      */
 
-__initfunc(void video_setup(char *options, int *ints))
+void __init video_setup(char *options, int *ints)
 {
     int i, j;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c
--- v2.3.12/linux/drivers/video/fm2fb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/fm2fb.c	Mon Aug  9 10:25:01 1999
@@ -374,7 +374,7 @@
      *  Initialisation
      */
 
-__initfunc(void fm2fb_init(void))
+void __init fm2fb_init(void)
 {
     int key, is_fm;
     const struct ConfigDev *cd  = NULL;
@@ -466,7 +466,7 @@
 	   fb_fix.id);
 }
 
-__initfunc(void fm2fb_setup(char *options, int *ints))
+void __init fm2fb_setup(char *options, int *ints)
 {
     char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/g364fb.c linux/drivers/video/g364fb.c
--- v2.3.12/linux/drivers/video/g364fb.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/video/g364fb.c	Mon Aug  9 10:25:01 1999
@@ -297,7 +297,7 @@
 /*
  *  Initialisation
  */
-__initfunc(void g364fb_init(void))
+void __init g364fb_init(void)
 {
     int i,j;
     volatile unsigned int *pal_ptr = (volatile unsigned int *) CLR_PAL_REG;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/hpfb.c linux/drivers/video/hpfb.c
--- v2.3.12/linux/drivers/video/hpfb.c	Thu Oct  1 10:02:21 1998
+++ linux/drivers/video/hpfb.c	Mon Aug  9 10:25:01 1999
@@ -301,7 +301,7 @@
 #define TOPCAT_FBOMSB	0x5d
 #define TOPCAT_FBOLSB	0x5f
 
-__initfunc(int hpfb_init_one(unsigned long base))
+int __init hpfb_init_one(unsigned long base)
 {
 	unsigned long fboff;
 
@@ -384,7 +384,7 @@
  * Initialise the framebuffer
  */
 
-__initfunc(unsigned long hpfb_init(unsigned long mem_start))
+unsigned long __init hpfb_init(unsigned long mem_start)
 {
 	unsigned int sid;
 
@@ -424,6 +424,6 @@
 	return mem_start;
 }
 
-__initfunc(void hpfb_setup(char *options, int *ints))
+void __init hpfb_setup(char *options, int *ints)
 {
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
--- v2.3.12/linux/drivers/video/igafb.c	Wed Jun  9 14:44:26 1999
+++ linux/drivers/video/igafb.c	Mon Aug  9 10:25:01 1999
@@ -559,7 +559,7 @@
 }
 
 
-__initfunc(static int iga_init(struct fb_info_iga *info))
+static int __init iga_init(struct fb_info_iga *info)
 {
         char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
 		                                         & MEM_SIZE_ALIAS;
@@ -624,7 +624,7 @@
 }	
 
 
-__initfunc(void igafb_init(void))
+void __init igafb_init(void)
 {
         struct pci_dev *pdev;
         struct fb_info_iga *info;
@@ -777,7 +777,7 @@
 #endif /* __sparc__ */
 }
 
-__initfunc(void igafb_setup(char *options, int *ints))
+void __init igafb_setup(char *options, int *ints)
 {
     char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- v2.3.12/linux/drivers/video/imsttfb.c	Mon Dec 21 14:48:04 1998
+++ linux/drivers/video/imsttfb.c	Mon Aug  9 10:25:01 1999
@@ -967,8 +967,8 @@
 	add_timer(&c->timer);
 }
 
-__initfunc(static void
-imstt_cursor_init (struct fb_info_imstt *p))
+static void __init 
+imstt_cursor_init (struct fb_info_imstt *p)
 {
 	struct imstt_cursor *c = &p->cursor;
 
@@ -1728,8 +1728,8 @@
 	out_le32(&p->dc_regs[STGCTL], ctrl);
 }
 
-__initfunc(static void
-init_imstt(struct fb_info_imstt *p))
+static void __init 
+init_imstt(struct fb_info_imstt *p)
 {
 	__u32 i, tmp;
 	__u32 *ip, *end;
@@ -1802,7 +1802,7 @@
 	p->fix.smem_start = (__u8 *)p->frame_buffer_phys;
 	p->fix.smem_len = p->total_vram;
 	p->fix.mmio_start = (__u8 *)p->dc_regs_phys;
-	p->fix.mmio_len = 0x40000;
+	p->fix.mmio_len = 0x1000;
 	p->fix.accel = FB_ACCEL_IMS_TWINTURBO;
 	p->fix.type = FB_TYPE_PACKED_PIXELS;
 	p->fix.visual = p->disp.var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
@@ -1868,8 +1868,8 @@
 }
 
 #if defined(CONFIG_FB_OF) && !defined(MODULE)
-__initfunc(void
-imsttfb_of_init(struct device_node *dp))
+void __init 
+imsttfb_of_init(struct device_node *dp)
 {
 	struct fb_info_imstt *p;
 	int i;
@@ -1912,8 +1912,8 @@
 }
 #endif
 
-__initfunc(void
-imsttfb_init(void))
+void __init 
+imsttfb_init(void)
 {
 #if defined(CONFIG_FB_OF) && !defined(MODULE)
 	/* We don't want to be called like this. */
@@ -1969,8 +1969,8 @@
 }
 
 #ifndef MODULE
-__initfunc(void
-imsttfb_setup(char *options, int *ints))
+void __init 
+imsttfb_setup(char *options, int *ints)
 {
 	char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/macfb.c linux/drivers/video/macfb.c
--- v2.3.12/linux/drivers/video/macfb.c	Mon Dec 21 14:48:04 1998
+++ linux/drivers/video/macfb.c	Mon Aug  9 10:25:01 1999
@@ -512,7 +512,7 @@
 	NULL
 };
 
-__initfunc(void macfb_init(void))
+void __init macfb_init(void)
 {
 	/* nubus_remap the video .. */
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
--- v2.3.12/linux/drivers/video/matroxfb.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/video/matroxfb.c	Mon Aug  9 11:56:26 1999
@@ -1,10 +1,10 @@
 /*
  *
- * Hardware accelerated Matrox Millennium I, II, Mystique and G200
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
  * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.15 1999/04/19
+ * Version: 1.19 1999/08/05
  *
  * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
  *
@@ -14,8 +14,8 @@
  *               "Kurt Garloff" <garloff@kg1.ping.de>
  *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
  *
- *               "Tom Rini" <tmrini@ntplx.net>
- *                     MTRR stuff, betatesting, fixes, ideas
+ *               "Tom Rini" <trini@disparity.net>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
  *
  *               "Bibek Sahu" <scorpio@dodds.net>
  *                     Access device through readb|w|l and write b|w|l
@@ -60,6 +60,9 @@
  *               "Cort Dougan" <cort@cs.nmt.edu>
  *                     CHRP fixes and PReP cleanup
  *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -87,6 +90,11 @@
 /* Debug register calls, too? */
 #undef MATROXFB_DEBUG_REG
 
+/* Log reentrancy attempts - you must have printstate() patch applied */
+#undef MATROXFB_DEBUG_REENTER
+/* you must define DEBUG_REENTER to get debugged CONSOLEBH... */
+#undef MATROXFB_DEBUG_CONSOLEBH
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -127,12 +135,15 @@
 #include <video/macmodes.h>
 #endif
 
+/* always compile support for 32MB... It cost almost nothing */
+#define CONFIG_FB_MATROX_32MB
+
 #define FBCON_HAS_VGATEXT
 
 #ifdef MATROXFB_DEBUG
 
 #define DEBUG
-#define DBG(x)		printk("matroxfb: %s\n", (x));
+#define DBG(x)		printk(KERN_DEBUG "matroxfb: %s\n", (x));
 
 #ifdef MATROXFB_DEBUG_HEAVY
 #define DBG_HEAVY(x)	DBG(x)
@@ -217,6 +228,9 @@
 #ifndef PCI_DEVICE_ID_MATROX_G100_AGP
 #define PCI_DEVICE_ID_MATROX_G100_AGP	0x1001
 #endif
+#ifndef PCI_DEVICE_ID_MATROX_G400_AGP
+#define PCI_DEVICE_ID_MATROX_G400_AGP	0x0525
+#endif
 
 #ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
 #define PCI_SS_ID_MATROX_GENERIC		0xFF00
@@ -422,7 +436,7 @@
 	unsigned char	MiscOutReg;
 	unsigned char	DACpal[768];
 	unsigned char	CRTC[25];
-	unsigned char	CRTCEXT[6];
+	unsigned char	CRTCEXT[9];
 	unsigned char	SEQ[5];
 	/* unused for MGA mode, but who knows... */
 	unsigned char	GCTL[9];
@@ -453,7 +467,8 @@
 }
 
 #define PMXINFO(p) mxinfo(p),
-#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+#define MINFO_FROM(x)	   struct matrox_fb_info* minfo = x
+#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
 
 #else
 
@@ -476,6 +491,7 @@
 #endif
 
 #define PMXINFO(p)
+#define MINFO_FROM(x)
 #define MINFO_FROM_DISP(x)
 
 #endif
@@ -563,6 +579,9 @@
 		int		hwcursor;
 		int		blink;
 		int		sgram;
+#ifdef CONFIG_FB_MATROX_32MB
+		int		support32MB;
+#endif
 
 		int		accelerator;
 		int		text_type_aux;
@@ -609,6 +628,8 @@
 #if defined(CONFIG_FB_OF)
 unsigned char nvram_read_byte(int);
 int matrox_of_init(struct device_node *dp);
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
 #endif
 
 #define curr_ydstorg(x)	ACCESS_FBINFO2(x, curr.ydstorg.pixels)
@@ -678,6 +699,8 @@
 
 #define M_RESET		0x1E40
 
+#define M_AGP2PLL	0x1E4C
+
 #define M_OPMODE	0x1E54
 #define     M_OPMODE_DMA_GEN_WRITE	0x00
 #define     M_OPMODE_DMA_BLIT		0x04
@@ -713,6 +736,9 @@
 #define M_EXTVGA_INDEX	0x1FDE
 #define M_EXTVGA_DATA	0x1FDF
 
+/* G200 only */
+#define M_SRCORG	0x2CB4
+
 #define M_RAMDAC_BASE	0x3C00
 
 /* fortunately, same on TVP3026 and MGA1064 */
@@ -723,6 +749,9 @@
 #define M_X_INDEX	0x00
 #define M_X_DATAREG	0x0A
 
+#define DAC_XGENIOCTRL		0x2A
+#define DAC_XGENIODATA		0x2B
+
 #ifdef CONFIG_FB_MATROX_MILLENIUM
 #define TVP3026_INDEX		0x00
 #define TVP3026_PALWRADD	0x00
@@ -1054,6 +1083,48 @@
 #define isMilleniumII(x) (0)
 #endif
 
+#ifdef MATROXFB_DEBUG_REENTER
+static atomic_t guard_counter = ATOMIC_INIT(1);
+static atomic_t guard_printing = ATOMIC_INIT(1);
+static void guard_start(void) {
+	if (atomic_dec_and_test(&guard_counter)) {	/* first level */
+		if (!(bh_mask & (1 << CONSOLE_BH)))	/* and CONSOLE_BH disabled */
+			return;				/* is OK */
+		/* otherwise it is first level with CONSOLE_BH enabled -
+		   - if we are __sti or SMP, reentering from console_bh possible */
+		atomic_dec(&guard_printing);	/* disable reentrancy warning */
+		printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n");
+#ifdef printstate
+		printstate();
+#endif
+		atomic_inc(&guard_printing);
+		return;
+	}
+	/* real reentering... You should be already warned by code above */
+	if (atomic_dec_and_test(&guard_printing)) {
+#ifdef printstate
+		printstate();
+#endif
+	}
+	atomic_inc(&guard_printing);
+}
+
+static inline void guard_end(void) {
+	atomic_inc(&guard_counter);
+}
+
+#define CRITBEGIN guard_start();
+#define CRITEND   guard_end();
+
+#else
+
+#define CRITBEGIN
+#define CRITEND
+
+#endif
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
 static void matrox_cfbX_init(WPMINFO struct display* p) {
 	u_int32_t maccess;
 	u_int32_t mpitch;
@@ -1101,7 +1172,7 @@
 	mga_outl(M_OPMODE, mopmode);
 	mga_outl(M_CXBNDRY, 0xFFFF0000);
 	mga_outl(M_YTOP, 0);
-	mga_outl(M_YBOT, 0x007FFFFF);
+	mga_outl(M_YBOT, 0x01FFFFFF);
 	mga_outl(M_MACCESS, maccess);
 	ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
 	if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
@@ -1113,7 +1184,9 @@
 	MINFO_FROM_DISP(p);
 
 	DBG("matrox_cfbX_bmove")
-	
+
+	CRITBEGIN
+
 	sx *= fontwidth(p);
 	dx *= fontwidth(p);
 	width *= fontwidth(p);
@@ -1142,8 +1215,10 @@
 	mga_outl(M_AR0, end);
 	mga_outl(M_AR3, start);
 	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
-	mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+	mga_ydstlen(dy, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB4
@@ -1154,7 +1229,9 @@
 	   also odd, that means that we cannot use acceleration */
 	
 	DBG("matrox_cfb4_bmove")
-	
+
+	CRITBEGIN
+
 	if ((sx | dx | width) & fontwidth(p) & 1) {
 		fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
 		return;
@@ -1194,6 +1271,8 @@
 	mga_outl(M_YDST, dy*pixx >> 5);
 	mga_outl(M_LEN | M_EXEC, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 #endif
 
@@ -1201,13 +1280,17 @@
 		int width) {
 	
 	DBG("matroxfb_accel_clear")
-	
-	mga_fifo(4);
+
+	CRITBEGIN
+
+	mga_fifo(5);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
 	mga_outl(M_FCOL, color);
 	mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
-	mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+	mga_ydstlen(sy, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
@@ -1225,7 +1308,9 @@
 	MINFO_FROM_DISP(p);
 
 	DBG("matrox_cfb4_clear")
-	
+
+	CRITBEGIN
+
 	whattodo = 0; 
 	bgx = attr_bgcol_ec(p, conp);
 	bgx |= bgx << 4;
@@ -1277,6 +1362,8 @@
 			}
 		}
 	}
+
+	CRITEND
 }
 #endif
 
@@ -1323,7 +1410,10 @@
 	charcell = fontwidth(p) * fontheight(p);
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
-	mga_fifo(7);
+
+	CRITBEGIN
+
+	mga_fifo(8);
 	mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 	
 	mga_outl(M_FCOL, fgx);
@@ -1332,8 +1422,10 @@
 	ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
 	mga_outl(M_AR3, ar3);
 	mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 	
 static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
@@ -1345,6 +1437,9 @@
 	
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1367,7 +1462,7 @@
 		mga_outl(M_BCOL, bgx);
 		mga_outl(M_AR3, 0);
 		mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 		mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
 	} else {
 		u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
@@ -1379,7 +1474,7 @@
 		mga_outl(M_AR5, 0);
 		mga_outl(M_AR3, 0);
 		mga_outl(M_AR0, ar0);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 
 		switch (step) {
 		case 1:	
@@ -1410,6 +1505,7 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB8
@@ -1464,6 +1560,9 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 	charcell = fontwidth(p) * fontheight(p);
+
+	CRITBEGIN
+
 	mga_fifo(3);
 	mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 	mga_outl(M_FCOL, fgx);
@@ -1475,10 +1574,12 @@
 		mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
 		mga_outl(M_AR3, ar3);
 		mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 		xx += fontwidth(p);
 	}
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
@@ -1504,7 +1605,7 @@
 		step = 4;
 	charcell = fontheight(p)*step;
 	xlen = (charcell + 3) & ~3;
-	ydstlen = (yy<<16) | fontheight(p);
+	ydstlen = (yy << 16) | fontheight(p);
 	if (fontwidth(p) == step << 3) {
 		ar0 = fontheight(p)*fontwidth(p) - 1;
 		easy = 1;
@@ -1512,6 +1613,9 @@
 		ar0 = fontwidth(p) - 1;
 		easy = 0;
 	}
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1529,7 +1633,7 @@
 	while (count--) {
 		u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
 
-		mga_fifo(5);
+		mga_fifo(6);
 		mga_writel(mmio, M_FXBNDRY, fxbndry);
 		mga_writel(mmio, M_AR0, ar0);
 		mga_writel(mmio, M_AR3, 0);
@@ -1573,6 +1677,7 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB8
@@ -1635,6 +1740,8 @@
 	xx |= (xx + fontwidth(p)) << 16;
 	xx >>= 1;
 
+	CRITBEGIN
+	
 	mga_fifo(5);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0xFFFFFFFF);
@@ -1642,6 +1749,8 @@
 	mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
 	mga_outl(M_LEN | M_EXEC, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 } 
 #endif
 
@@ -1654,12 +1763,16 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 
+	CRITBEGIN
+	
 	mga_fifo(4);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0x0F0F0F0F);
 	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 #endif
 
@@ -1671,12 +1784,16 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 
+	CRITBEGIN
+	
 	mga_fifo(4);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0xFFFFFFFF);
 	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
@@ -1840,6 +1957,9 @@
 
 	DBG("matroxfb_ti3026_cursor")
 	
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
 			spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
@@ -1914,6 +2034,9 @@
 	xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
 	cursorbase = ACCESS_FBINFO(video.vbase);
 	h = ACCESS_FBINFO(features.DAC1064.cursorimage);
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_32BPP);
@@ -1944,12 +2067,17 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+
+	CRITEND
 }
 	
 static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
 	unsigned long flags;
 	MINFO_FROM_DISP(p);
 
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
 			spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
@@ -2010,6 +2138,9 @@
 	fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
 	if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
 		return 0;
+
+	CRITBEGIN
+
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
 	if (width <= 8) {
 		if (width == 8)
@@ -2100,6 +2231,9 @@
 		}
 	}
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+
+	CRITEND
+
 	return 1;
 }
 
@@ -2117,6 +2251,8 @@
 	unsigned int step;
 	MINFO_FROM_DISP(p);
 
+	CRITBEGIN
+
 	step = ACCESS_FBINFO(devflags.textstep);
 	srcoff = (sy * p->next_line) + (sx * step);
 	dstoff = (dy * p->next_line) + (dx * step);
@@ -2144,6 +2280,7 @@
 			height--;
 		}
 	}
+	CRITEND
 }
 
 static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
@@ -2156,6 +2293,9 @@
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = sy * p->next_line + sx * step;
 	val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
+
+	CRITBEGIN
+	
 	while (height > 0) {
 		int i;
 		for (i = width; i > 0; offs += step, i--)
@@ -2163,6 +2303,7 @@
 		offs += p->next_line - width * step;
 		height--;
 	}
+	CRITEND
 }
 
 static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
@@ -2175,7 +2316,12 @@
 	offs = yy * p->next_line + xx * step;
 	chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
 	if (chr & 0x10000) chr |= 0x08;
+
+	CRITBEGIN
+	
 	mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
+
+	CRITEND
 }
 
 static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
@@ -2188,12 +2334,17 @@
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step;
 	attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
+
+	CRITBEGIN
+	
 	while (count-- > 0) {
 		unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
 		if (chr & 0x10000) chr ^= 0x10008;
 		mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
 		offs += step;
 	}
+
+	CRITEND
 }
 
 static void matrox_text_revc(struct display* p, int xx, int yy) {
@@ -2203,7 +2354,12 @@
 
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step + 1;
+	
+	CRITBEGIN
+	
 	mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
+
+	CRITEND
 }
 
 static int matrox_text_loadfont(WPMINFO struct display* p) {
@@ -2221,6 +2377,9 @@
 	dst = ACCESS_FBINFO(video.vbase);
 	i = 2;
 	font = (u_int8_t*)p->fontdata;
+
+	CRITBEGIN
+
 	mga_setr(M_SEQ_INDEX, 0x02, 0x04);
 	while (fsize--) {
 		int l;
@@ -2233,6 +2392,9 @@
 		i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
 	}
 	mga_setr(M_SEQ_INDEX, 0x02, 0x03);
+
+	CRITEND
+
 	return 1;
 }
 
@@ -2242,17 +2404,31 @@
 		return;
 
 	matroxfb_createcursorshape(PMINFO p, 0);
+
+	CRITBEGIN
+	
 	mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
 	mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
+
+	CRITEND
 }
 
 static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
 	unsigned int pos;
 	MINFO_FROM_DISP(p);
 
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+
+			CRITBEGIN
+			
 			mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
+
+			CRITEND
+
 			ACCESS_FBINFO(cursor.state) = CM_ERASE;
 		}
 		return;
@@ -2264,10 +2440,16 @@
 	ACCESS_FBINFO(cursor.x) = x;
 	ACCESS_FBINFO(cursor.y) = y;
 	pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
+
+	CRITBEGIN
+	
 	mga_setr(M_CRTC_INDEX, 0x0F, pos);
 	mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
 
 	mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
+
+	CRITEND
+
 	ACCESS_FBINFO(cursor.state) = CM_DRAW;
 }
 
@@ -2523,6 +2705,9 @@
 static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
 	unsigned int pos;
 	unsigned short p0, p1, p2;
+#ifdef CONFIG_FB_MATROX_32MB
+	unsigned int p3;
+#endif
 	struct display *disp;
 
 	DBG("matrox_pan_var")
@@ -2536,10 +2721,22 @@
 	}
 	p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
 	p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
-	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+#ifdef CONFIG_FB_MATROX_32MB
+	p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
+#endif	
+
+	CRITBEGIN
+
 	mga_setr(M_CRTC_INDEX, 0x0D, p0);
 	mga_setr(M_CRTC_INDEX, 0x0C, p1);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+#endif
 	mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+
+	CRITEND
 }
 
 	/*
@@ -2627,13 +2824,16 @@
 		case 0:		return xres;
 		case 4:		rounding = 128;
 				break;
-		case 8:		rounding = 64;
+		case 8:		rounding = 64;	/* doc says 64; 32 is OK for G400 */
 				break;
 		case 16:	rounding = 32;
 				break;
-		case 24:	rounding = 64;
+		case 24:	rounding = 64;	/* doc says 64; 32 is OK for G400 */
 				break;
 		default:	rounding = 16;
+				/* on G400, 16 really does not work */
+				if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+					rounding = 32;
 				break;
 	}
 	if (isInterleave(MINFO)) {
@@ -3140,7 +3340,7 @@
 	hw->DACclk[2] = p;
 }
 
-__initfunc(static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem)) {
+static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
 	u_int32_t mx;
 
 	DBG("DAC1064_setmclk")
@@ -3288,6 +3488,8 @@
 static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
 	
 	DBG("DAC1064_restore_1")
+
+	CRITBEGIN
 	
 	outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
 	outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
@@ -3298,6 +3500,8 @@
 		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
 			outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
 	}
+
+	CRITEND
 }
 
 static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
@@ -3305,6 +3509,8 @@
 	unsigned int tmout;
 	
 	DBG("DAC1064_restore_2")
+
+	CRITBEGIN
 	
 	for (i = 0; i < 3; i++)
 		outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
@@ -3313,6 +3519,9 @@
 			break;
 		udelay(10);
 	};
+
+	CRITEND
+
 	if (!tmout)
 		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 
@@ -3585,7 +3794,9 @@
 			var->pixclock = 15000;	/* limit for "normal" gclk & mclk */
 #endif
 	}
-
+	/* YDSTLEN contains only signed 16bit value */
+	if (var->yres_virtual > 32767)
+		var->yres_virtual = 32767;
 	if (var->yres_virtual < var->yres)
 		var->yres = var->yres_virtual;
 	if (var->xres_virtual < var->xres)
@@ -3684,7 +3895,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
 	unsigned int f_pll;
 	unsigned int pclk_m, pclk_n, pclk_p;
 	unsigned int mclk_m, mclk_n, mclk_p;
@@ -3783,7 +3994,7 @@
 		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 }
 
-__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("ti3026_ramdac_init")
 
@@ -3800,7 +4011,7 @@
 }
 #endif
 
-__initfunc(static void matroxfb_fastfont_init(struct matrox_fb_info* minfo)) {
+static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
 	unsigned int size;
 
 	size = ACCESS_FBINFO(fastfont.size);
@@ -3824,7 +4035,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MYSTIQUE
-__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("MGA1064_ramdac_init");
 
@@ -3841,7 +4052,7 @@
 	DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
 }
 
-__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960, 
 					     1024, 1152, 1280,      1600, 1664, 1920, 
 					     2048,    0};
@@ -3873,7 +4084,7 @@
 	return 0;
 }
 
-__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("MGA1064_reset");
 
@@ -3893,7 +4104,7 @@
 static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
 #endif
 
-__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
 	int reg;
 	int selClk;
 	int clk;
@@ -3937,7 +4148,7 @@
 	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
 }
 
-__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){
 	unsigned int m, n, p;
 
 	DBG("MGAG100_setPixClock")
@@ -3946,7 +4157,7 @@
 	MGAG100_progPixClock(PMINFO flags, m, n, p);
 }
 
-__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960, 
                                           1024, 1152, 1280,      1600, 1664, 1920, 
                                           2048, 0};
@@ -4036,7 +4247,7 @@
 	return 0;
 }
 	
-__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
 	u_int8_t b;
 
 	DBG("MGAG100_reset")
@@ -4104,6 +4315,8 @@
 		dprintk("%02X:", hw->ATTR[i]);
 	dprintk("\n");
 
+	CRITBEGIN
+
 	mga_inb(M_ATTR_RESET);
 	mga_outb(M_ATTR_INDEX, 0);
 	mga_outb(M_MISC_REG, hw->MiscOutReg);
@@ -4125,6 +4338,8 @@
 		mga_outb(M_DAC_VAL, hw->DACpal[i]);
 	mga_inb(M_ATTR_RESET);
 	mga_outb(M_ATTR_INDEX, 0x20);
+
+	CRITEND
 }
 
 static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -4227,10 +4442,15 @@
 	int i;
 
 	DBG("MGA1064_restore")
+
+	CRITBEGIN
 	
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
 	mga_outb(M_IEN, 0x00);
 	mga_outb(M_CACHEFLUSH, 0x00);
+
+	CRITEND
+
 	DAC1064_restore_1(PMINFO hw, oldhw);
 	vgaHWrestore(PMINFO hw, oldhw);
 	for (i = 0; i < 6; i++)
@@ -4244,10 +4464,18 @@
 	int i;
 
 	DBG("MGAG100_restore")
-	
+
+	CRITBEGIN
+
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	CRITEND
+
 	DAC1064_restore_1(PMINFO hw, oldhw);
 	vgaHWrestore(PMINFO hw, oldhw);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+#endif
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(PMINFO hw, oldhw, p);
@@ -4265,9 +4493,16 @@
 		dprintk("%02X:", hw->CRTCEXT[i]);
 	dprintk("\n");
 
+	CRITBEGIN
+
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
 
+	CRITEND
+
 	vgaHWrestore(PMINFO hw, oldhw);
+
+	CRITBEGIN
+
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 
@@ -4285,11 +4520,13 @@
 		oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
 		oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
 	}
+	CRITEND
 	if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
 		/* agrhh... setting up PLL is very slow on Millenium... */
 		/* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
 		/* Maybe even we should call schedule() ? */
 
+		CRITBEGIN
 		outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
 		outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
 		outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
@@ -4307,24 +4544,31 @@
 					break;
 				udelay(10);
 			}
+
+			CRITEND
+
 			if (!tmout)
 				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 			else
 				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+			CRITBEGIN
 		}
 		outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
 		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
 		for (i = 3; i < 6; i++)
 			outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+		CRITEND
 		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
 			int tmout;
 
+			CRITBEGIN
 			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
 			for (tmout = 500000; tmout; --tmout) {
 				if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) 
 					break;
 				udelay(10);
 			}
+			CRITEND
 			if (!tmout)
 				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
 			else
@@ -4379,7 +4623,7 @@
 	strcpy(fix->id,"MATROX");
 
 	fix->smem_start = (void*)ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
-	fix->smem_len = ACCESS_FBINFO(video.len) - ACCESS_FBINFO(curr.ydstorg.bytes);
+	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
 	fix->type = p->type;
 	fix->type_aux = p->type_aux;
 	fix->visual = p->visual;
@@ -4531,7 +4775,8 @@
 
 			hw->CRTC[0x0D] = pos & 0xFF;
 			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
-			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+			hw->CRTCEXT[8] = pos >> 21;
 			ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
 			ACCESS_FBINFO(cursor.redraw) = 1;
 			ACCESS_FBINFO(currenthw) = hw;
@@ -4717,10 +4962,16 @@
 		case 4:  seq = 0x20; crtc = 0x30; break;
 		default: seq = 0x00; crtc = 0x00; break;
 	}
+
+	CRITBEGIN
+	
 	mga_outb(M_SEQ_INDEX, 1);
 	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
 	mga_outb(M_EXTVGA_INDEX, 1);
 	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+
 #undef minfo
 }
 
@@ -4739,7 +4990,8 @@
 #define RS1056x344	12	/* 132 x 43 text */
 #define RS1056x400	13	/* 132 x 50 text */
 #define RS1056x480	14	/* 132 x 60 text */
-/* 0F-FF */
+#define RSNoxNo		15
+/* 10-FF */
 static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
 	{  640,  400,  48, 16, 39,  8,  96, 2, 70 },
 	{  640,  480,  48, 16, 33, 10,  96, 2, 60 },
@@ -4754,7 +5006,8 @@
 	{  640,  350,  48, 16, 39,  8,  96, 2, 70 },
 	{ 1056,  344,  96, 24, 59, 44, 160, 2, 70 },
 	{ 1056,  400,  96, 24, 39,  8, 160, 2, 70 },
-	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 }
+	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 },
+	{    0,    0,  ~0, ~0, ~0, ~0,   0, 0,  0 }
 };
 
 #define RSDepth(X)	(((X) >> 8) & 0x0F)
@@ -4775,13 +5028,14 @@
 	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
 	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 },
 	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode with (default) VGA8x16 */
-	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 }	/* textmode hardwired to VGA8x8 */
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode hardwired to VGA8x8 */
 };
 
 #define RSCreate(X,Y)	((X) | ((Y) << 8))
 static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
 /* default must be first */
 #ifdef FBCON_HAS_CFB8
+	{    ~0, RSCreate(RSNoxNo,     RS8bpp ) },
 	{ 0x101, RSCreate(RS640x480,   RS8bpp ) },
 	{ 0x100, RSCreate(RS640x400,   RS8bpp ) },
 	{ 0x180, RSCreate(RS768x576,   RS8bpp ) },
@@ -4793,14 +5047,8 @@
 	{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
 	{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
 #endif
-#ifdef FBCON_HAS_CFB4
-	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
-	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
-	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
-	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
-	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
-#endif
 #ifdef FBCON_HAS_CFB16
+	{    ~0, RSCreate(RSNoxNo,     RS15bpp) },
 	{ 0x110, RSCreate(RS640x480,   RS15bpp) },
 	{ 0x181, RSCreate(RS768x576,   RS15bpp) },
 	{ 0x113, RSCreate(RS800x600,   RS15bpp) },
@@ -4821,6 +5069,7 @@
 	{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
 #endif
 #ifdef FBCON_HAS_CFB24
+	{    ~0, RSCreate(RSNoxNo,     RS24bpp) },
 	{ 0x1B2, RSCreate(RS640x480,   RS24bpp) },
 	{ 0x184, RSCreate(RS768x576,   RS24bpp) },
 	{ 0x1B5, RSCreate(RS800x600,   RS24bpp) },
@@ -4832,6 +5081,7 @@
 	{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
 #endif
 #ifdef FBCON_HAS_CFB32
+	{    ~0, RSCreate(RSNoxNo,     RS32bpp) },
 	{ 0x112, RSCreate(RS640x480,   RS32bpp) },
 	{ 0x183, RSCreate(RS768x576,   RS32bpp) },
 	{ 0x115, RSCreate(RS800x600,   RS32bpp) },
@@ -4843,6 +5093,7 @@
 	{ 0x11F, RSCreate(RS1600x1200, RS32bpp) },
 #endif
 #ifdef FBCON_HAS_VGATEXT
+	{    ~0, RSCreate(RSNoxNo,     RSText)  },
 	{ 0x002, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
 	{ 0x003, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
 	{ 0x007, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
@@ -4853,6 +5104,14 @@
 	{ 0x10B, RSCreate(RS1056x400,  RSText8) },	/* 132x50 */
 	{ 0x10C, RSCreate(RS1056x480,  RSText8) },	/* 132x60 */
 #endif
+#ifdef FBCON_HAS_CFB4
+	{    ~0, RSCreate(RSNoxNo,     RS4bpp ) },
+	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
+	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
+	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
+	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
+#endif
 	{     0, 0                                 }};
 
 /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
@@ -4871,19 +5130,21 @@
 static int hwcursor = 1;		/* "matrox:nohwcursor" */
 static int blink = 1;			/* "matrox:noblink" */
 static int sgram = 0;			/* "matrox:sgram" */
+#ifdef CONFIG_MTRR
 static int mtrr = 1;			/* "matrox:nomtrr" */
+#endif
 static int grayscale = 0;		/* "matrox:grayscale" */
 static unsigned int fastfont = 0;	/* "matrox:fastfont:xxxxx" */
 static int dev = -1;			/* "matrox:dev:xxxxx" */
-static unsigned int vesa = 0x101;	/* "matrox:vesa:xxxxx" */
+static unsigned int vesa = ~0;		/* "matrox:vesa:xxxxx" */
 static int depth = -1;			/* "matrox:depth:xxxxx" */
 static unsigned int xres = 0;		/* "matrox:xres:xxxxx" */
 static unsigned int yres = 0;		/* "matrox:yres:xxxxx" */
-static unsigned int upper = 0;		/* "matrox:upper:xxxxx" */
-static unsigned int lower = 0;		/* "matrox:lower:xxxxx" */
+static unsigned int upper = ~0;		/* "matrox:upper:xxxxx" */
+static unsigned int lower = ~0;		/* "matrox:lower:xxxxx" */
 static unsigned int vslen = 0;		/* "matrox:vslen:xxxxx" */
-static unsigned int left = 0;		/* "matrox:left:xxxxx" */
-static unsigned int right = 0;		/* "matrox:right:xxxxx" */
+static unsigned int left = ~0;		/* "matrox:left:xxxxx" */
+static unsigned int right = ~0;		/* "matrox:right:xxxxx" */
 static unsigned int hslen = 0;		/* "matrox:hslen:xxxxx" */
 static unsigned int pixclock = 0;	/* "matrox:pixclock:xxxxx" */
 static int sync = -1;			/* "matrox:sync:xxxxx" */
@@ -4893,7 +5154,7 @@
 static char fontname[64];		/* "matrox:font:xxxxx" */
 
 #ifndef MODULE
-__initfunc(void matroxfb_setup(char *options, int *ints)) {
+void __init matroxfb_setup(char *options, int *ints){
 	char *this_opt;
 	
 	DBG("matroxfb_setup")
@@ -4901,7 +5162,7 @@
 	fontname[0] = '\0';
 	
 	if (!options || !*options)
-		return;
+		return 0;
 	
 	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
 		if (!*this_opt) continue;
@@ -4954,6 +5215,31 @@
 			fv = simple_strtoul(this_opt+3, NULL, 0);
 		else if (!strncmp(this_opt, "mem:", 4)) 
 			mem = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "mode:", 5))
+			strcpy(videomode, this_opt+5);
+#ifdef CONFIG_FB_OF
+		else 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
 		else if (!strncmp(this_opt, "fastfont:", 9))
 			fastfont = simple_strtoul(this_opt+9, NULL, 0);
 		else if (!strcmp(this_opt, "nofastfont"))	/* fastfont:N and nofastfont (nofastfont = fastfont:0) */
@@ -4987,8 +5273,10 @@
 				nobios = !value;
 			else if (!strcmp(this_opt, "init"))
 				noinit = !value;
+#ifdef CONFIG_MTRR
 			else if (!strcmp(this_opt, "mtrr"))
 				mtrr = value;
+#endif
 			else if (!strcmp(this_opt, "inv24"))
 				inv24 = value;
 			else if (!strcmp(this_opt, "cross4MB"))
@@ -5004,15 +5292,16 @@
 			}
 		}
 	}
+	return 0;
 }
 #endif
 
-__initfunc(static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize)) {
+static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){
 	vaddr_t vm;
 	unsigned int offs;
 	unsigned int offs2;
 	unsigned char store;
-	unsigned char bytes[16];
+	unsigned char bytes[32];
 	unsigned char* tmp;
 	unsigned long cbase;
 	unsigned long mbase;
@@ -5025,7 +5314,7 @@
 	maxSize &= ~0x1FFFFF;	/* must be X*2MB (really it must be 2 or X*4MB) */
 	/* at least 2MB */
 	if (maxSize < 0x0200000) return 0;
-	if (maxSize > 0x1000000) maxSize = 0x1000000;
+	if (maxSize > 0x2000000) maxSize = 0x2000000;
 
 	mga_outb(M_EXTVGA_INDEX, 0x03);
 	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
@@ -5080,7 +5369,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960, 
 					  1024, 1152, 1280,      1600, 1664, 1920, 
 					  2048, 0};
@@ -5133,7 +5422,7 @@
 	return 0;
 }
 
-__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init Ti3026_reset(WPMINFO struct matrox_hw_state* hw){
 	
 	DBG("Ti3026_reset")
 	
@@ -5163,20 +5452,28 @@
 
 struct video_board {
 	int maxvram;
+	int maxdisplayable;
 	int accelID;
 	struct matrox_switch* lowlevel;
 		 };
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-static struct video_board vbMillenium __initdata	= {0x0800000,	FB_ACCEL_MATROX_MGA2064W,	&matrox_millenium};
-static struct video_board vbMillenium2 __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W,	&matrox_millenium};
-static struct video_board vbMillenium2A __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W_AGP,	&matrox_millenium};
+static struct video_board vbMillenium __initdata   = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W,	  &matrox_millenium};
+static struct video_board vbMillenium2 __initdata  = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W,	  &matrox_millenium};
+static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
 #endif	/* CONFIG_FB_MATROX_MILLENIUM */
 #ifdef CONFIG_FB_MATROX_MYSTIQUE
-static struct video_board vbMystique __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGA1064SG,	&matrox_mystique};
+static struct video_board vbMystique __initdata    = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG,	  &matrox_mystique};
 #endif	/* CONFIG_FB_MATROX_MYSTIQUE */
 #ifdef CONFIG_FB_MATROX_G100
-static struct video_board vbG100 __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGAG100,	&matrox_G100};
-static struct video_board vbG200 __initdata		= {0x1000000,	FB_ACCEL_MATROX_MGAG200,	&matrox_G100};
+static struct video_board vbG100 __initdata	   = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100,	  &matrox_G100};
+static struct video_board vbG200 __initdata	   = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200,	  &matrox_G100};
+#ifdef CONFIG_FB_MATROX_32MB
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+   whole 32MB */
+static struct video_board vbG400 __initdata	   = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	  &matrox_G100};
+#else
+static struct video_board vbG400 __initdata	   = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	  &matrox_G100};
+#endif
 #endif
 
 #define DEVF_VIDEO64BIT	0x01
@@ -5185,6 +5482,15 @@
 #define	DEVF_MILLENIUM2	0x08
 #define DEVF_CROSS4MB	0x10
 #define DEVF_TEXT4B	0x20
+#define DEVF_DDC_8_2	0x40
+#define DEVF_DMA	0x80
+#define DEVF_SUPPORT32MB	0x100
+#define DEVF_ANY_VXRES		0x200
+
+#define DEVF_G100	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */
+#define DEVF_G200	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES)
+#define DEVF_G400	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB)
+
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
 	unsigned int flags;
@@ -5229,88 +5535,94 @@
 #ifdef CONFIG_FB_MATROX_G100
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_PCI,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"unknown G100 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"Productiva G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"unknown G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		250000,
 		&vbG200,
 		"unknown G200 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		220000,
 		&vbG200,
 		"MGA-G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"Mystique G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		250000,
 		&vbG200,
 		"Millennium G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MARVEL_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"Marvel G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"MGA-G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"unknown G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400_AGP,	0xFF,
+		0,			0,
+		DEVF_G400,
+		360000,
+		&vbG400,
+		"unknown G400 (AGP)"},
 #endif
 	{0,			0,				0xFF,
 		0,			0,
@@ -5319,7 +5631,7 @@
 		NULL,
 		NULL}};
 	
-__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) {
+static int __init initMatrox2(WPMINFO struct display* d, struct board* b){
 	unsigned long ctrlptr_phys = 0;
 	unsigned long video_base_phys = 0;
 	unsigned int memsize;
@@ -5348,17 +5660,21 @@
 		ACCESS_FBINFO(devflags.vgastepdisp) = 64;
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
 	}
+#ifdef CONFIG_FB_MATROX_32MB
+	ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+#endif
+	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
 	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
 	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
 	if (ACCESS_FBINFO(capable.cross4MB) < 0)
 		ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
 	if (b->flags & DEVF_SWAPS) {
-		ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x3FFF;
-		video_base_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x7FFFFF;	/* aligned at 8MB (or 16 for Mill 2) */
+		ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
+		video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
 	} else {
-		ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x3FFF;
-		video_base_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x7FFFFF;	/* aligned at 8MB */
+		ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
+		video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
 	}
 	if (!ctrlptr_phys) {
 		printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
@@ -5472,8 +5788,8 @@
 		return -ENOMEM;
 	}
 	ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
-	if (ACCESS_FBINFO(video.len_usable) > 0x08000000)
-		ACCESS_FBINFO(video.len_usable) = 0x08000000;
+	if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
+		ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
 #ifdef CONFIG_MTRR
 	if (mtrr) {
 		ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
@@ -5482,11 +5798,16 @@
 	}
 #endif	/* CONFIG_MTRR */
 
+	if (!ACCESS_FBINFO(devflags.novga))
+		request_region(0x3C0, 32, "matrox");
+	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
 /* validate params, autodetect k, M */
 	if (fh < 1000) fh *= 1000;	/* 1kHz minimum */
 	if (maxclk < 1000) maxclk *= 1000;	/* kHz -> Hz, MHz -> kHz */
 	if (maxclk < 1000000) maxclk *= 1000;	/* kHz -> Hz, 1MHz minimum */
-	vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
+	if (vesa != ~0)
+		vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
 
 	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
 	ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
@@ -5504,19 +5825,19 @@
 	}
 	{
 		int res = RSResolution(RSptr->info)-1;
-		if (!left)
+		if (left == ~0)
 			left = timmings[res].left;
 		if (!xres)
 			xres = timmings[res].xres;
-		if (!right)
+		if (right == ~0)
 			right = timmings[res].right;
 		if (!hslen)
 			hslen = timmings[res].hslen;
-		if (!upper)
+		if (upper == ~0)
 			upper = timmings[res].upper;
 		if (!yres)
 			yres = timmings[res].yres;
-		if (!lower)
+		if (lower == ~0)
 			lower = timmings[res].lower;
 		if (!vslen)
 			vslen = timmings[res].vslen;
@@ -5525,6 +5846,7 @@
 		if (depth == -1)
 			depth = RSDepth(RSptr->info);
 	}
+#if 0	
 	if (sync == -1) {
 		sync = 0;
 		if (yres < 400)
@@ -5532,31 +5854,7 @@
 		else if (yres < 480)
 			sync |= FB_SYNC_VERT_HIGH_ACT;
 	}
-	if (xres < 320)
-		xres = 320;
-	if (xres > 2048)
-		xres = 2048;
-	if (yres < 200)
-		yres = 200;
-	if (yres > 2048)
-		yres = 2048;
-	{
-		unsigned int tmp;
-
-		if (fv) {
-			tmp = fv * (upper + yres + lower + vslen);
-			if ((tmp < fh) || (fh == 0)) fh = tmp;
-		}
-		if (fh) {
-			tmp = fh * (left + xres + right + hslen);
-			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
-		}
-		maxclk = (maxclk + 499) / 500;
-		if (maxclk) {
-			tmp = (2000000000 + maxclk) / maxclk;
-			if (tmp > pixclock) pixclock = tmp;
-		}
-	}
+#endif
 	if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
 		strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
 	}
@@ -5564,27 +5862,8 @@
 	vesafb_defined.green = colors[depth-1].green;
 	vesafb_defined.blue = colors[depth-1].blue;
 	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
-	if (pixclock < 2000)		/* > 500MHz */
-		pixclock = 4000;	/* 250MHz */
-	if (pixclock > 1000000)
-		pixclock = 1000000;	/* 1MHz */
-	vesafb_defined.xres = xres;
-	vesafb_defined.yres = yres;
-	vesafb_defined.xoffset = 0;
-	vesafb_defined.yoffset = 0;
 	vesafb_defined.grayscale = grayscale;
-	vesafb_defined.pixclock = pixclock;
-	vesafb_defined.left_margin = left;
-	vesafb_defined.right_margin = right;
-	vesafb_defined.hsync_len = hslen;
-	vesafb_defined.upper_margin = upper;
-	vesafb_defined.lower_margin = lower;
-	vesafb_defined.vsync_len = vslen;
-	vesafb_defined.sync = sync;
 	vesafb_defined.vmode = 0;
-
-	if (!ACCESS_FBINFO(devflags.novga))
-		request_region(0x3C0, 32, "matrox");
 	if (noaccel)
 		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
 
@@ -5597,8 +5876,60 @@
 	ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
 	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
 	ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
-	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
 	ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
+
+#if 0
+	fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
+		NULL, 0, NULL, vesafb_defined.bits_per_pixel);
+#endif
+	/* mode modifiers */
+	if (sync != -1)
+		vesafb_defined.sync = sync;
+	if (hslen)
+		vesafb_defined.hsync_len = hslen;
+	if (vslen)
+		vesafb_defined.vsync_len = vslen;
+	if (left != ~0)
+		vesafb_defined.left_margin = left;
+	if (right != ~0)
+		vesafb_defined.right_margin = right;
+	if (upper != ~0)
+		vesafb_defined.upper_margin = upper;
+	if (lower != ~0)
+		vesafb_defined.lower_margin = lower;
+	if (xres)
+		vesafb_defined.xres = xres;
+	if (yres)
+		vesafb_defined.yres = yres;
+	/* fv, fh, maxclk limits was specified */
+	{
+		unsigned int tmp;
+
+		if (fv) {
+			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres 
+			          + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+			if ((tmp < fh) || (fh == 0)) fh = tmp;
+		}
+		if (fh) {
+			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres 
+			          + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+		}
+		maxclk = (maxclk + 499) / 500;
+		if (maxclk) {
+			tmp = (2000000000 + maxclk) / maxclk;
+			if (tmp > pixclock) pixclock = tmp;
+		}
+	}
+	if (pixclock) {
+		if (pixclock < 2000)		/* > 500MHz */
+			pixclock = 4000;	/* 250MHz */
+		if (pixclock > 1000000)
+			pixclock = 1000000;	/* 1MHz */
+		vesafb_defined.pixclock = pixclock;
+	}
+		
+	/* FIXME: Where to move this?! */
 #if defined(CONFIG_FB_OF)
 #if defined(CONFIG_FB_COMPAT_XPMAC)
 	strcpy(ACCESS_FBINFO(matrox_name), "MTRX,");	/* OpenFirmware naming convension */
@@ -5608,30 +5939,30 @@
 #endif
 	if ((xres <= 640) && (yres <= 480)) {
 		struct fb_var_screeninfo var;
-		int default_vmode = nvram_read_byte(NV_VMODE);
-		int default_cmode = nvram_read_byte(NV_CMODE);
-
-		if ((default_vmode <= 0) || (default_vmode > VMODE_MAX))
+		if (default_vmode == VMODE_NVRAM) {
+			default_vmode = nvram_read_byte(NV_VMODE);
+			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+				default_vmode = VMODE_CHOOSE;
+		}
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 			default_vmode = VMODE_640_480_60;
-		if ((default_cmode < CMODE_8) || (default_cmode > CMODE_32))
+		if (default_cmode == CMODE_NVRAM)
+			default_cmode = nvram_read_byte(NV_CMODE);
+		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
 			default_cmode = CMODE_8;
 		if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
 			var.accel_flags = vesafb_defined.accel_flags;
 			var.xoffset = var.yoffset = 0;
 			vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
-		}
+              }
 	}
 #endif
-	{
-		int pixel_size = vesafb_defined.bits_per_pixel;
-
-		vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO vesafb_defined.xres, pixel_size);
-		if (nopan) {
-			vesafb_defined.yres_virtual = vesafb_defined.yres;
-		} else {
-			vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
-			                                        to yres_virtual * xres_virtual < 2^32 */
-		}
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	if (nopan) {
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
+	} else {
+		vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+		                                        to yres_virtual * xres_virtual < 2^32 */
 	}
 	if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
 		printk(KERN_ERR "matroxfb: cannot set required parameters\n");
@@ -5647,8 +5978,9 @@
 /* We do not have to set currcon to 0... register_framebuffer do it for us on first console
  * and we do not want currcon == 0 for subsequent framebuffers */
 
-	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
 		return -EINVAL;
+	}
 	printk("fb%d: %s frame buffer device\n",
 	       GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
 	if (ACCESS_FBINFO(currcon) < 0) {
@@ -5663,7 +5995,7 @@
 
 static struct matrox_fb_info* fb_list = NULL;
 
-__initfunc(static int matrox_init(void)) {
+static int __init matrox_init(void){
 	struct pci_dev* pdev = NULL;
 
 	DBG("matrox_init")
@@ -5756,7 +6088,7 @@
 #ifndef MODULE
 static int __init initialized = 0;
 
-__initfunc(void matroxfb_init(void))
+void __init matroxfb_init(void)
 {
 	DBG("matroxfb_init")
 	
@@ -5764,10 +6096,12 @@
 		initialized = 1;
 		matrox_init();
 	}
+	if (!fb_list) return -ENXIO;
+	return 0;
 }
 
 #if defined(CONFIG_FB_OF)
-__initfunc(int matrox_of_init(struct device_node *dp)) {
+int __init matrox_of_init(struct device_node *dp){
 	DBG("matrox_of_init");
 	
 	if (!initialized) {
@@ -5781,8 +6115,8 @@
 
 #else
 
-MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200");
+MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
 MODULE_PARM(mem, "i");
 MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
 MODULE_PARM(disabled, "i");
@@ -5802,7 +6136,7 @@
 MODULE_PARM(mtrr, "i");
 MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
 MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
 MODULE_PARM(inv24, "i");
 MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
 MODULE_PARM(inverse, "i");
@@ -5855,14 +6189,20 @@
 MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
 MODULE_PARM(cross4MB, "i");
 MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+#ifdef CONFIG_FB_OF
+MODULE_PARM(vmode, "i");
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+MODULE_PARM(cmode, "i");
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
 
-__initfunc(int init_module(void)) {
+int __init init_module(void){
 
 	DBG("init_module")
 
 #ifdef DEBUG
 	if( disabled )
-		return 0;
+		return -ENXIO;
 #endif /* DEBUG */
 
 	if (depth == 0)
diff -u --recursive --new-file v2.3.12/linux/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- v2.3.12/linux/drivers/video/mdacon.c	Fri May 14 17:46:07 1999
+++ linux/drivers/video/mdacon.c	Mon Aug  9 10:25:01 1999
@@ -182,7 +182,7 @@
 
 
 #ifndef MODULE
-__initfunc(void mdacon_setup(char *str, int *ints))
+void __init mdacon_setup(char *str, int *ints)
 {
 	/* command line format: mdacon=<first>,<last> */
 
@@ -201,7 +201,7 @@
 #ifdef MODULE
 static int mda_detect(void)
 #else
-__initfunc(static int mda_detect(void))
+static int __init mda_detect(void)
 #endif
 {
 	int count=0;
@@ -283,7 +283,7 @@
 #ifdef MODULE
 static void mda_initialize(void)
 #else
-__initfunc(static void mda_initialize(void))
+static void __init mda_initialize(void)
 #endif
 {
 	write_mda_b(97, 0x00);		/* horizontal total */
@@ -312,7 +312,7 @@
 #ifdef MODULE
 static const char *mdacon_startup(void)
 #else
-__initfunc(static const char *mdacon_startup(void))
+static const char __init *mdacon_startup(void)
 #endif
 {
 	mda_num_columns = 80;
@@ -591,7 +591,7 @@
 #ifdef MODULE
 void mda_console_init(void)
 #else
-__initfunc(void mda_console_init(void))
+void __init mda_console_init(void)
 #endif
 {
 	if (mda_first_vc > mda_last_vc)
diff -u --recursive --new-file v2.3.12/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.3.12/linux/drivers/video/offb.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/video/offb.c	Mon Aug  9 10:25:01 1999
@@ -320,7 +320,7 @@
      *  Initialisation
      */
 
-__initfunc(void offb_init(void))
+void __init offb_init(void)
 {
     struct device_node *dp;
     unsigned int dpy;
@@ -391,7 +391,7 @@
     }
 }
 
-__initfunc(static int offb_init_driver(struct device_node *dp))
+static int __init offb_init_driver(struct device_node *dp)
 {
 #ifdef CONFIG_FB_ATY
     if (!strncmp(dp->name, "ATY", 3)) {
@@ -444,7 +444,7 @@
     return 0;
 }
 
-__initfunc(static void offb_init_nodriver(struct device_node *dp))
+static void __init offb_init_nodriver(struct device_node *dp)
 {
     int *pp, i;
     unsigned int len;
@@ -488,9 +488,9 @@
     
 }
 
-__initfunc(static void offb_init_fb(const char *name, const char *full_name,
+static void offb_init_fb(const char *name, const char *full_name,
 				    int width, int height, int depth,
-				    int pitch, unsigned long address))
+				    int pitch, unsigned long address)
 {
     int i;
     struct fb_fix_screeninfo *fix;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- v2.3.12/linux/drivers/video/platinumfb.c	Thu Oct  1 10:02:21 1998
+++ linux/drivers/video/platinumfb.c	Mon Aug  9 10:25:01 1999
@@ -581,7 +581,7 @@
 }
 
 
-__initfunc(static int init_platinum(struct fb_info_platinum *info))
+static int __init init_platinum(struct fb_info_platinum *info)
 {
 	struct fb_var_screeninfo var;
 	struct display *disp;
@@ -651,7 +651,7 @@
 	return 1;
 }
 
-__initfunc(void platinum_init(void))
+void __init platinum_init(void)
 {
 #ifndef CONFIG_FB_OF
 	struct device_node *dp;
@@ -670,7 +670,7 @@
 #define invalidate_cache(addr)
 #endif
 
-__initfunc(void platinum_of_init(struct device_node *dp))
+void __init platinum_of_init(struct device_node *dp)
 {
 	struct fb_info_platinum	*info;
 	unsigned long		addr, size;
@@ -854,7 +854,7 @@
 /* 
  * Parse user speficied options (`video=platinumfb:')
  */
-__initfunc(void platinum_setup(char *options, int *ints))
+void __init platinum_setup(char *options, int *ints)
 {
 	char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/pm2fb.c linux/drivers/video/pm2fb.c
--- v2.3.12/linux/drivers/video/pm2fb.c	Mon Mar 15 16:11:31 1999
+++ linux/drivers/video/pm2fb.c	Mon Aug  9 11:39:38 1999
@@ -741,7 +741,7 @@
 		set_memclock(p, p->memclock);
 }
 
-__initfunc(static int pm2fb_conf(struct pm2fb_info* p)) {
+static int __init pm2fb_conf(struct pm2fb_info* p){
 
 	for (p->board=0; board_table[p->board].detect &&
 			!(board_table[p->board].detect(p)); p->board++);
@@ -1526,14 +1526,14 @@
 }
 
 static void pm2fb_set_disp(const void* par, struct display* disp,
-						struct fb_info_gen* info) {
+						   struct fb_info_gen* info) {
 	struct pm2fb_info* i=(struct pm2fb_info* )info;
-	u32 flags;
-	u32 depth;
+	unsigned long flags;
+	unsigned long depth;
 
 	save_flags(flags);
 	cli();
-	disp->screen_base=i->regions.v_fb;
+	disp->screen_base = i->regions.v_fb;
 	switch (depth=((struct pm2fb_par* )par)->depth) {
 #ifdef FBCON_HAS_CFB8
 		case 8:
@@ -1591,7 +1591,7 @@
 		board_table[i->board].cleanup(i);
 }
 
-__initfunc(void pm2fb_init(void)) {
+void __init pm2fb_init(void){
 
 	memset(&fb_info, 0, sizeof(fb_info));
 	if (!pm2fb_conf(&fb_info))
@@ -1624,7 +1624,7 @@
 	MOD_INC_USE_COUNT;
 }
 
-__initfunc(void pm2fb_mode_setup(char* options)) {
+void __init pm2fb_mode_setup(char* options){
 	int i;
 
 	for (i=0; user_mode[i].name[0] &&
@@ -1634,13 +1634,13 @@
 					sizeof(pm2fb_options.user_mode));
 }
 
-__initfunc(void pm2fb_font_setup(char* options)) {
+void __init pm2fb_font_setup(char* options){
 
 	strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
 	pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
 }
 
-__initfunc(void pm2fb_setup(char* options, int* ints)) {
+void __init pm2fb_setup(char* options, int* ints){
 	char* next;
 
 	while (options) {
diff -u --recursive --new-file v2.3.12/linux/drivers/video/promcon.c linux/drivers/video/promcon.c
--- v2.3.12/linux/drivers/video/promcon.c	Thu Apr 22 19:30:08 1999
+++ linux/drivers/video/promcon.c	Mon Aug  9 10:25:01 1999
@@ -104,7 +104,7 @@
 	return b - p;
 }
 
-__initfunc(const char *promcon_startup(void))
+const char __init *promcon_startup(void)
 {
 	const char *display_desc = "PROM";
 	int node;
@@ -128,8 +128,8 @@
 	return display_desc;
 }
 
-__initfunc(static void
-promcon_init_unimap(struct vc_data *conp))
+static void __init 
+promcon_init_unimap(struct vc_data *conp)
 {
 	mm_segment_t old_fs = get_fs();
 	struct unipair *p, *p1;
@@ -591,7 +591,7 @@
 	con_invert_region:	NULL,
 };
 
-__initfunc(void prom_con_init(void))
+void __init prom_con_init(void)
 {
 #ifdef CONFIG_DUMMY_CONSOLE
 	if (conswitchp == &dummy_con)
diff -u --recursive --new-file v2.3.12/linux/drivers/video/q40fb.c linux/drivers/video/q40fb.c
--- v2.3.12/linux/drivers/video/q40fb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/q40fb.c	Mon Aug  9 11:39:38 1999
@@ -6,6 +6,8 @@
 #include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -15,8 +17,10 @@
 #include <linux/module.h>
 #include <asm/pgtable.h>
 
+#include <video/fbcon.h>
 #include <video/fbcon-cfb16.h>
 
+#define FBIOSETSCROLLMODE   0x4611
 
 #define Q40_PHYS_SCREEN_ADDR 0xFE800000
 static unsigned long q40_screen_addr;
@@ -212,7 +216,7 @@
   blue>>=10;
 
     if (regno < 16) {
-      fbcon_cmap_cfb16[regno] = ((red & 31) <<5) |
+      fbcon_cmap_cfb16[regno] = ((red & 31) <<6) |
 	                         ((green & 31) << 11) |
 	                         (blue & 63);
     }
@@ -275,6 +279,27 @@
 		      unsigned int cmd, unsigned long arg, int con,
 		      struct fb_info *info)
 {
+#if 0
+        unsigned long i;
+	struct display *display;
+
+	if (con>=0)
+	  display = &fb_display[con];
+	else
+	  display = &disp[0];
+
+        if (cmd == FBIOSETSCROLLMODE)
+	  {
+	    i = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long));
+	    if (!i) 
+	      {
+		copy_from_user(&i, (void *)arg, sizeof(unsigned long));
+		display->scrollmode = i;
+	      }
+	    q40_updatescrollmode(display);
+	    return i;
+	  }
+#endif
 	return -EINVAL;
 }
 
@@ -302,6 +327,8 @@
    display->inverse = 0;
    display->line_length = fix.line_length;
 
+   display->scrollmode = SCROLL_YREDRAW;
+
 #ifdef FBCON_HAS_CFB16
    display->dispsw = &fbcon_cfb16;
    disp->dispsw_data = fbcon_cmap_cfb16;
@@ -312,6 +339,9 @@
   
 void q40fb_init(void)
 {
+
+        if ( !MACH_IS_Q40)
+	  return;
 #if 0
         q40_screen_addr = kernel_map(Q40_PHYS_SCREEN_ADDR, 1024*1024,
 					   KERNELMAP_NO_COPYBACK, NULL);
diff -u --recursive --new-file v2.3.12/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- v2.3.12/linux/drivers/video/retz3fb.c	Thu Feb 25 10:02:11 1999
+++ linux/drivers/video/retz3fb.c	Mon Aug  9 11:41:05 1999
@@ -109,6 +109,7 @@
 	unsigned long physregs;
 	int currcon;
 	int current_par_valid; /* set to 0 by memset */
+	int blitbusy;
 	struct display disp;
 	struct retz3fb_par current_par;
 	unsigned char color_table [256][3];
@@ -178,11 +179,7 @@
 	"640x480", {		/* 640x480, 8 bpp */
 	    640, 480, 640, 480, 0, 0, 8, 0,
 	    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-#if 1
 	    0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
-#else
-	    0, 0, -1, -1, FB_ACCELF_TEXT, 38461, 28, 32, 12, 10, 96, 2,
-#endif
 	    FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
 	}
     },
@@ -265,7 +262,7 @@
  *    Interface used by the world
  */
 
-void retz3fb_setup(char *options, int *ints);
+void retz3fb_setup(char *options);
 
 static int retz3fb_open(struct fb_info *info, int user);
 static int retz3fb_release(struct fb_info *info, int user);
@@ -346,7 +343,7 @@
 static int get_video_mode(const char *name);
 
 
-/* -------------------- Hardware specific routines -------------------------- */
+/* -------------------- Hardware specific routines ------------------------- */
 
 static unsigned short find_fq(unsigned int freq)
 {
@@ -959,6 +956,21 @@
 }
 
 
+static inline void retz3_busy(struct display *p)
+{
+	struct retz3_fb_info *zinfo = retz3info(p->fb_info);
+	volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
+	unsigned char blt_status;
+
+	if (zinfo->blitbusy) {
+		do{
+			blt_status = *((acm) + (ACM_START_STATUS + 2));
+		}while ((blt_status & 1) == 0);
+		zinfo->blitbusy = 0;
+	}
+}
+
+
 static void retz3_bitblt (struct display *p,
 			  unsigned short srcx, unsigned short srcy,
 			  unsigned short destx, unsigned short desty,
@@ -973,7 +985,6 @@
 	unsigned short mod;
 	unsigned long tmp;
 	unsigned long pat, src, dst;
-	unsigned char blt_status;
 
 	int i, xres_virtual = var->xres_virtual;
 	short bpp = (var->bits_per_pixel & 0xff);
@@ -983,16 +994,7 @@
 
 	tmp = mask | (mask << 16);
 
-#if 0
-	/*
-	 * Check for blitter finished before we start messing with the
-	 * pattern.
-	 */
-	do{
-		blt_status = *(((volatile unsigned char *)acm) +
-			       (ACM_START_STATUS + 2));
-	}while ((blt_status & 1) == 0);
-#endif
+	retz3_busy(p);
 
 	i = 0;
 	do{
@@ -1042,23 +1044,7 @@
 
 	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
 	*(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
-
-	/*
-	 * No reason to wait for the blitter to finish, it is better
-	 * just to check if it has finished before we use it again.
-	 */
-#if 1
-#if 0
-	while ((*(((volatile unsigned char *)acm) +
-		  (ACM_START_STATUS + 2)) & 1) == 0);
-#else
-	do{
-		blt_status = *(((volatile unsigned char *)acm) +
-			       (ACM_START_STATUS + 2));
-	}
-	while ((blt_status & 1) == 0);
-#endif
-#endif
+	zinfo->blitbusy = 1;
 }
 
 #if 0
@@ -1192,7 +1178,6 @@
 }
 
 
-#if 1
 static void retz3fb_set_disp(int con, struct fb_info *info)
 {
 	struct fb_fix_screeninfo fix;
@@ -1243,7 +1228,6 @@
 		break;
 	}
 }
-#endif
 
 
 /*
@@ -1407,7 +1391,7 @@
 };
 
 
-__initfunc(void retz3fb_setup(char *options, int *ints))
+void __init retz3fb_setup(char *options, int *ints)
 {
 	char *this_opt;
 
@@ -1422,7 +1406,7 @@
 		} else if (!strncmp(this_opt, "font:", 5)) {
 			strncpy(fontname, this_opt+5, 39);
 			fontname[39] = '\0';
-		}else
+		} else
 			z3fb_mode = get_video_mode(this_opt);
 	}
 }
@@ -1432,7 +1416,7 @@
  *    Initialization
  */
 
-__initfunc(void retz3fb_init(void))
+void __init retz3fb_init(void)
 {
 	unsigned long board_addr, board_size;
 	unsigned int key;
@@ -1576,11 +1560,11 @@
  *    Get a Video Mode
  */
 
-__initfunc(static int get_video_mode(const char *name))
+static int __init get_video_mode(const char *name)
 {
 	short i;
 
-	for (i = 0; i <= NUM_TOTAL_MODES; i++)
+	for (i = 0; i < NUM_TOTAL_MODES; i++)
 		if (!strcmp(name, retz3fb_predefined[i].name)){
 			retz3fb_default = retz3fb_predefined[i].var;
 			return i;
@@ -1613,8 +1597,8 @@
  */
 
 #ifdef FBCON_HAS_CFB8
-static void fbcon_retz3_8_bmove(struct display *p, int sy, int sx,
-				int dy, int dx, int height, int width)
+static void retz3_8_bmove(struct display *p, int sy, int sx,
+			  int dy, int dx, int height, int width)
 {
 	int fontwidth = fontwidth(p);
 
@@ -1633,8 +1617,8 @@
 		     0xffff);
 }
 
-static void fbcon_retz3_8_clear(struct vc_data *conp, struct display *p,
-				int sy, int sx, int height, int width)
+static void retz3_8_clear(struct vc_data *conp, struct display *p,
+			  int sy, int sx, int height, int width)
 {
 	unsigned short col;
 	int fontwidth = fontwidth(p);
@@ -1657,9 +1641,42 @@
 		     col);
 }
 
+
+static void retz3_putc(struct vc_data *conp, struct display *p, int c,
+		       int yy, int xx)
+{
+	retz3_busy(p);
+	fbcon_cfb8_putc(conp, p, c, yy, xx);
+}
+
+
+static void retz3_putcs(struct vc_data *conp, struct display *p,
+			const unsigned short *s, int count,
+			int yy, int xx)
+{
+	retz3_busy(p);
+	fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+}
+
+
+static void retz3_revc(struct display *p, int xx, int yy)
+{
+	retz3_busy(p);
+	fbcon_cfb8_revc(p, xx, yy);
+}
+
+
+static void retz3_clear_margins(struct vc_data* conp, struct display* p,
+				int bottom_only)
+{
+	retz3_busy(p);
+	fbcon_cfb8_clear_margins(conp, p, bottom_only);
+}
+
+
 static struct display_switch fbcon_retz3_8 = {
-    fbcon_cfb8_setup, fbcon_retz3_8_bmove, fbcon_retz3_8_clear,
-    fbcon_cfb8_putc, fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL,
-    fbcon_cfb8_clear_margins, FONTWIDTH(8)
+    fbcon_cfb8_setup, retz3_8_bmove, retz3_8_clear,
+    retz3_putc, retz3_putcs, retz3_revc, NULL, NULL,
+    retz3_clear_margins, FONTWIDTH(8)
 };
 #endif
diff -u --recursive --new-file v2.3.12/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.3.12/linux/drivers/video/sbusfb.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/video/sbusfb.c	Mon Aug  9 10:25:01 1999
@@ -743,7 +743,7 @@
      *  Setup: parse used options
      */
 
-__initfunc(void sbusfb_setup(char *options, int *ints))
+void __init sbusfb_setup(char *options, int *ints)
 {
 	char *p;
 	
@@ -960,8 +960,8 @@
      
 extern void (*prom_palette)(int);
 
-__initfunc(static void sbusfb_init_fb(int node, int parent, int fbtype,
-				      struct linux_sbus_device *sbdp))
+static void __init sbusfb_init_fb(int node, int parent, int fbtype,
+				      struct linux_sbus_device *sbdp)
 {
 	struct fb_fix_screeninfo *fix;
 	struct fb_var_screeninfo *var;
@@ -1151,7 +1151,7 @@
 	return FBTYPE_NOTYPE;
 }
 
-__initfunc(void sbusfb_init(void))
+void __init sbusfb_init(void)
 {
 	int type;
 	struct linux_sbus_device *sbdp;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c
--- v2.3.12/linux/drivers/video/sgivwfb.c	Fri Apr 16 08:20:23 1999
+++ linux/drivers/video/sgivwfb.c	Mon Aug  9 10:25:01 1999
@@ -919,7 +919,7 @@
   return 0;
 }
 
-__initfunc(void sgivwfb_setup(char *options, int *ints))
+void __init sgivwfb_setup(char *options, int *ints)
 {
   char *this_opt;
 
@@ -938,7 +938,7 @@
 /*
  *  Initialisation
  */
-__initfunc(void sgivwfb_init(void))
+void __init sgivwfb_init(void)
 {
   printk("sgivwfb: framebuffer at 0x%lx, size %ldk\n",
 	 sgivwfb_mem_phys, sgivwfb_mem_size/1024);
diff -u --recursive --new-file v2.3.12/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- v2.3.12/linux/drivers/video/skeletonfb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/skeletonfb.c	Mon Aug  9 10:25:01 1999
@@ -297,7 +297,7 @@
      *  Initialization
      */
 
-__initfunc(void xxxfb_init(void))
+void __init xxxfb_init(void)
 {
     fb_info.gen.fbhw = &xxx_switch;
     fb_info.gen.fbhw->detect();
@@ -345,7 +345,7 @@
      *  Setup
      */
 
-__initfunc(void xxxfb_setup(char *options, int *ints))
+void __init xxxfb_setup(char *options, int *ints)
 {
     /* Parse user speficied options (`video=xxxfb:') */
 }
diff -u --recursive --new-file v2.3.12/linux/drivers/video/tcxfb.c linux/drivers/video/tcxfb.c
--- v2.3.12/linux/drivers/video/tcxfb.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/tcxfb.c	Mon Aug  9 10:25:01 1999
@@ -206,7 +206,7 @@
 
 static char idstring[60] __initdata = { 0 };
 
-__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb))
+char __init *tcxfb_init(struct fb_info_sbusfb *fb)
 {
 	struct fb_fix_screeninfo *fix = &fb->fix;
 	struct display *disp = &fb->disp;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c
--- v2.3.12/linux/drivers/video/valkyriefb.c	Thu Oct  1 10:02:21 1998
+++ linux/drivers/video/valkyriefb.c	Mon Aug  9 10:25:01 1999
@@ -471,7 +471,7 @@
 	}
 }
 
-__initfunc(static void init_valkyrie(struct fb_info_valkyrie *p))
+static void __init init_valkyrie(struct fb_info_valkyrie *p)
 {
 	struct fb_par_valkyrie *par = &p->par;
 	struct fb_var_screeninfo var;
@@ -584,7 +584,7 @@
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 
-__initfunc(void valkyriefb_init(void))
+void __init valkyriefb_init(void)
 {
 #ifndef CONFIG_FB_OF
 	struct device_node *dp;
@@ -595,7 +595,7 @@
 #endif /* CONFIG_FB_OF */
 }
 
-__initfunc(void valkyrie_of_init(struct device_node *dp))
+void __init valkyrie_of_init(struct device_node *dp)
 {
 	struct fb_info_valkyrie	*p;
 	unsigned long addr, size;
@@ -848,7 +848,7 @@
 /*
  * Parse user speficied options (`video=valkyriefb:')
  */
-__initfunc(void valkyriefb_setup(char *options, int *ints))
+void __init valkyriefb_setup(char *options, int *ints)
 {
 	char *this_opt;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.3.12/linux/drivers/video/vesafb.c	Tue May 11 09:55:45 1999
+++ linux/drivers/video/vesafb.c	Mon Aug  9 11:35:04 1999
@@ -96,8 +96,7 @@
 static int             currcon   = 0;
 
 static int             pmi_setpal = 0;	/* pmi for palette changes ??? */
-static int             ypan       = 0;
-static int             ywrap      = 0;
+static int             ypan       = 0;  /* 0..nothing, 1..ypan, 2..ywrap */
 static unsigned short  *pmi_base  = 0;
 static void            (*pmi_start)(void);
 static void            (*pmi_pal)(void);
@@ -130,13 +129,13 @@
 {
 	int offset;
 
-	if (!ypan && !ywrap)
+	if (!ypan)
 		return -EINVAL;
 	if (var->xoffset)
 		return -EINVAL;
-	if (ypan && var->yoffset+var->yres > var->yres_virtual)
+	if (var->yoffset > var->yres_virtual)
 		return -EINVAL;
-	if (ywrap && var->yoffset > var->yres_virtual)
+	if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
 		return -EINVAL;
 
 	offset = (var->yoffset * video_linelength + var->xoffset) / 4;
@@ -154,7 +153,7 @@
 
 static int vesafb_update_var(int con, struct fb_info *info)
 {
-	if (con == currcon && (ywrap || ypan)) {
+	if (con == currcon && ypan) {
 		struct fb_var_screeninfo *var = &fb_display[currcon].var;
 		return vesafb_pan_display(var,con,info);
 	}
@@ -172,8 +171,8 @@
 	fix->type = video_type;
 	fix->visual = video_visual;
 	fix->xpanstep  = 0;
-	fix->ypanstep  = (ywrap || ypan)  ? 1 : 0;
-	fix->ywrapstep =  ywrap           ? 1 : 0;
+	fix->ypanstep  = ypan     ? 1 : 0;
+	fix->ywrapstep = (ypan>1) ? 1 : 0;
 	fix->line_length=video_linelength;
 	return 0;
 }
@@ -245,7 +244,7 @@
 	}
 	memcpy(&vesafb_sw, sw, sizeof(*sw));
 	display->dispsw = &vesafb_sw;
-	if (!ypan && !ywrap) {
+	if (!ypan) {
 		display->scrollmode = SCROLL_YREDRAW;
 		vesafb_sw.bmove = fbcon_redraw_bmove;
 	}
@@ -274,7 +273,7 @@
 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
 		return 0;
 
-	if (ypan || ywrap) {
+	if (ypan) {
 		if (vesafb_defined.yres_virtual != var->yres_virtual) {
 			vesafb_defined.yres_virtual = var->yres_virtual;
 			if (con != -1) {
@@ -486,11 +485,11 @@
 		if (! strcmp(this_opt, "inverse"))
 			inverse=1;
 		else if (! strcmp(this_opt, "redraw"))
-			ywrap=0,ypan=0;
+			ypan=0;
 		else if (! strcmp(this_opt, "ypan"))
-			ywrap=0,ypan=1;
+			ypan=1;
 		else if (! strcmp(this_opt, "ywrap"))
-			ywrap=1,ypan=0;
+			ypan=2;
 		else if (! strcmp(this_opt, "vgapal"))
 			pmi_setpal=0;
 		else if (! strcmp(this_opt, "pmipal"))
@@ -523,7 +522,7 @@
 	/* Not supported */
 }
 
-__initfunc(void vesafb_init(void))
+void __init vesafb_init(void)
 {
 	int i,j;
 
@@ -551,9 +550,9 @@
 	}
 
 	if (screen_info.vesapm_seg < 0xc000)
-		ywrap = ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
+		ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
 
-	if (ypan || ywrap || pmi_setpal) {
+	if (ypan || pmi_setpal) {
 		pmi_base  = (unsigned short*)(__PAGE_OFFSET+((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
 		pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
 		pmi_pal   = (void*)((char*)pmi_base + pmi_base[2]);
@@ -571,7 +570,7 @@
 				 * memory area and pass it in the ES register to the BIOS function.
 				 */
 				printk("vesafb: can't handle memory requests, pmi disabled\n");
-				ywrap = ypan = pmi_setpal = 0;
+				ypan = pmi_setpal = 0;
 			}
 		}
 	}
@@ -582,13 +581,13 @@
 	vesafb_defined.yres_virtual=video_size / video_linelength;
 	vesafb_defined.bits_per_pixel=video_bpp;
 
-	if ((ypan || ywrap) && vesafb_defined.yres_virtual > video_height) {
+	if (ypan && vesafb_defined.yres_virtual > video_height) {
 		printk("vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
-		       ywrap ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
+		       (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
 	} else {
 		printk("vesafb: scrolling: redraw\n");
 		vesafb_defined.yres_virtual = video_height;
-		ypan = ywrap = 0;
+		ypan = 0;
 	}
 	video_height_virtual = vesafb_defined.yres_virtual;
 
diff -u --recursive --new-file v2.3.12/linux/drivers/video/vfb.c linux/drivers/video/vfb.c
--- v2.3.12/linux/drivers/video/vfb.c	Thu Oct  1 10:02:21 1998
+++ linux/drivers/video/vfb.c	Mon Aug  9 10:25:01 1999
@@ -406,7 +406,7 @@
 }
 
 
-__initfunc(void vfb_setup(char *options, int *ints))
+void __init vfb_setup(char *options, int *ints)
 {
     char *this_opt;
 
@@ -429,7 +429,7 @@
      *  Initialisation
      */
 
-__initfunc(void vfb_init(void))
+void __init vfb_init(void)
 {
     if (!vfb_enable)
 	return;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- v2.3.12/linux/drivers/video/vga16fb.c	Wed May 26 16:55:40 1999
+++ linux/drivers/video/vga16fb.c	Mon Aug  9 11:41:32 1999
@@ -1003,7 +1003,7 @@
 	}
 }
 
-__initfunc(void vga16fb_init(void))
+void __init vga16_init(void)
 {
 	int i,j;
 
@@ -1047,12 +1047,35 @@
 	vga16fb_set_disp(-1, &vga16fb);
 
 	if (register_framebuffer(&vga16fb.fb_info)<0)
-		return;
+		return -EINVAL;
 
 	printk("fb%d: %s frame buffer device\n",
 	       GET_FB_IDX(vga16fb.fb_info.node), vga16fb.fb_info.modename);
+
+	return 0;
+}
+
+#ifndef MODULE
+__initfunc(void vga16fb_init(void))
+{
+    vga16_init();
+}
+
+#else /* MODULE */
+
+__initfunc(int init_module(void))
+{
+    return vga16_init();
+}
+
+void cleanup_module(void)
+{
+    unregister_framebuffer(&vga16fb.fb_info);
+    release_region(0x3c0, 32);
+    iounmap(vga16fb.video_vbase);
 }
 
+#endif
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.3.12/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.3.12/linux/drivers/video/vgacon.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/video/vgacon.c	Mon Aug  9 10:25:01 1999
@@ -116,7 +116,7 @@
 static unsigned int    vga_rolled_over = 0;
 
 
-void no_scroll(char *str, int *ints)
+static int __init no_scroll(char *str)
 {
 	/*
 	 * Disabling scrollback is required for the Braillex ib80-piezo
@@ -124,8 +124,11 @@
 	 * Use the "no-scroll" bootflag.
 	 */
 	vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
+	return 1;
 }
 
+__setup("no-scroll", no_scroll);
+
 /*
  * By replacing the four outb_p with two back to back outw, we can reduce
  * the window of opportunity to see text mislocated to the RHS of the
@@ -159,7 +162,7 @@
 	restore_flags(flags);
 }
 
-__initfunc(static const char *vgacon_startup(void))
+static const char __init *vgacon_startup(void)
 {
 	const char *display_desc = NULL;
 	u16 saved1, saved2;
diff -u --recursive --new-file v2.3.12/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.3.12/linux/drivers/video/virgefb.c	Thu Feb 25 10:02:11 1999
+++ linux/drivers/video/virgefb.c	Mon Aug  9 11:39:38 1999
@@ -85,10 +85,21 @@
                 (*((unsigned word volatile *)(CyberRegs + reg)) = dat)
 #define wl_3d(reg,dat) \
                 (*((unsigned long volatile *)(CyberRegs + reg)) = dat)
-
 #define rl_3d(reg) \
                 (*((unsigned long volatile *)(CyberRegs + reg)))
 
+#define Select_Zorro2_FrameBuffer(flag) \
+	do { \
+		*((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x08)) = \
+		((flag * 0x40) & 0xffff); asm volatile ("nop"); \
+	} while (0)
+/*
+ *	may be needed when we initialize the board?
+ *	8bit: flag = 2, 16 bit: flag = 1, 24/32bit: flag = 0 
+ *	_when_ the board is initialized, depth doesnt matter, we allways write
+ *	to the same address, aperture seems not to matter on Z2.
+ */
+
 struct virgefb_par {
    int xres;
    int yres;
@@ -175,7 +186,10 @@
  *    Predefined Video Modes
  */
 
-static struct fb_videomode virgefb_predefined[] __initdata = {
+static struct {
+    const char *name;
+    struct fb_var_screeninfo var;
+} virgefb_predefined[] __initdata = {
     {
 	"640x480-8", {		/* Cybervision 8 bpp */
 	    640, 480, 640, 480, 0, 0, 8, 0,
@@ -236,28 +250,28 @@
 	"1024x768-16", {         /* Cybervision 16 bpp */
 	    1024, 768, 1024, 768, 0, 0, 16, 0,
 	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
        }
     }, {
 	"1152x886-16", {         /* Cybervision 16 bpp */
 	    1152, 886, 1152, 886, 0, 0, 16, 0,
 	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
        }
     }, {
 	"1280x1024-16", {         /* Cybervision 16 bpp */
 	    1280, 1024, 1280, 1024, 0, 0, 16, 0,
 	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
        }
     }, {
 	"1600x1200-16", {         /* Cybervision 16 bpp */
 	    1600, 1200, 1600, 1200, 0, 0, 16, 0,
 	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
        }
     }
@@ -268,10 +282,6 @@
 
 
 static int Cyberfb_inverse = 0;
-#if 0
-static int Cyberfb_Cyber8 = 0;        /* Use Cybervision board */
-static int Cyberfb_Cyber16 = 0;       /* Use Cybervision board */
-#endif
 
 /*
  *    Some default modes
@@ -392,6 +402,7 @@
 	} else {
 		CyberSize = 0x00400000; /* 4 MB */
 	}
+
 	memset ((char*)CyberMem, 0, CyberSize);
 
 	/* Disable hardware cursor */
@@ -667,7 +678,13 @@
  * CV3D low-level support
  */
 
-#define Cyber3D_WaitQueue(v)	 { do { while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); } while (0); }
+#define Cyber3D_WaitQueue(v) \
+{ \
+	 do { \
+		while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); \
+	 } \
+	while (0); \
+}
 
 static inline void Cyber3D_WaitBusy(void)
 {
@@ -699,11 +716,22 @@
   */
 
 static void Cyber3D_BitBLT(u_short curx, u_short cury, u_short destx,
-			   u_short desty, u_short width, u_short height)
+			   u_short desty, u_short width, u_short height, u_short depth)
 {
-	unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_DST_8BPP;
+	unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_BLT_COPY;
 
-	blitcmd |= S3V_BLT_COPY;
+	switch (depth) {
+#ifdef FBCON_HAS_CFB8
+		case 8 :
+			blitcmd |= S3V_DST_8BPP;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16 :
+			blitcmd |= S3V_DST_16BPP;
+			break;
+#endif
+	}
 
 	/* Set drawing direction */
 	/* -Y, X maj, -X (default) */
@@ -748,16 +776,29 @@
  */
 
 static void Cyber3D_RectFill(u_short x, u_short y, u_short width,
-			     u_short height, u_short color)
+			     u_short height, u_short color, u_short depth)
 {
 	unsigned int tmp;
-	unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW | S3V_DST_8BPP |
+	unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW |
 		S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
 
 	if (blit_maybe_busy)
 		Cyber3D_WaitBusy();
 	blit_maybe_busy = 1;
 
+	switch (depth) {
+#ifdef FBCON_HAS_CFB8
+		case 8 :
+			blitcmd |= S3V_DST_8BPP;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16 :
+			blitcmd |= S3V_DST_16BPP;
+			break;
+#endif
+	}
+
 	tmp = color & 0xff;
 	wl_3d(0xa4f4, tmp);
 
@@ -1087,7 +1128,7 @@
 };
 
 
-__initfunc(void virgefb_setup(char *options, int *ints))
+void __init virgefb_setup(char *options, int *ints)
 {
 	char *this_opt;
 
@@ -1121,7 +1162,7 @@
  *    Initialization
  */
 
-__initfunc(void virgefb_init(void))
+void __init virgefb_init(void)
 {
 	struct virgefb_par par;
 	unsigned long board_addr;
@@ -1157,7 +1198,6 @@
 	else
 	{
 		CyberVGARegs = (unsigned long)ioremap(board_addr +0x0c000000, 0x00010000);
-
 		CyberRegs_phys = board_addr + 0x05000000;
 		CyberMem_phys  = board_addr + 0x04000000;	/* was 0x04800000 */
 		CyberRegs = ioremap(CyberRegs_phys, 0x00010000);
@@ -1242,7 +1282,7 @@
  *    Get a Video Mode
  */
 
-__initfunc(static int get_video_mode(const char *name))
+static int __init get_video_mode(const char *name)
 {
 	int i;
 
@@ -1269,7 +1309,7 @@
         sx *= 8; dx *= 8; width *= 8;
         Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
                        (u_short)(dy*fontheight(p)), (u_short)width,
-                       (u_short)(height*fontheight(p)));
+                       (u_short)(height*fontheight(p)), 8);
 }
 
 static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
@@ -1281,7 +1321,7 @@
         bg = attr_bgcol_ec(p,conp);
         Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
                          (u_short)width, (u_short)(height*fontheight(p)),
-                         (u_short)bg);
+                         (u_short)bg, 8);
 }
 
 static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy,
@@ -1326,10 +1366,10 @@
 static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy,
                                int dx, int height, int width)
 {
-        sx *= 16; dx *= 16; width *= 16;
+        sx *= 8; dx *= 8; width *= 8;
         Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
                        (u_short)(dy*fontheight(p)), (u_short)width,
-                       (u_short)(height*fontheight(p)));
+                       (u_short)(height*fontheight(p)), 16);
 }
                 
 static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy,
@@ -1337,11 +1377,11 @@
 {
         unsigned char bg;   
                 
-        sx *= 16; width *= 16;
+        sx *= 8; width *= 8;
         bg = attr_bgcol_ec(p,conp);
         Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
                          (u_short)width, (u_short)(height*fontheight(p)),
-                         (u_short)bg);
+                         (u_short)bg, 16);
 }
    
 static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy,
diff -u --recursive --new-file v2.3.12/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.12/linux/fs/binfmt_aout.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/binfmt_aout.c	Tue Aug  3 10:18:39 1999
@@ -36,13 +36,7 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 
 static struct linux_binfmt aout_format = {
-	NULL,
-#ifndef MODULE
-	NULL,
-#else
-	&__this_module,
-#endif
-	load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
+	NULL, THIS_MODULE, load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
 };
 
 static void set_brk(unsigned long start, unsigned long end)
@@ -559,17 +553,15 @@
 }
 
 
-int __init init_aout_binfmt(void)
+static int __init init_aout_binfmt(void)
 {
 	return register_binfmt(&aout_format);
 }
 
-#ifdef MODULE
-int init_module(void) {
-	return init_aout_binfmt();
-}
-
-void cleanup_module( void) {
+static void __exit exit_aout_binfmt(void)
+{
 	unregister_binfmt(&aout_format);
 }
-#endif
+
+module_init(init_aout_binfmt)
+module_exit(exit_aout_binfmt)
diff -u --recursive --new-file v2.3.12/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.12/linux/fs/binfmt_elf.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/binfmt_elf.c	Tue Aug  3 10:18:39 1999
@@ -64,13 +64,7 @@
 #define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
 
 static struct linux_binfmt elf_format = {
-	NULL,
-#ifndef MODULE
-	NULL,
-#else
-	&__this_module,
-#endif
-	load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
+	NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
 };
 
 static void set_brk(unsigned long start, unsigned long end)
@@ -1296,26 +1290,16 @@
 }
 #endif		/* USE_ELF_CORE_DUMP */
 
-int __init init_elf_binfmt(void)
+static int __init init_elf_binfmt(void)
 {
 	return register_binfmt(&elf_format);
 }
 
-#ifdef MODULE
-
-int init_module(void)
-{
-	/* Install the COFF, ELF and XOUT loaders.
-	 * N.B. We *rely* on the table being the right size with the
-	 * right number of free slots...
-	 */
-	return init_elf_binfmt();
-}
-
-
-void cleanup_module( void)
+static void __exit exit_elf_binfmt(void)
 {
 	/* Remove the COFF and ELF loaders. */
 	unregister_binfmt(&elf_format);
 }
-#endif
+
+module_init(init_elf_binfmt)
+module_exit(exit_elf_binfmt)
diff -u --recursive --new-file v2.3.12/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c
--- v2.3.12/linux/fs/binfmt_em86.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/binfmt_em86.c	Tue Aug  3 10:18:39 1999
@@ -105,27 +105,18 @@
 }
 
 struct linux_binfmt em86_format = {
-	NULL,
-#ifndef MODULE
-	NULL,
-#else
-	&__this_module,
-#endif
-	load_em86, NULL, NULL, 0
+	NULL, THIS_MODULE, load_em86, NULL, NULL, 0
 };
 
-int __init init_em86_binfmt(void)
+static int __init init_em86_binfmt(void)
 {
 	return register_binfmt(&em86_format);
 }
 
-#ifdef MODULE
-int init_module(void)
+static void __exit exit_em86_binfmt(void)
 {
-	return init_em86_binfmt();
-}
-
-void cleanup_module( void) {
 	unregister_binfmt(&em86_format);
 }
-#endif
+
+module_init(init_em86_binfmt)
+module_exit(exit_em86_binfmt)
diff -u --recursive --new-file v2.3.12/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.3.12/linux/fs/binfmt_misc.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/binfmt_misc.c	Tue Aug  3 10:18:39 1999
@@ -64,13 +64,7 @@
 static int entry_proc_setup(struct binfmt_entry *e);
 
 static struct linux_binfmt misc_format = {
-	NULL,
-#ifndef MODULE
-	NULL,
-#else
-	&__this_module,
-#endif
-	load_misc_binary, NULL, NULL, 0
+	NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
 };
 
 static struct proc_dir_entry *bm_dir = NULL;
@@ -495,7 +489,7 @@
 }
 #endif
 
-int __init init_misc_binfmt(void)
+static int __init init_misc_binfmt(void)
 {
 	int error = -ENOENT;
 	struct proc_dir_entry *status = NULL, *reg;
@@ -530,14 +524,7 @@
 	goto out;
 }
 
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
-	return init_misc_binfmt();
-}
-
-void cleanup_module(void)
+static void __exit exit_misc_binfmt(void)
 {
 	unregister_binfmt(&misc_format);
 	remove_proc_entry("register", bm_dir);
@@ -545,5 +532,8 @@
 	clear_entries();
 	remove_proc_entry("sys/fs/binfmt_misc", NULL);
 }
-#endif
-#undef VERBOSE_STATUS
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_misc_binfmt)
+module_exit(exit_misc_binfmt)
diff -u --recursive --new-file v2.3.12/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v2.3.12/linux/fs/binfmt_script.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/binfmt_script.c	Tue Aug  3 10:18:39 1999
@@ -101,27 +101,18 @@
 }
 
 struct linux_binfmt script_format = {
-	NULL,
-#ifndef MODULE
-	NULL,
-#else
-	&__this_module,
-#endif
-	load_script, NULL, NULL, 0
+	NULL, THIS_MODULE, load_script, NULL, NULL, 0
 };
 
-int __init init_script_binfmt(void)
+static int __init init_script_binfmt(void)
 {
 	return register_binfmt(&script_format);
 }
 
-#ifdef MODULE
-int init_module(void)
+static void __exit exit_script_binfmt(void)
 {
-	return init_script_binfmt();
-}
-
-void cleanup_module( void) {
 	unregister_binfmt(&script_format);
 }
-#endif
+
+module_init(init_script_binfmt)
+module_exit(exit_script_binfmt)
diff -u --recursive --new-file v2.3.12/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.12/linux/fs/buffer.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/buffer.c	Mon Aug  9 11:49:24 1999
@@ -840,7 +840,7 @@
  * pressures on different devices - thus the (currently unused)
  * 'dev' parameter.
  */
-int too_many_dirty_buffers;
+static int too_many_dirty_buffers;
 
 void balance_dirty(kdev_t dev)
 {
@@ -1036,13 +1036,6 @@
 	}
 }
 
-static void put_unused_buffer_head(struct buffer_head *bh)
-{
-	spin_lock(&unused_list_lock);
-	__put_unused_buffer_head(bh);
-	spin_unlock(&unused_list_lock);
-}
-
 /*
  * Reserve NR_RESERVED buffer heads for async IO requests to avoid
  * no-buffer-head deadlock.  Return NULL on failure; waiting for
@@ -1148,11 +1141,13 @@
  */
 no_grow:
 	if (head) {
+		spin_lock(&unused_list_lock);
 		do {
 			bh = head;
 			head = head->b_this_page;
-			put_unused_buffer_head(bh);
+			__put_unused_buffer_head(bh);
 		} while (head);
+		spin_unlock(&unused_list_lock);
 
 		/* Wake up any waiters ... */
 		wake_up(&buffer_wait);
@@ -1201,8 +1196,8 @@
 		PAGE_BUG(page);
 	/*
 	 * Allocate async buffer heads pointing to this page, just for I/O.
-	 * They show up in the buffer hash table and are registered in
-	 * page->buffers.
+	 * They don't show up in the buffer hash table, but they *are*
+	 * registered in page->buffers.
 	 */
 	head = create_buffers(page_address(page), size, 1);
 	if (page->buffers)
@@ -1528,6 +1523,176 @@
 	return err;
 }
 
+/*
+ * For moronic filesystems that do not allow holes in file.
+ * we allow offset==PAGE_SIZE, bytes==0
+ */
+
+int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	unsigned long block;
+	int err, partial;
+	unsigned long blocksize, start_block, end_block;
+	unsigned long start_offset, start_bytes, end_bytes;
+	unsigned long bbits, blocks, i, len;
+	struct buffer_head *bh, *head;
+	char * target_buf, *target_data;
+	unsigned long data_offset = offset;
+
+	offset = page->offset-inode->i_size;
+	if (offset < 0) 
+		offset = 0;
+	else if (offset >= data_offset)
+		offset = data_offset;
+	bytes += data_offset-offset;
+
+	target_buf = (char *)page_address(page) + offset;
+	target_data = (char *)page_address(page) + data_offset;
+
+	if (!PageLocked(page))
+		BUG();
+
+	blocksize = inode->i_sb->s_blocksize;
+	if (!page->buffers)
+		create_empty_buffers(page, inode, blocksize);
+	head = page->buffers;
+
+	bbits = inode->i_sb->s_blocksize_bits;
+	block = page->offset >> bbits;
+	blocks = PAGE_SIZE >> bbits;
+	start_block = offset >> bbits;
+	end_block = (offset + bytes - 1) >> bbits;
+	start_offset = offset & (blocksize - 1);
+	start_bytes = blocksize - start_offset;
+	if (start_bytes > bytes)
+		start_bytes = bytes;
+	end_bytes = (offset+bytes) & (blocksize - 1);
+	if (end_bytes > bytes)
+		end_bytes = bytes;
+
+	if (offset < 0 || offset > PAGE_SIZE)
+		BUG();
+	if (bytes+offset < 0 || bytes+offset > PAGE_SIZE)
+		BUG();
+	if (start_block < 0 || start_block > blocks)
+		BUG();
+	if (end_block < 0 || end_block >= blocks)
+		BUG();
+	// FIXME: currently we assume page alignment.
+	if (page->offset & (PAGE_SIZE-1))
+		BUG();
+
+	i = 0;
+	bh = head;
+	partial = 0;
+	do {
+		if (!bh)
+			BUG();
+
+		if ((i < start_block) || (i > end_block)) {
+			if (!buffer_uptodate(bh))
+				partial = 1;
+			goto skip;
+		}
+
+		/*
+		 * If the buffer is not up-to-date, we need to ask the low-level
+		 * FS to do something for us (we used to have assumptions about
+		 * the meaning of b_blocknr etc, that's bad).
+		 *
+		 * If "update" is set, that means that the low-level FS should
+		 * try to make sure that the block is up-to-date because we're
+		 * not going to fill it completely.
+		 */
+		bh->b_end_io = end_buffer_io_sync;
+		if (!buffer_mapped(bh)) {
+			err = inode->i_op->get_block(inode, block, bh, 1);
+			if (err)
+				goto out;
+		}
+
+		if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
+			if (buffer_new(bh)) {
+				memset(bh->b_data, 0, bh->b_size);
+			} else {
+				ll_rw_block(READ, 1, &bh);
+				wait_on_buffer(bh);
+				err = -EIO;
+				if (!buffer_uptodate(bh))
+					goto out;
+			}
+		}
+
+		len = blocksize;
+		if (start_offset) {
+			len = start_bytes;
+			start_offset = 0;
+		} else if (end_bytes && (i == end_block)) {
+			len = end_bytes;
+			end_bytes = 0;
+		}
+		err = 0;
+		if (target_buf+len<=target_data)
+			memset(target_buf, 0, len);
+		else if (target_buf<target_data) {
+			memset(target_buf, 0, target_data-target_buf);
+			copy_from_user(target_data, buf,
+					len+target_buf-target_data);
+		} else
+			err = copy_from_user(target_buf, buf, len);
+		target_buf += len;
+		buf += len;
+
+		/*
+		 * we dirty buffers only after copying the data into
+		 * the page - this way we can dirty the buffer even if
+		 * the bh is still doing IO.
+		 *
+		 * NOTE! This also does a direct dirty balace check,
+		 * rather than relying on bdflush just waking up every
+		 * once in a while. This is to catch (and slow down)
+		 * the processes that write tons of buffer..
+		 *
+		 * Note how we do NOT want to do this in the full block
+		 * case: full pages are flushed not by the people who
+		 * dirtied them, but by people who need memory. And we
+		 * should not penalize them for somebody else writing
+		 * lots of dirty pages.
+		 */
+		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);
+		}
+
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+
+skip:
+		i++;
+		block++;
+		bh = bh->b_this_page;
+	} while (bh != head);
+
+	/*
+	 * is this a partial write that happened to make all buffers
+	 * uptodate then we can optimize away a bogus readpage() for
+	 * the next read(). Here we 'discover' wether the page went
+	 * uptodate as a result of this (potentially partial) write.
+	 */
+	if (!partial)
+		SetPageUptodate(page);
+	return bytes;
+out:
+	ClearPageUptodate(page);
+	return err;
+}
+
 
 /*
  * IO completion routine for a buffer_head being used for kiobuf IO: we
@@ -1858,7 +2023,6 @@
 	blocks = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
 	iblock = page->offset >> inode->i_sb->s_blocksize_bits;
 	page->owner = (void *)-1;
-	head = page->buffers;
 	bh = head;
 	nr = 0;
 
@@ -1917,10 +2081,8 @@
 	if (!(page = __get_free_page(GFP_BUFFER)))
 		return 0;
 	bh = create_buffers(page, size, 0);
-	if (!bh) {
-		free_page(page);
-		return 0;
-	}
+	if (!bh)
+		goto no_buffer_head;
 
 	isize = BUFSIZE_INDEX(size);
 
@@ -1950,6 +2112,10 @@
 	mem_map[MAP_NR(page)].buffers = bh;
 	atomic_add(PAGE_SIZE, &buffermem);
 	return 1;
+
+no_buffer_head:
+	free_page(page);
+	return 0;
 }
 
 /*
@@ -2290,12 +2456,7 @@
 				 */
 				atomic_inc(&bh->b_count);
 				spin_unlock(&lru_list_lock);
-				if (major == LOOP_MAJOR && written > 1) {
-					ll_rw_block(WRITEA, 1, &bh);
-					if (buffer_dirty(bh))
-						--written;
-				} else
-					ll_rw_block(WRITE, 1, &bh);
+				ll_rw_block(WRITE, 1, &bh);
 				atomic_dec(&bh->b_count);
 				goto repeat;
 			}
@@ -2319,3 +2480,12 @@
 		}
 	}
 }
+
+static int __init bdflush_init(void)
+{
+	kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	return 0;
+}
+
+module_init(bdflush_init)
+
diff -u --recursive --new-file v2.3.12/linux/fs/exec.c linux/fs/exec.c
--- v2.3.12/linux/fs/exec.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/exec.c	Fri Aug  6 11:11:03 1999
@@ -50,36 +50,6 @@
 
 static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;
 
-void __init binfmt_setup(void)
-{
-#ifdef CONFIG_BINFMT_MISC
-	init_misc_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_ELF
-	init_elf_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_ELF32
-	init_elf32_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_AOUT
-	init_aout_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_AOUT32
-	init_aout32_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_EM86
-	init_em86_binfmt();
-#endif
-
-	/* This cannot be configured out of the kernel */
-	init_script_binfmt();
-}
-
 int register_binfmt(struct linux_binfmt * fmt)
 {
 	struct linux_binfmt ** tmp = &formats;
@@ -98,7 +68,6 @@
 	return 0;	
 }
 
-#ifdef CONFIG_MODULES
 int unregister_binfmt(struct linux_binfmt * fmt)
 {
 	struct linux_binfmt ** tmp = &formats;
@@ -112,7 +81,6 @@
 	}
 	return -EINVAL;
 }
-#endif	/* CONFIG_MODULES */
 
 /* N.B. Error returns must be < 0 */
 int open_dentry(struct dentry * dentry, int mode)
@@ -382,7 +350,7 @@
 
 		current->mm = mm;
 		current->active_mm = mm;
-		switch_mm(active_mm, mm, smp_processor_id());
+		activate_mm(active_mm, mm);
 		mm_release();
 		if (old_mm) {
 			if (active_mm != old_mm) BUG();
diff -u --recursive --new-file v2.3.12/linux/fs/fat/buffer.c linux/fs/fat/buffer.c
--- v2.3.12/linux/fs/fat/buffer.c	Wed Jun 24 14:30:09 1998
+++ linux/fs/fat/buffer.c	Mon Aug  9 11:43:49 1999
@@ -17,195 +17,189 @@
 #  define PRINTK(x)
 #endif
 
-struct buffer_head *fat_bread (
+struct buffer_head *fat_bread(struct super_block *sb, int block)
+{
+	return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
+}
+struct buffer_head *fat_getblk(struct super_block *sb, int block)
+{
+	return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
+}
+void fat_brelse (struct super_block *sb, struct buffer_head *bh)
+{
+	if (bh) 
+		MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
+}
+void fat_mark_buffer_dirty (
 	struct super_block *sb,
-	int block)
+	struct buffer_head *bh,
+	int dirty)
 {
-	struct buffer_head *ret = NULL;
-
-	PRINTK(("fat_bread: block=0x%x\n", block));
-	/*
-	 * Note that the blocksize is 512, 1024 or 2048, but the first read
-	 * is always of size 1024 (or 2048). Doing readahead may be
-	 * counterproductive or just plain wrong.
-	 */
+	MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
+}
+void fat_set_uptodate (
+	struct super_block *sb,
+	struct buffer_head *bh,
+	int val)
+{
+	MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
+}
+int fat_is_uptodate(struct super_block *sb, struct buffer_head *bh)
+{
+	return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
+}
+void fat_ll_rw_block (
+	struct super_block *sb,
+	int opr,
+	int nbreq,
+	struct buffer_head *bh[32])
+{
+	MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
+}
 
-	if(MSDOS_SB(sb)->cvf_format &&
-	   MSDOS_SB(sb)->cvf_format->cvf_bread)
-		return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
+struct buffer_head *default_fat_bread(struct super_block *sb, int block)
+{
+	return bread (sb->s_dev,block,512);
+}
+struct buffer_head *default_fat_getblk(struct super_block *sb, int block)
+{
+	return getblk (sb->s_dev,block,512);
+}
+void default_fat_brelse(struct super_block *sb, struct buffer_head *bh)
+{
+	brelse (bh);
+}
+void default_fat_mark_buffer_dirty (
+	struct super_block *sb,
+	struct buffer_head *bh,
+	int dirty)
+{
+	mark_buffer_dirty (bh,dirty);
+}
+void default_fat_set_uptodate (
+	struct super_block *sb,
+	struct buffer_head *bh,
+	int val)
+{
+	mark_buffer_uptodate(bh, val);
+}
+int default_fat_is_uptodate (struct super_block *sb, struct buffer_head *bh)
+{
+	return buffer_uptodate(bh);
+}
+void default_fat_ll_rw_block (
+	struct super_block *sb,
+	int opr,
+	int nbreq,
+	struct buffer_head *bh[32])
+{
+	ll_rw_block(opr,nbreq,bh);
+}
 
-	if (sb->s_blocksize == 512) {
-		ret = bread (sb->s_dev,block,512);
+struct buffer_head *bigblock_fat_bread (
+	struct super_block *sb,
+	int block)
+{
+	struct buffer_head *ret = NULL;
+	struct buffer_head *real;
+	if (sb->s_blocksize == 1024){
+		real = bread (sb->s_dev,block>>1,1024);
 	} else {
-		struct buffer_head *real;
-		if (sb->s_blocksize == 1024){
-			real = bread (sb->s_dev,block>>1,1024);
-		} else {
-			real = bread (sb->s_dev,block>>2,2048);
-		}
+		real = bread (sb->s_dev,block>>2,2048);
+	}
 
-		if (real != NULL){
-			ret = (struct buffer_head *)
-				kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
-			if (ret != NULL) {
-				/* #Specification: msdos / strategy / special device / dummy blocks
-				 * Many special device (Scsi optical disk for one) use
-				 * larger hardware sector size. This allows for higher
-				 * capacity.
-
-				 * Most of the time, the MS-DOS filesystem that sits
-				 * on this device is totally unaligned. It use logically
-				 * 512 bytes sector size, with logical sector starting
-				 * in the middle of a hardware block. The bad news is
-				 * that a hardware sector may hold data own by two
-				 * different files. This means that the hardware sector
-				 * must be read, patch and written almost all the time.
-
-				 * Needless to say that it kills write performance
-				 * on all OS.
-
-				 * Internally the linux msdos fs is using 512 bytes
-				 * logical sector. When accessing such a device, we
-				 * allocate dummy buffer cache blocks, that we stuff
-				 * with the information of a real one (1k large).
-
-				 * This strategy is used to hide this difference to
-				 * the core of the msdos fs. The slowdown is not
-				 * hidden though!
-				 */
-				/*
-				 * The memset is there only to catch errors. The msdos
-				 * fs is only using b_data
-				 */
-				memset (ret,0,sizeof(*ret));
-				ret->b_data = real->b_data;
-				if (sb->s_blocksize == 2048) {
-					if (block & 3) ret->b_data += (block & 3) << 9;
-				}else{
-					if (block & 1) ret->b_data += 512;
-				}
-				ret->b_next = real;
+	if (real != NULL) {
+		ret = (struct buffer_head *)
+			kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
+		if (ret != NULL) {
+			/* #Specification: msdos / strategy / special device / dummy blocks
+			 * Many special device (Scsi optical disk for one) use
+			 * larger hardware sector size. This allows for higher
+			 * capacity.
+
+			 * Most of the time, the MS-DOS filesystem that sits
+			 * on this device is totally unaligned. It use logically
+			 * 512 bytes sector size, with logical sector starting
+			 * in the middle of a hardware block. The bad news is
+			 * that a hardware sector may hold data own by two
+			 * different files. This means that the hardware sector
+			 * must be read, patch and written almost all the time.
+
+			 * Needless to say that it kills write performance
+			 * on all OS.
+
+			 * Internally the linux msdos fs is using 512 bytes
+			 * logical sector. When accessing such a device, we
+			 * allocate dummy buffer cache blocks, that we stuff
+			 * with the information of a real one (1k large).
+
+			 * This strategy is used to hide this difference to
+			 * the core of the msdos fs. The slowdown is not
+			 * hidden though!
+			 */
+			/*
+			 * The memset is there only to catch errors. The msdos
+			 * fs is only using b_data
+			 */
+			memset (ret,0,sizeof(*ret));
+			ret->b_data = real->b_data;
+			if (sb->s_blocksize == 2048) {
+				if (block & 3) ret->b_data += (block & 3) << 9;
 			}else{
-				brelse (real);
+				if (block & 1) ret->b_data += 512;
 			}
+			ret->b_next = real;
+		}else{
+			brelse (real);
 		}
 	}
 	return ret;
 }
 
-struct buffer_head *fat_getblk(struct super_block *sb, int block)
-{
-	struct buffer_head *ret = NULL;
-	PRINTK(("fat_getblk: block=0x%x\n", block));
-
-	if (MSDOS_SB(sb)->cvf_format &&
-	    MSDOS_SB(sb)->cvf_format->cvf_getblk)
-		return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
-
-	if (sb->s_blocksize == 512){
-		ret = getblk (sb->s_dev,block,512);
-	} else {
-		/*
-		 * #Specification: msdos / special device / writing
-		 * A write is always preceded by a read of the complete block
-		 * (large hardware sector size). This defeat write performance.
-		 * There is a possibility to optimize this when writing large
-		 * chunk by making sure we are filling large block. Volunteer ?
-		 */
-		ret = fat_bread (sb,block);
-	}
-	return ret;
-}
-
-void fat_brelse (
+void bigblock_fat_brelse (
 	struct super_block *sb,
 	struct buffer_head *bh)
 {
-	if (bh != NULL) {
-		if (MSDOS_SB(sb)->cvf_format &&
-		    MSDOS_SB(sb)->cvf_format->cvf_brelse)
-			return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
-
-		if (sb->s_blocksize == 512){
-			brelse (bh);
-		}else{
-			brelse (bh->b_next);
-			/* We can free the dummy because a new one is allocated at
-				each fat_getblk() and fat_bread().
-			*/
-			kfree (bh);
-		}
-	}
+	brelse (bh->b_next);
+	/*
+	 * We can free the dummy because a new one is allocated at
+	 * each fat_getblk() and fat_bread().
+	 */
+	kfree (bh);
 }
-	
-void fat_mark_buffer_dirty (
+
+void bigblock_fat_mark_buffer_dirty (
 	struct super_block *sb,
 	struct buffer_head *bh,
 	int dirty)
 {
-	if (MSDOS_SB(sb)->cvf_format &&
-	    MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) {
-		MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
-		return;
-	}
- 
-	if (sb->s_blocksize != 512){
-		bh = bh->b_next;
-	}
-	mark_buffer_dirty (bh,dirty);
+	mark_buffer_dirty (bh->b_next,dirty);
 }
 
-void fat_set_uptodate (
+void bigblock_fat_set_uptodate (
 	struct super_block *sb,
 	struct buffer_head *bh,
 	int val)
 {
-	if (MSDOS_SB(sb)->cvf_format && 
-	    MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) {
-		MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
-		return;
-	}
- 
-	if (sb->s_blocksize != 512){
-		bh = bh->b_next;
-	}
-	mark_buffer_uptodate(bh, val);
+	mark_buffer_uptodate(bh->b_next, val);
 }
-int fat_is_uptodate (
+
+int bigblock_fat_is_uptodate (
 	struct super_block *sb,
 	struct buffer_head *bh)
 {
-	if(MSDOS_SB(sb)->cvf_format &&
-	   MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
-		return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
- 
-	if (sb->s_blocksize != 512){
-		bh = bh->b_next;
-	}
-	return buffer_uptodate(bh);
+	return buffer_uptodate(bh->b_next);
 }
 
-void fat_ll_rw_block (
+void bigblock_fat_ll_rw_block (
 	struct super_block *sb,
 	int opr,
 	int nbreq,
 	struct buffer_head *bh[32])
 {
-        if (MSDOS_SB(sb)->cvf_format &&
-	    MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) {
-		MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
-		return;
-	}
- 
-	if (sb->s_blocksize == 512){
-		ll_rw_block(opr,nbreq,bh);
-	}else{
-		struct buffer_head *tmp[32];
-		int i;
-		for (i=0; i<nbreq; i++){
-			tmp[i] = bh[i]->b_next;
-		}
-		ll_rw_block(opr,nbreq,tmp);
-	}
+	struct buffer_head *tmp[32];
+	int i;
+	for (i=0; i<nbreq; i++)
+		tmp[i] = bh[i]->b_next;
+	ll_rw_block(opr,nbreq,tmp);
 }
-
diff -u --recursive --new-file v2.3.12/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.3.12/linux/fs/fat/cache.c	Thu May 13 23:18:20 1999
+++ linux/fs/fat/cache.c	Mon Aug  9 11:43:49 1999
@@ -30,14 +30,20 @@
 
 int fat_access(struct super_block *sb,int nr,int new_value)
 {
+	return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
+}
+
+int fat_bmap(struct inode *inode,int sector)
+{
+	return MSDOS_SB(inode->i_sb)->cvf_format->cvf_bmap(inode,sector);
+}
+
+int default_fat_access(struct super_block *sb,int nr,int new_value)
+{
 	struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
 	unsigned char *p_first,*p_last;
 	int copy,first,last,next,b;
 
-	if (MSDOS_SB(sb)->cvf_format &&
-	    MSDOS_SB(sb)->cvf_format->fat_access)
-		return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
-
 	if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
 		return 0;
 	if (MSDOS_SB(sb)->fat_bits == 32) {
@@ -265,14 +271,11 @@
 	return nr;
 }
 
-int fat_smap(struct inode *inode,int sector)
+int default_fat_bmap(struct inode *inode,int sector)
 {
-	struct msdos_sb_info *sb;
+	struct msdos_sb_info *sb=MSDOS_SB(inode->i_sb);
 	int cluster,offset;
 
-	sb = MSDOS_SB(inode->i_sb);
-	if (sb->cvf_format && sb->cvf_format->cvf_smap)
-		return sb->cvf_format->cvf_smap(inode,sector);
 	if ((sb->fat_bits != 32) &&
 	    (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
 	     !MSDOS_I(inode)->i_start))) {
@@ -280,6 +283,8 @@
 			return 0;
 		return sector+sb->dir_start;
 	}
+	if (sector >= (MSDOS_I(inode)->i_realsize>>9))
+		return 0;
 	cluster = sector/sb->cluster_size;
 	offset = sector % sb->cluster_size;
 	if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
diff -u --recursive --new-file v2.3.12/linux/fs/fat/cvf.c linux/fs/fat/cvf.c
--- v2.3.12/linux/fs/fat/cvf.c	Sun Feb 28 09:47:37 1999
+++ linux/fs/fat/cvf.c	Mon Aug  9 11:43:49 1999
@@ -21,6 +21,83 @@
 
 #define MAX_CVF_FORMATS 3
 
+struct buffer_head *default_fat_bread(struct super_block *,int);
+struct buffer_head *default_fat_getblk(struct super_block *, int);
+struct buffer_head *bigblock_fat_bread(struct super_block *, int);
+void default_fat_brelse(struct super_block *, struct buffer_head *);
+void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
+void default_fat_mark_buffer_dirty (struct super_block *,
+	struct buffer_head *, int);
+void bigblock_fat_mark_buffer_dirty (struct super_block *,
+	struct buffer_head *, int);
+void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
+void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
+int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
+int bigblock_fat_is_uptodate(struct super_block *, struct buffer_head *);
+int default_fat_access(struct super_block *sb,int nr,int new_value);
+void default_fat_ll_rw_block (
+	struct super_block *sb,
+	int opr,
+	int nbreq,
+	struct buffer_head *bh[32]);
+void bigblock_fat_ll_rw_block (
+	struct super_block *sb,
+	int opr,
+	int nbreq,
+	struct buffer_head *bh[32]);
+int default_fat_bmap(struct inode *inode,int block);
+ssize_t default_fat_file_write(
+	struct file *filp,
+	const char *buf,
+	size_t count,
+	loff_t *ppos);
+
+struct cvf_format default_cvf = {
+	0,	/* version - who cares? */	
+	"plain",
+	0,	/* flags - who cares? */
+	NULL,
+	NULL,
+	NULL,
+	default_fat_bread,
+	default_fat_getblk,
+	default_fat_brelse,
+	default_fat_mark_buffer_dirty,
+	default_fat_set_uptodate,
+	default_fat_is_uptodate,
+	default_fat_ll_rw_block,
+	default_fat_access,
+	NULL,
+	default_fat_bmap,
+	generic_file_read,
+	default_fat_file_write,
+	NULL,
+	NULL
+};
+
+struct cvf_format bigblock_cvf = {
+	0,	/* version - who cares? */	
+	"big_blocks",
+	0,	/* flags - who cares? */
+	NULL,
+	NULL,
+	NULL,
+	bigblock_fat_bread,
+	bigblock_fat_bread,
+	bigblock_fat_brelse,
+	bigblock_fat_mark_buffer_dirty,
+	bigblock_fat_set_uptodate,
+	bigblock_fat_is_uptodate,
+	bigblock_fat_ll_rw_block,
+	default_fat_access,
+	NULL,
+	default_fat_bmap,
+	NULL,
+	default_fat_file_write,
+	NULL,
+	NULL
+};
+
 struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
 int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
 
diff -u --recursive --new-file v2.3.12/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.3.12/linux/fs/fat/dir.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/fat/dir.c	Mon Aug  9 11:43:49 1999
@@ -605,7 +605,7 @@
 	struct super_block *sb = dir->i_sb;
 	loff_t offset, curr;
 	int row;
-	int res;
+	struct buffer_head *new_bh;
 
 	offset = curr = 0;
 	*bh = NULL;
@@ -621,9 +621,45 @@
 	}
 	if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32)) 
 		return -ENOSPC;
-	if ((res = fat_add_cluster(dir)) < 0) return res;
+	new_bh = fat_extend_dir(dir);
+	if (!new_bh)
+		return -ENOSPC;
+	fat_brelse(sb, new_bh);
 	do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
 	return offset;
+}
+
+int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
+{
+	struct super_block *sb = dir->i_sb;
+	struct buffer_head *bh;
+	struct msdos_dir_entry *de;
+	__u16 date, time;
+
+	if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
+	/* zeroed out, so... */
+	fat_date_unix2dos(dir->i_mtime,&time,&date);
+	de = (struct msdos_dir_entry*)&bh->b_data[0];
+	memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
+	memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
+	de[0].attr = de[1].attr = ATTR_DIR;
+	de[0].time = de[1].time = CT_LE_W(time);
+	de[0].date = de[1].date = CT_LE_W(date);
+	if (is_vfat) {	/* extra timestamps */
+		de[0].ctime = de[1].ctime = CT_LE_W(time);
+		de[0].adate = de[0].cdate =
+			de[1].adate = de[1].cdate = CT_LE_W(date);
+	}
+	de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
+	de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
+	de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
+	de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
+	fat_mark_buffer_dirty(sb, bh, 1);
+	fat_brelse(sb, bh);
+	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.3.12/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.3.12/linux/fs/fat/fatfs_syms.c	Thu May 13 23:18:20 1999
+++ linux/fs/fat/fatfs_syms.c	Mon Aug  9 11:43:49 1999
@@ -17,9 +17,9 @@
 
 extern struct file_operations fat_dir_operations;
 
-EXPORT_SYMBOL(fat_add_cluster);
-EXPORT_SYMBOL(fat_add_cluster1);
+EXPORT_SYMBOL(fat_new_dir);
 EXPORT_SYMBOL(fat_bmap);
+EXPORT_SYMBOL(fat_get_block);
 EXPORT_SYMBOL(fat_brelse);
 EXPORT_SYMBOL(fat_cache_inval_inode);
 EXPORT_SYMBOL(fat_clear_inode);
@@ -44,9 +44,7 @@
 EXPORT_SYMBOL(fat_search_long);
 EXPORT_SYMBOL(fat_readdir);
 EXPORT_SYMBOL(fat_scan);
-EXPORT_SYMBOL(fat_smap);
 EXPORT_SYMBOL(fat_statfs);
-EXPORT_SYMBOL(fat_truncate);
 EXPORT_SYMBOL(fat_uni2esc);
 EXPORT_SYMBOL(fat_unlock_creation);
 EXPORT_SYMBOL(fat_write_inode);
diff -u --recursive --new-file v2.3.12/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.3.12/linux/fs/fat/file.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/fat/file.c	Mon Aug  9 11:43:49 1999
@@ -57,7 +57,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	fat_bmap,		/* get_block */
+	fat_get_block,		/* get_block */
 	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -67,392 +67,117 @@
 	NULL			/* revalidate */
 };
 
-/* #Specification: msdos / special devices / mmap	
-	Mmapping does work because a special mmap is provide in that case.
-	Note that it is much less efficient than the generic_file_mmap normally
-	used since it allocate extra buffer. generic_file_mmap is used for
-	normal device (512 bytes hardware sectors).
-*/
-static struct file_operations fat_file_operations_1024 = {
-	NULL,			/* lseek - default */
-	fat_file_read,		/* read */
-	fat_file_write,		/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* select v2.0.x/poll v2.1.x - default */
-	NULL,			/* ioctl - default */
-	fat_mmap,		/* mmap */
-	NULL,			/* no special open is needed */
-	NULL,			/* flush */
-	NULL,			/* release */
-	file_fsync		/* fsync */
-};
-
-/* #Specification: msdos / special devices / swap file
-	Swap file can't work on special devices with a large sector
-	size (1024 bytes hard sector). Those devices have a weird
-	MS-DOS filesystem layout. Generally a single hardware sector
-	may contain 2 unrelated logical sector. This mean that there is
-	no easy way to do a mapping between disk sector of a file and virtual
-	memory. So swap file is difficult (not available right now)
-	on those devices. Off course, Ext2 does not have this problem.
-*/
-struct inode_operations fat_file_inode_operations_1024 = {
-	&fat_file_operations_1024,	/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* get_block */
-	block_read_full_page,	/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* flushpage */
-	fat_truncate,		/* truncate */
-	NULL,			/* permission */
-	NULL,			/* smap */
-	NULL			/* revalidate */
-};
-
-static struct file_operations fat_file_operations_readpage = {
-	NULL,			/* lseek - default */
-	fat_file_read,		/* read */
-	fat_file_write,		/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* select v2.0.x/poll v2.1.x - default */
-	NULL,			/* ioctl - default */
-	generic_file_mmap,	/* mmap */
-	NULL,			/* no special open is needed */
-	NULL,			/* flush */
-	NULL,			/* release */
-	file_fsync		/* fsync */
-};
-
-struct inode_operations fat_file_inode_operations_readpage = {
-	&fat_file_operations_readpage,	/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* get_block */
-	fat_readpage,		/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* flushpage */
-	fat_truncate,		/* truncate */
-	NULL,			/* permission */
-	NULL,			/* smap */
-	NULL			/* revalidate */
-};
-
-#define MSDOS_PREFETCH	32
-struct fat_pre {
-	int file_sector;/* Next sector to read in the prefetch table */
-			/* This is relative to the file, not the disk */
-	struct buffer_head *bhlist[MSDOS_PREFETCH];	/* All buffers needed */
-	int nblist;	/* Number of buffers in bhlist */
-	int nolist;	/* index in bhlist */
-};
-/*
-	Order the prefetch of more sectors.
-*/
-static void fat_prefetch (
-	struct inode *inode,
-	struct fat_pre *pre,
-	int nb)		/* How many must we prefetch at once */
-{
-	struct super_block *sb = inode->i_sb;
-	struct buffer_head *bhreq[MSDOS_PREFETCH];	/* Buffers not */
-							/* already read */
-	int nbreq = 0;			/* Number of buffers in bhreq */
-	int i;
-	for (i=0; i<nb; i++){
-		int sector = fat_smap(inode,pre->file_sector);
-		if (sector != 0){
-			struct buffer_head *bh;
-			PRINTK (("fsector2 %d -> %d\n",pre->file_sector-1,sector));
-			pre->file_sector++;
-			bh = fat_getblk(sb, sector);
-			if (bh == NULL)	break;
-			pre->bhlist[pre->nblist++] = bh;
-			if (!fat_is_uptodate(sb,bh))
-				bhreq[nbreq++] = bh;
-		}else{
-			break;
-		}
-	}
-	if (nbreq > 0) fat_ll_rw_block (sb,READ,nbreq,bhreq);
-	for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
-}
-
-/*
-	Read a file into user space
-*/
-static ssize_t fat_file_read_text(
+ssize_t fat_file_read(
 	struct file *filp,
 	char *buf,
 	size_t count,
 	loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct super_block *sb = inode->i_sb;
-	char *start = buf;
-	char *end   = buf + count;
-	int i;
-	int left_in_file;
-	struct fat_pre pre;
-		
+	return MSDOS_SB(inode->i_sb)->cvf_format
+			->cvf_file_read(filp,buf,count,ppos);
+}
 
-	if (!inode) {
-		printk("fat_file_read: inode = NULL\n");
-		return -EINVAL;
-	}
-	/* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
-	if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
-		printk("fat_file_read: mode = %07o\n",inode->i_mode);
-		return -EINVAL;
+
+int fat_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) {
+	unsigned long phys;
+	phys = fat_bmap(inode, iblock);
+	if (phys) {
+		bh_result->b_dev = inode->i_dev;
+		bh_result->b_blocknr = phys;
+		bh_result->b_state |= (1UL << BH_Mapped);
+		return 0;
 	}
-	if (*ppos >= inode->i_size || count == 0) return 0;
-	/*
-		Tell the buffer cache which block we expect to read in advance
-		Since we are limited with the stack, we preread only MSDOS_PREFETCH
-		because we have to keep the result into the local
-		arrays pre.bhlist and bhreq.
-		
-		Each time we process one block in bhlist, we replace
-		it by a new prefetch block if needed.
-	*/
-	PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,inode->i_size,count));
-	{
-		/*
-			We must prefetch complete block, so we must
-			take in account the offset in the first block.
-		*/
-		int count_max = (*ppos & (SECTOR_SIZE-1)) + count;
-		int   to_reada;	/* How many block to read all at once */
-		pre.file_sector = *ppos >> SECTOR_BITS;
-		to_reada = count_max / SECTOR_SIZE;
-		if (count_max & (SECTOR_SIZE-1)) to_reada++;
-		if (filp->f_reada || !MSDOS_I(inode)->i_binary){
-			/* Doing a read ahead on ASCII file make sure we always */
-			/* read enough, since we don't know how many blocks */
-			/* we really need */
-			int ahead = read_ahead[MAJOR(inode->i_dev)];
-			PRINTK (("to_reada %d ahead %d\n",to_reada,ahead));
-			if (ahead == 0) ahead = 8;
-			to_reada += ahead;
-		}
-		if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
-		pre.nblist = 0;
-		fat_prefetch (inode,&pre,to_reada);
+	if (!create)
+		return 0;
+	if (iblock<<9 != MSDOS_I(inode)->i_realsize) {
+		BUG();
+		return -EIO;
 	}
-	pre.nolist = 0;
-	PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
-	while ((left_in_file = inode->i_size - *ppos) > 0
-		&& buf < end){
-		struct buffer_head *bh = pre.bhlist[pre.nolist];
-		char *data;
-		int size,offset;
-		if (bh == NULL) break;
-		pre.bhlist[pre.nolist] = NULL;
-		pre.nolist++;
-		if (pre.nolist == MSDOS_PREFETCH/2){
-			memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
-				,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
-			pre.nblist -= MSDOS_PREFETCH/2;
-			fat_prefetch (inode,&pre,MSDOS_PREFETCH/2);
-			pre.nolist = 0;
-		}
-		PRINTK (("file_read pos %ld nblist %d %d %d\n",*ppos,pre.nblist,pre.fetched,count));
-		wait_on_buffer(bh);
-		if (!fat_is_uptodate(sb,bh)){
-			/* read error  ? */
-			fat_brelse (sb, bh);
-			break;
-		}
-		offset = *ppos & (SECTOR_SIZE-1);
-		data = bh->b_data + offset;
-		size = MIN(SECTOR_SIZE-offset,left_in_file);
-		if (MSDOS_I(inode)->i_binary) {
-			size = MIN(size,end-buf);
-			copy_to_user(buf,data,size);
-			buf += size;
-			*ppos += size;
-		}else{
-			for (; size && buf < end; size--) {
-				char ch = *data++;
-				++*ppos;
-				if (ch == 26){
-					*ppos = inode->i_size;
-					break;
-				}else if (ch != '\r'){
-					put_user(ch,buf++);
-				}
+	if (!(iblock % MSDOS_SB(inode->i_sb)->cluster_size)) {
+		if (fat_add_cluster(inode))
+			return -ENOSPC;
+	}
+	MSDOS_I(inode)->i_realsize+=SECTOR_SIZE;
+	phys=fat_bmap(inode, iblock);
+	if (!phys)
+		BUG();
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	bh_result->b_state |= (1UL << BH_New);
+	return 0;
+}
+
+static int fat_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+	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;
+
+	pgpos = inode->i_size & PAGE_CACHE_MASK;
+	while (pgpos < page->offset) {
+		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;
 			}
-		}
-		fat_brelse(sb, bh);
-	}
-	PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
-	for (i=0; i<pre.nblist; i++)
-		fat_brelse (sb, pre.bhlist[i]);
-	if (start == buf)
-		return -EIO;
-	if (!IS_RDONLY(inode))
-		inode->i_atime = CURRENT_TIME;
-	filp->f_reada = 1;	/* Will be reset if a lseek is done */
-	return buf-start;
+			new_page = page_cache_entry(page_cache);
+			if (add_to_page_cache_unique(new_page,inode,pgpos,hash))
+				goto repeat_find;
+			page_cache = 0;
+		}
+		status = block_write_cont_page(file, new_page, PAGE_SIZE, 0, NULL);
+		UnlockPage(new_page);
+		page_cache_release(new_page);
+		if (status < 0)
+			goto out;
+		pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
+	}
+	status = block_write_cont_page(file, page, offset, bytes, buf);
+out:
+	if (page_cache)
+		page_cache_free(page_cache);
+	return status;
 }
 
-ssize_t fat_file_read(
+ssize_t fat_file_write(
 	struct file *filp,
-	char *buf,
+	const char *buf,
 	size_t count,
 	loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	if (MSDOS_SB(inode->i_sb)->cvf_format &&
-	    MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read)
-		return MSDOS_SB(inode->i_sb)->cvf_format
-			->cvf_file_read(filp,buf,count,ppos);
-
-	/*
-	 * MS-DOS filesystems with a blocksize > 512 may have blocks
-	 * spread over several hardware sectors (unaligned), which
-	 * is not something the generic routines can (or would want
-	 * to) handle).
-	 */
-	if (!MSDOS_I(inode)->i_binary || inode->i_sb->s_blocksize > 512)
-		return fat_file_read_text(filp, buf, count, ppos);
-	return generic_file_read(filp, buf, count, ppos);
+	struct super_block *sb = inode->i_sb;
+	return MSDOS_SB(sb)->cvf_format
+			->cvf_file_write(filp,buf,count,ppos);
 }
-/*
-	Write to a file either from user space
-*/
-ssize_t fat_file_write(
+
+ssize_t default_fat_file_write(
 	struct file *filp,
 	const char *buf,
 	size_t count,
 	loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct super_block *sb = inode->i_sb;
-	int sector,offset,size,left,written;
-	int error,carry;
-	const char *start;
-	char *to,ch;
-	struct buffer_head *bh;
-	int binary_mode = MSDOS_I(inode)->i_binary;
+	int retval;
 
-	PRINTK(("fat_file_write: dentry=%p, inode=%p, ino=%ld\n",
-		filp->f_dentry, inode, inode->i_ino));
-	if (!inode) {
-		printk("fat_file_write: inode = NULL\n");
-		return -EINVAL;
+	retval = generic_file_write(filp, buf, count, ppos,
+					fat_write_partial_page);
+	if (retval > 0) {
+		inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+		mark_inode_dirty(inode);
 	}
-        if (MSDOS_SB(sb)->cvf_format &&
-	    MSDOS_SB(sb)->cvf_format->cvf_file_write)
-		return MSDOS_SB(sb)->cvf_format
-			->cvf_file_write(filp,buf,count,ppos);
-
-	/* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
-	if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
-		printk("fat_file_write: mode = %07o\n",inode->i_mode);
-		return -EINVAL;
-	}
-	/* system files may be immutable */
-	if (IS_IMMUTABLE(inode))
-		return -EPERM;
-/*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
-	if (filp->f_flags & O_APPEND)
-		*ppos = inode->i_size;
-	if (count == 0)
-		return 0;
-	if (*ppos + count > 0x7FFFFFFFLL) {
-		count = 0x7FFFFFFFLL-*ppos;
-		if (!count)
-			return -EFBIG;
-	}
-
-	error = carry = 0;
-	for (start = buf; count || carry; count -= size) {
-		while (!(sector = fat_smap(inode,*ppos >> SECTOR_BITS)))
-			if ((error = fat_add_cluster(inode)) < 0) break;
-		if (error) {
-			fat_truncate(inode);
-			break;
-		}
-		offset = *ppos & (SECTOR_SIZE-1);
-		size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
-		if (binary_mode
-			&& offset == 0
-			&& (size == SECTOR_SIZE
-				|| *ppos + size >= inode->i_size)){
-			/* No need to read the block first since we will */
-			/* completely overwrite it */
-			/* or at least write past the end of file */
-			if (!(bh = fat_getblk(sb,sector))){
-				error = -EIO;
-				break;
-			}
-		} else if (!(bh = fat_bread(sb,sector))) {
-			error = -EIO;
-			break;
-		}
-		if (binary_mode) {
-			copy_from_user(bh->b_data+offset,buf,written = size);
-			buf += size;
-		} else {
-			written = left = SECTOR_SIZE-offset;
-			to = (char *) bh->b_data+(*ppos & (SECTOR_SIZE-1));
-			if (carry) {
-				*to++ = '\n';
-				left--;
-				carry = 0;
-			}
-			for (size = 0; size < count && left; size++) {
-				get_user(ch, buf++);
-				if (ch == '\n') {
-					*to++ = '\r';
-					left--;
-				}
-				if (!left) carry = 1;
-				else {
-					*to++ = ch;
-					left--;
-				}
-			}
-			written -= left;
-		}
-		update_vm_cache(inode, *ppos, bh->b_data + (*ppos & (SECTOR_SIZE-1)), written);
-		*ppos += written;
-		if (*ppos > inode->i_size) {
-			inode->i_size = *ppos;
-			mark_inode_dirty(inode);
-		}
-		fat_set_uptodate(sb, bh, 1);
-		fat_mark_buffer_dirty(sb, bh, 0);
-		fat_brelse(sb, bh);
-	}
-	if (start == buf)
-		return error;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
-	mark_inode_dirty(inode);
-	return buf-start;
+	return retval;
 }
 
 void fat_truncate(struct inode *inode)
@@ -460,14 +185,14 @@
 	int cluster;
 
 	/* Why no return value?  Surely the disk could fail... */
+	if (IS_RDONLY (inode))
+		return /* -EPERM */;
 	if (IS_IMMUTABLE(inode))
 		return /* -EPERM */;
-	if(inode->i_sb->s_flags&MS_RDONLY) {
-		printk("FAT: fat_truncate called though fs is read-only, uhh...\n");
-		return /* -EROFS */;
-	}
 	cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+	MSDOS_I(inode)->i_realsize = ((inode->i_size-1) | (SECTOR_SIZE-1)) + 1;
 	(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(inode);
 }
diff -u --recursive --new-file v2.3.12/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.3.12/linux/fs/fat/inode.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/fat/inode.c	Mon Aug  9 11:43:49 1999
@@ -33,6 +33,8 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
+extern struct cvf_format default_cvf, bigblock_cvf;
+
 /* #define FAT_PARANOIA 1 */
 #define DEBUG_LEVEL 0
 #ifdef FAT_DEBUG
@@ -166,7 +168,7 @@
 
 void fat_put_super(struct super_block *sb)
 {
-	if (MSDOS_SB(sb)->cvf_format) {
+	if (MSDOS_SB(sb)->cvf_format->cvf_version) {
 		dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
 		MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
 	}
@@ -364,7 +366,6 @@
 	struct super_block *sb = inode->i_sb;
 	int nr;
 
-	MSDOS_I(inode)->i_binary = 1;
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
 	MSDOS_I(inode)->i_fat_inode = inode;
@@ -394,6 +395,7 @@
 	inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
 		    inode->i_blksize*MSDOS_SB(sb)->cluster_size;
 	MSDOS_I(inode)->i_logstart = 0;
+	MSDOS_I(inode)->i_realsize = inode->i_size;
 
 	MSDOS_I(inode)->i_attrs = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
@@ -477,10 +479,10 @@
 	    sb->s_blocksize = 1024;
 	    set_blocksize(sb->s_dev, 1024);
 	  }
-	bh = fat_bread(sb, 0);
+	bh = bread(sb->s_dev, 0, sb->s_blocksize);
 	unlock_super(sb);
-	if (bh == NULL || !fat_is_uptodate(sb,bh)) {
-		fat_brelse (sb, bh);
+	if (bh == NULL || !buffer_uptodate(bh)) {
+		brelse (bh);
 		goto out_no_bread;
 	}
 
@@ -572,7 +574,7 @@
 		    MSDOS_MAX_EXTRA || (logical_sector_size & (SECTOR_SIZE-1))
 		    || !b->secs_track || !b->heads;
 	}
-	fat_brelse(sb, bh);
+	brelse(bh);
 	set_blocksize(sb->s_dev, blksize);
 	/*
 		This must be done after the brelse because the bh is a dummy
@@ -589,6 +591,10 @@
 		i = detect_cvf(sb,cvf_format);
 	if (i >= 0)
 		error = cvf_formats[i]->mount_cvf(sb,cvf_options);
+	else if (sb->s_blocksize == 512)
+		MSDOS_SB(sb)->cvf_format = &default_cvf;
+	else
+		MSDOS_SB(sb)->cvf_format = &bigblock_cvf;
 	if (error || debug) {
 		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
 		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
@@ -717,25 +723,6 @@
 	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
-
-int fat_bmap(struct inode *inode,int block)
-{
-	struct msdos_sb_info *sb;
-	int cluster,offset;
-
-	sb = MSDOS_SB(inode->i_sb);
-	if (sb->cvf_format &&
-	    sb->cvf_format->cvf_bmap)
-		return sb->cvf_format->cvf_bmap(inode,block);
-	if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
-		return sb->dir_start + block;
-	}
-	cluster = block/sb->cluster_size;
-	offset = block % sb->cluster_size;
-	if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
-	return (cluster-2)*sb->cluster_size+sb->data_start+offset;
-}
-
 static int is_exec(char *extension)
 {
 	char *exe_extensions = "EXECOMBAT", *walk;
@@ -752,7 +739,6 @@
 	struct super_block *sb = inode->i_sb;
 	int nr;
 
-	MSDOS_I(inode)->i_binary = 1;
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
 	MSDOS_I(inode)->i_fat_inode = inode;
@@ -789,6 +775,7 @@
 					break;
 				}
 			}
+		MSDOS_I(inode)->i_realsize = inode->i_size;
 	} else { /* not a directory */
 		inode->i_mode = MSDOS_MKMODE(de->attr,
 		    ((IS_NOEXEC(inode) || 
@@ -796,14 +783,7 @@
 		       !is_exec(de->ext)))
 		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
 		    & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
-		if (MSDOS_SB(sb)->cvf_format)
-			inode->i_op = (MSDOS_SB(sb)->cvf_format->flags & CVF_USE_READPAGE)
-				? &fat_file_inode_operations_readpage
-				: &fat_file_inode_operations_1024;
-		else
-		  inode->i_op = (sb->s_blocksize == 1024 || sb->s_blocksize == 2048)
-			? &fat_file_inode_operations_1024
-			: &fat_file_inode_operations;
+	        inode->i_op = &fat_file_inode_operations;
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
 		if (MSDOS_SB(sb)->fat_bits == 32) {
 			MSDOS_I(inode)->i_start |=
@@ -812,12 +792,11 @@
 		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		inode->i_nlink = 1;
 		inode->i_size = CF_LE_L(de->size);
+		MSDOS_I(inode)->i_realsize = ((inode->i_size-1)|(SECTOR_SIZE-1))+1;
 	}
 	if(de->attr & ATTR_SYS)
 		if (MSDOS_SB(sb)->options.sys_immutable)
 			inode->i_flags |= S_IMMUTABLE;
-	MSDOS_I(inode)->i_binary =
-	    fat_is_binary(MSDOS_SB(sb)->options.conversion, de->ext);
 	MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
 	/* this is as close to the truth as we can get ... */
 	inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
diff -u --recursive --new-file v2.3.12/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.3.12/linux/fs/fat/misc.c	Thu May 13 23:18:20 1999
+++ linux/fs/fat/misc.c	Mon Aug  9 11:43:49 1999
@@ -144,7 +144,70 @@
  * represented by inode. The cluster is zero-initialized.
  */
 
-struct buffer_head *fat_add_cluster1(struct inode *inode)
+/* not a directory */
+
+int fat_add_cluster(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	int count,nr,limit,last,curr,file_cluster;
+	int res = -ENOSPC;
+	int cluster_size = MSDOS_SB(sb)->cluster_size;
+
+	if (!MSDOS_SB(sb)->free_clusters) return res;
+	lock_fat(sb);
+	limit = MSDOS_SB(sb)->clusters;
+	nr = limit; /* to keep GCC happy */
+	for (count = 0; count < limit; count++) {
+		nr = ((count+MSDOS_SB(sb)->prev_free) % limit)+2;
+		if (fat_access(sb,nr,-1) == 0) break;
+	}
+	MSDOS_SB(sb)->prev_free = (count+MSDOS_SB(sb)->prev_free+1) % limit;
+	if (count >= limit) {
+		MSDOS_SB(sb)->free_clusters = 0;
+		unlock_fat(sb);
+		return res;
+	}
+	fat_access(sb,nr,EOF_FAT(sb));
+	if (MSDOS_SB(sb)->free_clusters != -1)
+		MSDOS_SB(sb)->free_clusters--;
+	if (MSDOS_SB(sb)->fat_bits == 32)
+		fat_clusters_flush(sb);
+	unlock_fat(sb);
+	last = 0;
+	/* We must locate the last cluster of the file to add this
+	   new one (nr) to the end of the link list (the FAT).
+	   
+	   Here file_cluster will be the number of the last cluster of the
+	   file (before we add nr).
+	   
+	   last is the corresponding cluster number on the disk. We will
+	   use last to plug the nr cluster. We will use file_cluster to
+	   update the cache.
+	*/
+	file_cluster = 0;
+	if ((curr = MSDOS_I(inode)->i_start) != 0) {
+		fat_cache_lookup(inode,INT_MAX,&last,&curr);
+		file_cluster = last;
+		while (curr && curr != -1){
+			file_cluster++;
+			if (!(curr = fat_access(sb, last = curr,-1))) {
+				fat_fs_panic(sb,"File without EOF");
+				return res;
+			}
+		}
+	}
+	if (last) fat_access(sb,last,nr);
+	else {
+		MSDOS_I(inode)->i_start = nr;
+		MSDOS_I(inode)->i_logstart = nr;
+		mark_inode_dirty(inode);
+	}
+	fat_cache_add(inode,file_cluster,nr);
+	inode->i_blocks += cluster_size;
+	return 0;
+}
+
+struct buffer_head *fat_extend_dir(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
 	int count,nr,limit,last,curr,sector,last_sector,file_cluster;
@@ -248,30 +311,17 @@
 		fat_cache_add(inode,file_cluster,nr);
 	}
 	inode->i_blocks += cluster_size;
-	if (S_ISDIR(inode->i_mode)) {
-		if (inode->i_size & (SECTOR_SIZE-1)) {
-			fat_fs_panic(sb,"Odd directory size");
-			inode->i_size = (inode->i_size+SECTOR_SIZE) &
-			    ~(SECTOR_SIZE-1);
-		}
-		inode->i_size += SECTOR_SIZE*cluster_size;
-#ifdef DEBUG
-printk("size is %d now (%x)\n",inode->i_size,inode);
-#endif
-		mark_inode_dirty(inode);
+	if (inode->i_size & (SECTOR_SIZE-1)) {
+		fat_fs_panic(sb,"Odd directory size");
+		inode->i_size = (inode->i_size+SECTOR_SIZE) &
+		    ~(SECTOR_SIZE-1);
 	}
+	inode->i_size += SECTOR_SIZE*cluster_size;
+	MSDOS_I(inode)->i_realsize += SECTOR_SIZE*cluster_size;
+	mark_inode_dirty(inode);
 	return res;
 }
 
-int fat_add_cluster(struct inode *inode)
-{
-	struct buffer_head *bh = fat_add_cluster1(inode);
-	if (!bh)
-		return -ENOSPC;
-	fat_brelse(inode->i_sb, bh);
-	return 0;
-}
-
 /* Linear day numbers of the respective 1sts in non-leap years. */
 
 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
@@ -351,7 +401,7 @@
 		if (*bh)
 			fat_brelse(sb, *bh);
 		*bh = NULL;
-		if ((sector = fat_smap(dir,offset >> SECTOR_BITS)) == -1)
+		if ((sector = fat_bmap(dir,offset >> SECTOR_BITS)) == -1)
 			return -1;
 		PRINTK (("get_entry sector %d %p\n",sector,*bh));
 		PRINTK (("get_entry sector apres brelse\n"));
diff -u --recursive --new-file v2.3.12/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.3.12/linux/fs/minix/bitmap.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/minix/bitmap.c	Mon Aug  9 12:29:00 1999
@@ -16,6 +16,8 @@
 #include <linux/stat.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
 
 #include <asm/bitops.h>
 
@@ -51,8 +53,9 @@
 	return(sum);
 }
 
-void minix_free_block(struct super_block * sb, int block)
+void minix_free_block(struct inode * inode, int block)
 {
+	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 	unsigned int bit,zone;
 
@@ -80,12 +83,15 @@
 	if (!minix_clear_bit(bit,bh->b_data))
 		printk("free_block (%s:%d): bit already cleared\n",
 		       kdevname(sb->s_dev), block);
+	else
+		DQUOT_FREE_BLOCK(sb, inode, 1);
 	mark_buffer_dirty(bh, 1);
 	return;
 }
 
-int minix_new_block(struct super_block * sb)
+int minix_new_block(struct inode * inode)
 {
+	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 	int i,j;
 
@@ -94,6 +100,9 @@
 		return 0;
 	}
 repeat:
+	if(DQUOT_ALLOC_BLOCK(sb, inode, 1))
+		return -EDQUOT;
+
 	j = 8192;
 	bh = NULL;
 	for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
@@ -105,6 +114,7 @@
 		return 0;
 	if (minix_set_bit(j,bh->b_data)) {
 		printk("new_block: bit already set");
+		DQUOT_FREE_BLOCK(sb, inode, 1);
 		goto repeat;
 	}
 	mark_buffer_dirty(bh, 1);
@@ -222,6 +232,10 @@
 		printk("free_inode: nonexistent imap in superblock\n");
 		return;
 	}
+
+	DQUOT_FREE_INODE(inode->i_sb, inode);
+	DQUOT_DROP(inode);
+
 	bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
 	minix_clear_inode(inode);
 	clear_inode(inode);
@@ -230,7 +244,7 @@
 	mark_buffer_dirty(bh, 1);
 }
 
-struct inode * minix_new_inode(const struct inode * dir)
+struct inode * minix_new_inode(const struct inode * dir, int * error)
 {
 	struct super_block * sb;
 	struct inode * inode;
@@ -274,6 +288,20 @@
 	inode->i_blocks = inode->i_blksize = 0;
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
+
+	unlock_super(sb);
+printk("m_n_i: allocated inode ");
+	if(DQUOT_ALLOC_INODE(sb, inode)) {
+printk("fails quota test\n");
+		sb->dq_op->drop(inode);
+		inode->i_nlink = 0;
+		iput(inode);
+		*error = -EDQUOT;
+		return NULL;
+	}
+printk("is within quota\n");
+
+	*error = 0;
 	return inode;
 }
 
diff -u --recursive --new-file v2.3.12/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.3.12/linux/fs/minix/namei.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/minix/namei.c	Mon Aug  9 12:29:00 1999
@@ -11,6 +11,7 @@
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
+#include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
 
@@ -212,7 +213,9 @@
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-	inode = minix_new_inode(dir);
+	inode = minix_new_inode(dir, &error);
+	if (error)
+		return error;
 	if (!inode)
 		return -ENOSPC;
 	inode->i_op = &minix_file_inode_operations;
@@ -240,7 +243,9 @@
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-	inode = minix_new_inode(dir);
+	inode = minix_new_inode(dir, &error);
+	if (error)
+		return error;
 	if (!inode)
 		return -ENOSPC;
 	inode->i_uid = current->fsuid;
@@ -271,7 +276,9 @@
 	info = &dir->i_sb->u.minix_sb;
 	if (dir->i_nlink >= info->s_link_max)
 		return -EMLINK;
-	inode = minix_new_inode(dir);
+	inode = minix_new_inode(dir, &error);
+	if (error)
+		return error;
 	if (!inode)
 		return -ENOSPC;
 	inode->i_op = &minix_dir_inode_operations;
@@ -383,6 +390,7 @@
 	if (!bh)
 		goto end_rmdir;
 	inode = dentry->d_inode;
+	DQUOT_INIT(inode);
 
 	if (!empty_dir(inode)) {
 		retval = -ENOTEMPTY;
@@ -422,6 +430,7 @@
 
 	retval = -ENOENT;
 	inode = dentry->d_inode;
+	DQUOT_INIT(inode);
 	bh = minix_find_entry(dir, dentry->d_name.name,
 			      dentry->d_name.len, &de);
 	if (!bh || de->inode != inode->i_ino)
@@ -456,7 +465,10 @@
 	int i;
 	char c;
 
-	if (!(inode = minix_new_inode(dir)))
+	inode = minix_new_inode(dir, &i);
+	if (i)
+		return i;
+	if (!inode)
 		return -ENOSPC;
 
 	inode->i_mode = S_IFLNK | 0777;
@@ -554,6 +566,8 @@
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
+		} else {
+			DQUOT_INIT(new_inode);
 		}
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
diff -u --recursive --new-file v2.3.12/linux/fs/minix/truncate.c linux/fs/minix/truncate.c
--- v2.3.12/linux/fs/minix/truncate.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/minix/truncate.c	Mon Aug  9 12:29:00 1999
@@ -66,7 +66,7 @@
 			mark_buffer_clean(bh);
 			brelse(bh);
 		}
-		minix_free_block(inode->i_sb,tmp);
+		minix_free_block(inode,tmp);
 	}
 	return retry;
 }
@@ -114,7 +114,7 @@
 		*ind = 0;
 		mark_buffer_dirty(ind_bh, 1);
 		brelse(bh);
-		minix_free_block(inode->i_sb,tmp);
+		minix_free_block(inode,tmp);
 	}
 	ind = (unsigned short *) ind_bh->b_data;
 	for (i = 0; i < 512; i++)
@@ -126,7 +126,7 @@
 		else {
 			tmp = *p;
 			*p = 0;
-			minix_free_block(inode->i_sb,tmp);
+			minix_free_block(inode,tmp);
 		}
 	}
 	brelse(ind_bh);
@@ -172,7 +172,7 @@
 			tmp = *p;
 			*p = 0;
 			mark_inode_dirty(inode);
-			minix_free_block(inode->i_sb,tmp);
+			minix_free_block(inode,tmp);
 		}
 	}
 	brelse(dind_bh);
@@ -230,7 +230,7 @@
 			mark_buffer_clean(bh);
 			brelse(bh);
 		}
-		minix_free_block(inode->i_sb,tmp);
+		minix_free_block(inode,tmp);
 	}
 	return retry;
 }
@@ -278,7 +278,7 @@
 		*ind = 0;
 		mark_buffer_dirty(ind_bh, 1);
 		brelse(bh);
-		minix_free_block(inode->i_sb,tmp);
+		minix_free_block(inode,tmp);
 	}
 	ind = (unsigned long *) ind_bh->b_data;
 	for (i = 0; i < 256; i++)
@@ -290,7 +290,7 @@
 		else {
 			tmp = *p;
 			*p = 0;
-			minix_free_block(inode->i_sb,tmp);
+			minix_free_block(inode,tmp);
 		}
 	}
 	brelse(ind_bh);
@@ -336,7 +336,7 @@
 			tmp = *p;
 			*p = 0;
 			mark_inode_dirty(inode);
-			minix_free_block(inode->i_sb,tmp);
+			minix_free_block(inode,tmp);
 		}
 	}
 	brelse(dind_bh);
@@ -382,7 +382,7 @@
                         tmp = *p;
                         *p = 0;
                         mark_inode_dirty(inode);
-                        minix_free_block(inode->i_sb,tmp);
+                        minix_free_block(inode,tmp);
 		}
 	}
         brelse(tind_bh);
diff -u --recursive --new-file v2.3.12/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.3.12/linux/fs/msdos/namei.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/msdos/namei.c	Mon Aug  9 11:43:49 1999
@@ -385,41 +385,16 @@
 		fat_brelse(sb, bh);
 		goto out_unlock;
 	}
-	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	mark_inode_dirty(inode);
 	res = 0;
 
 	dir->i_nlink++;
 	inode->i_nlink = 2; /* no need to mark them dirty */
 
-	if (!(bh1 = fat_add_cluster1(inode))) {
-		res = -ENOSPC;
+	res = fat_new_dir(inode, dir, 0);
+	if (res)
 		goto mkdir_error;
-	}
-	fat_brelse(sb, bh);
-	de1 = (struct msdos_dir_entry *)bh1->b_data;
-	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(inode);
 
-	memcpy(de1->name,MSDOS_DOT,MSDOS_NAME);
-	de1->attr = ATTR_DIR;
-	de1->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
-	de1->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
-	fat_date_unix2dos(inode->i_mtime,&de1->time,&de1->date);
-	de1->size = 0;
-	de1->time = CT_LE_W(de1->time);
-	de1->date = CT_LE_W(de1->date);
-	de1++;
-	memcpy(de1->name,MSDOS_DOTDOT,MSDOS_NAME);
-	de1->attr = ATTR_DIR;
-	de1->start = CT_LE_W(MSDOS_I(dir)->i_logstart);
-	de1->starthi = CT_LE_W(MSDOS_I(dir)->i_logstart >> 16);
-	fat_date_unix2dos(dir->i_mtime,&de1->time,&de1->date);
-	de1->size = 0;
-	de1->time = CT_LE_W(de1->time);
-	de1->date = CT_LE_W(de1->date);
-	fat_mark_buffer_dirty(sb, bh1, 1);
-	fat_brelse(sb, bh1);
+	fat_brelse(sb, bh);
 	d_instantiate(dentry, inode);
 	res = 0;
 
diff -u --recursive --new-file v2.3.12/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.12/linux/fs/ncpfs/dir.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/ncpfs/dir.c	Sat Aug  7 12:59:40 1999
@@ -350,7 +350,7 @@
 	struct ncpfs_inode_info finfo;
 	__u8 __name[dentry->d_name.len + 1];
 
-	if (!dir)
+	if (!dentry->d_inode || !dir)
 		return 0;
         
 	server = NCP_SERVER(dir);
diff -u --recursive --new-file v2.3.12/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.3.12/linux/fs/ncpfs/inode.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/ncpfs/inode.c	Sat Aug  7 12:59:40 1999
@@ -134,7 +134,15 @@
 	if ((inode->i_size)&&(inode->i_blksize)) {
 		inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
 	}
+
 	/* TODO: times? I'm not sure... */
+	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.modifyTime),
+			  		   le16_to_cpu(nwinfo->i.modifyDate));
+	inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.creationTime),
+			    		   le16_to_cpu(nwinfo->i.creationDate));
+	inode->i_atime = ncp_date_dos2unix(0,
+					   le16_to_cpu(nwinfo->i.lastAccessDate));
+
 	NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
 	NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
 	NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
diff -u --recursive --new-file v2.3.12/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.12/linux/fs/proc/array.c	Wed Jul 28 14:47:42 1999
+++ linux/fs/proc/array.c	Mon Aug  2 22:07:16 1999
@@ -532,9 +532,9 @@
 	    unsigned long schedule_frame;
 	    unsigned long pc;
 
-	    pc = thread_saved_pc(&p->tss);
+	    pc = thread_saved_pc(&p->thread);
 	    if (pc >= first_sched && pc < last_sched) {
-		schedule_frame = ((unsigned long *)p->tss.ksp)[6];
+		schedule_frame = ((unsigned long *)p->thread.ksp)[6];
 		return ((unsigned long *)schedule_frame)[12];
 	    }
 	    return pc;
@@ -603,7 +603,7 @@
 #ifdef __sparc_v9__
 		bias = STACK_BIAS;
 #endif
-		fp = p->tss.ksp + bias;
+		fp = p->thread.ksp + bias;
 		do {
 			/* Bogus frame pointer? */
 			if (fp < (task_base + sizeof(struct task_struct)) ||
@@ -631,7 +631,7 @@
 				 + (long)&((struct pt_regs *)0)->reg)
 # define KSTK_EIP(tsk) \
     (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
-# define KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->tss.usp)
+# define KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->thread.usp)
 #elif defined(__arm__)
 # define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
 # define KSTK_ESP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
@@ -648,11 +648,11 @@
 #define KSTK_EIP(tsk)	((tsk)->tss.regs->nip)
 #define KSTK_ESP(tsk)	((tsk)->tss.regs->gpr[1])
 #elif defined (__sparc_v9__)
-# define KSTK_EIP(tsk)  ((tsk)->tss.kregs->tpc)
-# define KSTK_ESP(tsk)  ((tsk)->tss.kregs->u_regs[UREG_FP])
+# define KSTK_EIP(tsk)  ((tsk)->thread.kregs->tpc)
+# define KSTK_ESP(tsk)  ((tsk)->thread.kregs->u_regs[UREG_FP])
 #elif defined(__sparc__)
-# define KSTK_EIP(tsk)  ((tsk)->tss.kregs->pc)
-# define KSTK_ESP(tsk)  ((tsk)->tss.kregs->u_regs[UREG_FP])
+# define KSTK_EIP(tsk)  ((tsk)->thread.kregs->pc)
+# define KSTK_ESP(tsk)  ((tsk)->thread.kregs->u_regs[UREG_FP])
 #endif
 
 /* Gcc optimizes away "strlen(x)" for constant x */
diff -u --recursive --new-file v2.3.12/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.12/linux/fs/proc/root.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/proc/root.c	Wed Aug  4 17:19:09 1999
@@ -651,8 +651,8 @@
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
-static struct proc_dir_entry proc_root_memory = {
-	PROC_MEMORY, 6, "memory",
+static struct proc_dir_entry proc_root_iomem = {
+	PROC_MEMORY, 5, "iomem",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
@@ -744,7 +744,7 @@
 	proc_register(&proc_root, &proc_root_fs);
 	proc_register(&proc_root, &proc_root_dma);
 	proc_register(&proc_root, &proc_root_ioports);
-	proc_register(&proc_root, &proc_root_memory);
+	proc_register(&proc_root, &proc_root_iomem);
 	proc_register(&proc_root, &proc_root_cmdline);
 #ifdef CONFIG_RTC
 	proc_register(&proc_root, &proc_root_rtc);
diff -u --recursive --new-file v2.3.12/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.3.12/linux/fs/romfs/inode.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/romfs/inode.c	Thu Jul 29 13:37:22 1999
@@ -405,7 +405,7 @@
 	buf = page_address(page);
 
 	/* hack? */
-	page->owner = (int)current;
+	page->owner = current;
 
 	offset = page->offset;
 	if (offset < inode->i_size) {
diff -u --recursive --new-file v2.3.12/linux/fs/super.c linux/fs/super.c
--- v2.3.12/linux/fs/super.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/super.c	Wed Aug  4 15:39:26 1999
@@ -1166,6 +1166,7 @@
 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
 #ifdef CONFIG_BLK_DEV_RAM
 		extern int rd_doload;
+		extern void rd_load_secondary(void);
 #endif
 		floppy_eject();
 #ifndef CONFIG_BLK_DEV_RAM
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile
--- v2.3.12/linux/fs/umsdos/Makefile	Wed Sep  9 09:01:19 1998
+++ linux/fs/umsdos/Makefile	Mon Aug  9 11:43:49 1999
@@ -8,7 +8,7 @@
 # Note 2:  the CFLAGS definitions are now in the main makefile.
 O_TARGET := umsdos.o
 
-O_OBJS   := dir.o  file.o inode.o ioctl.o mangle.o namei.o \
+O_OBJS   := dir.o  inode.o ioctl.o mangle.o namei.o \
 		rdir.o symlink.o emd.o check.o
 
 M_OBJS   := $(O_TARGET)
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/check.c linux/fs/umsdos/check.c
--- v2.3.12/linux/fs/umsdos/check.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/umsdos/check.c	Mon Aug  9 11:43:49 1999
@@ -92,24 +92,7 @@
 		}
 		
 		printk (" (i_patched=%d)", inode->u.umsdos_i.i_patched);
-		
-		if (inode->i_op == NULL) {
-			printk (" (i_op is NULL)\n");
-		} else if (inode->i_op == &umsdos_dir_inode_operations) {
-			printk (" (i_op is umsdos_dir_inode_operations)\n");
-		} else if (inode->i_op == &umsdos_file_inode_operations) {
-			printk (" (i_op is umsdos_file_inode_operations)\n");
-		} else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) {
-			printk (" (i_op is umsdos_file_inode_operations_no_bmap)\n");
-		} else if (inode->i_op == &umsdos_file_inode_operations_readpage) {
-			printk (" (i_op is umsdos_file_inode_operations_readpage)\n");
-		} else if (inode->i_op == &umsdos_rdir_inode_operations) {
-			printk (" (i_op is umsdos_rdir_inode_operations)\n");
-		} else if (inode->i_op == &umsdos_symlink_inode_operations) {
-			printk (" (i_op is umsdos_symlink_inode_operations)\n");
-		} else {
-			printk (" (i_op is UNKNOWN: %p)\n", inode->i_op);
-		}
+
 	} else {
 		printk (KERN_DEBUG "*   inode is NULL\n");
 	}
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.3.12/linux/fs/umsdos/dir.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/umsdos/dir.c	Mon Aug  9 11:43:49 1999
@@ -393,7 +393,6 @@
 	inode->i_uid = entry->uid;
 	inode->i_gid = entry->gid;
 
-	MSDOS_I (inode)->i_binary = 1;
 	/* #Specification: umsdos / i_nlink
 	 * The nlink field of an inode is maintained by the MSDOS file system
 	 * for directory and by UMSDOS for other files.  The logic is that
@@ -832,8 +831,8 @@
 	UMSDOS_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* followlink */
-	fat_bmap,		/* get_block */
-	block_read_full_page,	/* readpage */
+	NULL,			/* get_block */
+	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
 	NULL,			/* truncate */
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.3.12/linux/fs/umsdos/emd.c	Mon Apr 12 10:03:45 1999
+++ linux/fs/umsdos/emd.c	Mon Aug  9 11:43:49 1999
@@ -34,7 +34,6 @@
 	mm_segment_t old_fs = get_fs ();
 
 	set_fs (KERNEL_DS);
-	MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
 	ret = fat_file_read (filp, buf, count, &filp->f_pos);
 	set_fs (old_fs);
 	return ret;
@@ -53,15 +52,6 @@
 {
 	mm_segment_t old_fs = get_fs ();
 	ssize_t ret;
-
-	/* note: i_binary=2 is for CVF-FAT. We put it here, instead of
-	 * umsdos_file_write_kmem, since it is also wise not to compress
-	 * symlinks (in the unlikely event that they are > 512 bytes and
-	 * can be compressed.
-	 * FIXME: should we set it when reading symlinks too?
-	 */
-
-	MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
 
 	set_fs (KERNEL_DS);
 	ret = fat_file_write (filp, buf, count, &filp->f_pos);
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.3.12/linux/fs/umsdos/file.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/umsdos/file.c	Wed Dec 31 16:00:00 1969
@@ -1,189 +0,0 @@
-/*
- *  linux/fs/umsdos/file.c
- *
- *  Written 1993 by Jacques Gelinas
- *      inspired from linux/fs/msdos/file.c Werner Almesberger
- *
- *  Extended MS-DOS regular file handling primitives
- */
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/umsdos_fs.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-/*
- * Read a file into user space memory
- */
-static ssize_t UMSDOS_file_read (
-					struct file *filp,
-					char *buf,
-					size_t count,
-					loff_t * ppos
-)
-{
-	struct dentry *dentry = filp->f_dentry;
-	struct inode *inode = dentry->d_inode;
-
-	int ret = fat_file_read (filp, buf, count, ppos);
-
-	/* We have to set the access time because msdos don't care */
-	if (!IS_RDONLY (inode)) {
-		inode->i_atime = CURRENT_TIME;
-		mark_inode_dirty(inode);
-	}
-	return ret;
-}
-
-
-/*
- * Write a file from user space memory
- */
-static ssize_t UMSDOS_file_write (
-					 struct file *filp,
-					 const char *buf,
-					 size_t count,
-					 loff_t * ppos)
-{
-	return fat_file_write (filp, buf, count, ppos);
-}
-
-
-/*
- * Truncate a file to 0 length.
- */
-static void UMSDOS_truncate (struct inode *inode)
-{
-	Printk (("UMSDOS_truncate\n"));
-	if (!IS_RDONLY (inode)) {
-		fat_truncate (inode);
-		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-		mark_inode_dirty(inode);
-	}
-}
-
-/* Function for normal file system (512 bytes hardware sector size) */
-struct file_operations umsdos_file_operations =
-{
-	NULL,			/* lseek - default */
-	UMSDOS_file_read,	/* read */
-	UMSDOS_file_write,	/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* poll - default */
-	NULL,			/* ioctl - default */
-	generic_file_mmap,	/* mmap */
-	NULL,			/* no special open is needed */
-	NULL,			/* flush */
-	NULL,			/* release */
-	file_fsync		/* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations =
-{
-	&umsdos_file_operations,	/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	fat_bmap,		/* get_block */
-	block_read_full_page,	/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* flushpage */
-	UMSDOS_truncate,	/* truncate */
-	NULL,			/* permission */
-	fat_smap,		/* smap */
-	NULL			/* revalidate */
-};
-
-/* For other with larger and unaligned file system */
-struct file_operations umsdos_file_operations_no_bmap =
-{
-	NULL,			/* lseek - default */
-	UMSDOS_file_read,	/* read */
-	UMSDOS_file_write,	/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* poll - default */
-	NULL,			/* ioctl - default */
-	fat_mmap,		/* mmap */
-	NULL,			/* no special open is needed */
-	NULL,			/* flush */
-	NULL,			/* release */
-	file_fsync		/* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations_no_bmap =
-{
-	&umsdos_file_operations_no_bmap,	/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow link */
-	NULL,			/* get_block */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* flushpage */
-	UMSDOS_truncate,	/* truncate */
-	NULL,			/* permission */
-	NULL,			/* smap */
-	NULL			/* revalidate */
-};
-
-/* For other with larger and unaligned file system with readpage */
-struct file_operations umsdos_file_operations_readpage =
-{
-	NULL,			/* lseek - default */
-	UMSDOS_file_read,	/* read */
-	UMSDOS_file_write,	/* write */
-	NULL,			/* readdir - bad */
-	NULL,			/* poll - default */
-	NULL,			/* ioctl - default */
-	generic_file_mmap,	/* mmap */
-	NULL,			/* no special open is needed */
-	NULL,			/* flush */
-	NULL,			/* release */
-	file_fsync		/* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations_readpage =
-{
-	&umsdos_file_operations_readpage,	/* default file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow link */
-	NULL,			/* get_block */
-	fat_readpage,		/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* flushpage */
-	UMSDOS_truncate,	/* truncate */
-	NULL,			/* permission */
-	NULL,			/* smap */
-	NULL			/* revalidate */
-};
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.3.12/linux/fs/umsdos/inode.c	Thu May 13 23:18:21 1999
+++ linux/fs/umsdos/inode.c	Mon Aug  9 11:44:49 1999
@@ -42,7 +42,7 @@
 	filp->f_reada = 1;
 	filp->f_flags = O_RDWR;
 	filp->f_dentry = dentry;
-	filp->f_op = &umsdos_file_operations;
+	filp->f_op = dentry->d_inode->i_op->default_file_ops;
 }
 
 
@@ -146,19 +146,7 @@
 	umsdos_set_dirinfo_new(dentry, f_pos);
 
 	if (S_ISREG (inode->i_mode)) {
-		if (MSDOS_SB (inode->i_sb)->cvf_format) {
-			if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
-				inode->i_op = &umsdos_file_inode_operations_readpage;
-			} else {
-				inode->i_op = &umsdos_file_inode_operations_no_bmap;
-			}
-		} else {
-			if (inode->i_op->bmap != NULL) {
-				inode->i_op = &umsdos_file_inode_operations;
-			} else {
-				inode->i_op = &umsdos_file_inode_operations_no_bmap;
-			}
-		}
+		/* All set */
 	} else if (S_ISDIR (inode->i_mode)) {
 		umsdos_setup_dir(dentry);
 	} else if (S_ISLNK (inode->i_mode)) {
diff -u --recursive --new-file v2.3.12/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- v2.3.12/linux/fs/umsdos/symlink.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/umsdos/symlink.c	Mon Aug  9 11:43:49 1999
@@ -135,7 +135,7 @@
 	NULL,			/* rename */
 	UMSDOS_readlink,	/* readlink */
 	UMSDOS_followlink,	/* followlink */
-	fat_bmap,		/* get_block */
+	fat_get_block,		/* get_block */
 	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.12/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.3.12/linux/fs/vfat/namei.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/vfat/namei.c	Mon Aug  9 11:43:49 1999
@@ -982,35 +982,6 @@
 	return 0;
 }
 
-static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
-{
-	struct super_block *sb = dir->i_sb;
-	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
-	__u16 date, time;
-
-	if ((bh = fat_add_cluster1(dir)) == NULL) return -ENOSPC;
-	/* zeroed out, so... */
-	fat_date_unix2dos(dir->i_mtime,&time,&date);
-	de = (struct msdos_dir_entry*)&bh->b_data[0];
-	memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
-	memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
-	de[0].attr = de[1].attr = ATTR_DIR;
-	de[0].ctime = de[0].time = de[1].ctime = de[1].time = CT_LE_W(time);
-	de[0].adate = de[0].cdate = de[0].date = de[1].adate =
-		de[1].cdate = de[1].date = CT_LE_W(date);
-	de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
-	de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
-	de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
-	de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
-	fat_mark_buffer_dirty(sb, bh, 1);
-	fat_brelse(sb, bh);
-	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(dir);
-
-	return 0;
-}
-
 static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
      struct buffer_head *bh, struct msdos_dir_entry *de)
 {
@@ -1110,8 +1081,7 @@
 	dir->i_version = event;
 	dir->i_nlink++;
 	inode->i_nlink = 2; /* no need to mark them dirty */
-
-	res = vfat_create_dotdirs(inode, dir);
+	res = fat_new_dir(inode, dir, 1);
 	if (res < 0)
 		goto mkdir_failed;
 	dentry->d_time = dentry->d_parent->d_inode->i_version;
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/cache.h linux/include/asm-alpha/cache.h
--- v2.3.12/linux/include/asm-alpha/cache.h	Mon Mar 15 16:11:55 1999
+++ linux/include/asm-alpha/cache.h	Fri Aug  6 10:41:47 1999
@@ -10,4 +10,6 @@
 #define L1_CACHE_ALIGN(x)  (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 #define SMP_CACHE_BYTES    L1_CACHE_BYTES
 
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.3.12/linux/include/asm-alpha/hardirq.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-alpha/hardirq.h	Wed Aug  4 15:42:06 1999
@@ -3,7 +3,7 @@
 
 /* Initially just a straight copy of the i386 code.  */
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 #ifndef __SMP__
 extern int __local_irq_count;
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/ide.h linux/include/asm-alpha/ide.h
--- v2.3.12/linux/include/asm-alpha/ide.h	Thu May 13 11:00:08 1999
+++ linux/include/asm-alpha/ide.h	Fri Aug  6 11:16:54 1999
@@ -13,6 +13,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	4
 #endif
@@ -67,7 +69,7 @@
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
 	hw_regs_t hw;
 	int index;
 
@@ -76,7 +78,7 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 typedef union {
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/init.h linux/include/asm-alpha/init.h
--- v2.3.12/linux/include/asm-alpha/init.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/init.h	Wed Aug  4 15:48:00 1999
@@ -1,19 +1 @@
-#ifndef _ALPHA_INIT_H
-#define _ALPHA_INIT_H
-
-#ifndef MODULE
-#define __init __attribute__ ((__section__ (".text.init")))
-#define __initdata __attribute__ ((__section__ (".data.init")))
-#define __initfunc(__arginit) \
-	__arginit __init; \
-	__arginit
-
-/* For assembly routines */
-#define __INIT		.section	.text.init,"ax"
-#define __FINIT		.previous
-#define __INITDATA	.section	.data.init,"a"
-#endif
-
-#define __cacheline_aligned __attribute__((__aligned__(32)))
-
-#endif
+#error "<asm/init.h> should never be used - use <linux/init.h> instead"
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.3.12/linux/include/asm-alpha/io.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/io.h	Thu Jul 29 13:37:22 1999
@@ -142,7 +142,7 @@
 # include <asm/core_tsunami.h>
 #elif defined(CONFIG_ALPHA_JENSEN)
 # include <asm/jensen.h>
-#elif defined(CONFIG_ALPHA_RX164)
+#elif defined(CONFIG_ALPHA_POLARIS)
 # include <asm/core_polaris.h>
 #else
 #error "What system is this?"
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- v2.3.12/linux/include/asm-alpha/machvec.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/machvec.h	Thu Jul 29 13:37:22 1999
@@ -72,7 +72,10 @@
 	int (*hose_write_config_dword)(u8, u8, u8, u32 value,
 				       struct linux_hose_info *);
 	
-	void (*mv_get_mmu_context)(struct task_struct *);
+	void (*mv_switch_mm)(struct mm_struct *, struct mm_struct *,
+			     struct task_struct *, long);
+	void (*mv_activate_mm)(struct mm_struct *, struct mm_struct *, long);
+
 	void (*mv_flush_tlb_current)(struct mm_struct *);
 	void (*mv_flush_tlb_other)(struct mm_struct *);
 	void (*mv_flush_tlb_current_page)(struct mm_struct * mm,
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h
--- v2.3.12/linux/include/asm-alpha/mmu_context.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-alpha/mmu_context.h	Thu Jul 29 13:42:27 1999
@@ -11,6 +11,34 @@
 #include <asm/system.h>
 #include <asm/machvec.h>
 
+
+/*
+ * Force a context reload. This is needed when we change the page
+ * table pointer or when we update the ASN of the current process.
+ */
+
+/* Don't get into trouble with dueling __EXTERN_INLINEs.  */
+#ifndef __EXTERN_INLINE
+#include <asm/io.h>
+#endif
+
+extern inline unsigned long
+__reload_thread(struct thread_struct *pcb)
+{
+	register unsigned long a0 __asm__("$16");
+	register unsigned long v0 __asm__("$0");
+
+	a0 = virt_to_phys(pcb);
+	__asm__ __volatile__(
+		"call_pal %2 #__reload_thread"
+		: "=r"(v0), "=r"(a0)
+		: "i"(PAL_swpctx), "r"(a0)
+		: "$1", "$16", "$22", "$23", "$24", "$25");
+
+	return v0;
+}
+
+
 /*
  * The maximum ASN's the processor supports.  On the EV4 this is 63
  * but the PAL-code doesn't actually use this information.  On the
@@ -91,24 +119,25 @@
 #define __MMU_EXTERN_INLINE
 #endif
 
-extern void get_new_mmu_context(struct task_struct *p, struct mm_struct *mm);
+extern void get_new_mm_context(struct task_struct *p, struct mm_struct *mm);
 
 static inline unsigned long
-__get_new_mmu_context(struct task_struct *p, struct mm_struct *mm)
+__get_new_mm_context(struct mm_struct *mm, long cpu)
 {
-	unsigned long asn = cpu_last_asn(smp_processor_id());
+	unsigned long asn = cpu_last_asn(cpu);
 	unsigned long next = asn + 1;
 
 	if ((asn & HARDWARE_ASN_MASK) >= MAX_ASN) {
 		tbiap();
 		next = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION;
 	}
-	cpu_last_asn(smp_processor_id()) = next;
+	cpu_last_asn(cpu) = next;
 	return next;
 }
 
 __EXTERN_INLINE void
-ev4_get_mmu_context(struct task_struct *p)
+ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
+	      struct task_struct *next, long cpu)
 {
 	/* As described, ASN's are broken.  But we can optimize for
 	   switching between threads -- if the mm is unchanged from
@@ -119,12 +148,23 @@
 	   for a 1992 SRM, reports Joseph Martin (jmartin@hlo.dec.com).
 	   I'm going to leave this here anyway, just to Be Sure.  -- r~  */
 
-	if (current->mm != p->mm)
+	if (prev_mm != next_mm)
 		tbiap();
 }
 
 __EXTERN_INLINE void
-ev5_get_mmu_context(struct task_struct *p)
+ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, long cpu)
+{
+	/* This is only called after changing mm on current.  */
+	tbiap();
+
+        current->thread.ptbr
+	  = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
+}
+
+__EXTERN_INLINE void
+ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
+	      struct task_struct *next, long cpu)
 {
 	/* Check if our ASN is of an older version, or on a different CPU,
 	   and thus invalid.  */
@@ -132,35 +172,51 @@
 	   fight over the context.  Find a way to record a per-mm, per-cpu
 	   value for the asn.  */
 
-	unsigned long asn = cpu_last_asn(smp_processor_id());
-	struct mm_struct *mm = p->mm;
-	unsigned long mmc = mm->context;
+	unsigned long asn = cpu_last_asn(cpu);
+	unsigned long mmc = next_mm->context;
 	
 	if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) {
-		mmc = __get_new_mmu_context(p, mm);
-		mm->context = mmc;
+		mmc = __get_new_mm_context(next_mm, cpu);
+		next_mm->context = mmc;
 	}
 
 	/* Always update the PCB ASN.  Another thread may have allocated
 	   a new mm->context (via flush_tlb_mm) without the ASN serial
 	   number wrapping.  We have no way to detect when this is needed.  */
-	p->tss.asn = mmc & HARDWARE_ASN_MASK;
+	next->thread.asn = mmc & HARDWARE_ASN_MASK;
+}
+
+__EXTERN_INLINE void
+ev5_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, long cpu)
+{
+	unsigned long mmc = __get_new_mm_context(next_mm, cpu);
+	next_mm->context = mmc;
+	current->thread.asn = mmc & HARDWARE_ASN_MASK;
+        current->thread.ptbr
+	  = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
+
+	__reload_thread(&current->thread);
 }
 
+
 #ifdef CONFIG_ALPHA_GENERIC
-# define get_mmu_context		(alpha_mv.mv_get_mmu_context)
+# define switch_mm			alpha_mv.mv_switch_mm
+# define activate_mm(x,y)		alpha_mv.mv_activate_mm((x),(y),smp_processor_id())
 #else
 # ifdef CONFIG_ALPHA_EV4
-#  define get_mmu_context		ev4_get_mmu_context
+#  define switch_mm			ev4_switch_mm
+#  define activate_mm(x,y)		ev4_activate_mm((x),(y),smp_processor_id())
 # else
-#  define get_mmu_context		ev5_get_mmu_context
+#  define switch_mm			ev5_switch_mm
+#  define activate_mm(x,y)		ev5_activate_mm((x),(y),smp_processor_id())
 # endif
 #endif
 
 extern inline void
-init_new_context(struct mm_struct *mm)
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
 	mm->context = 0;
+        tsk->thread.ptbr = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
 }
 
 extern inline void
@@ -173,49 +229,5 @@
 #undef __EXTERN_INLINE
 #undef __MMU_EXTERN_INLINE
 #endif
-
-/*
- * Force a context reload. This is needed when we change the page
- * table pointer or when we update the ASN of the current process.
- */
-
-/* Don't get into trouble with dueling __EXTERN_INLINEs.  */
-#ifndef __EXTERN_INLINE
-#include <asm/io.h>
-#endif
-
-extern inline unsigned long
-__reload_tss(struct thread_struct *tss)
-{
-	register unsigned long a0 __asm__("$16");
-	register unsigned long v0 __asm__("$0");
-
-	a0 = virt_to_phys(tss);
-	__asm__ __volatile__(
-		"call_pal %2 #__reload_tss"
-		: "=r"(v0), "=r"(a0)
-		: "i"(PAL_swpctx), "r"(a0)
-		: "$1", "$16", "$22", "$23", "$24", "$25");
-
-	return v0;
-}
-
-extern inline void
-reload_context(struct task_struct *task)
-{
-	__reload_tss(&task->tss);
-}
-
-/*
- * After setting current->mm to a new value, activate the context for the
- * new mm so we see the new mappings.
- */
-
-extern inline void
-activate_context(struct task_struct *task)
-{
-	get_new_mmu_context(task, task->mm);
-	reload_context(task);
-}
 
 #endif /* __ALPHA_MMU_CONTEXT_H */
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/page.h linux/include/asm-alpha/page.h
--- v2.3.12/linux/include/asm-alpha/page.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/page.h	Thu Jul 29 13:37:22 1999
@@ -106,13 +106,8 @@
 
 #endif /* STRICT_MM_TYPECHECKS */
 
-#define BUG()							\
-do {								\
-	printk("Kernel BUG at %s:%d!\n", __FILE__, __LINE__);	\
-	__asm__ __volatile__("call_pal 129 # bugchk");		\
-} while (1)
-
-#define PAGE_BUG(page) BUG()
+#define BUG()		__asm__ __volatile__("call_pal 129 # bugchk")
+#define PAGE_BUG(page)	BUG()
 
 #endif /* !ASSEMBLY */
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/parport.h linux/include/asm-alpha/parport.h
--- v2.3.12/linux/include/asm-alpha/parport.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/parport.h	Fri Aug  6 11:16:54 1999
@@ -0,0 +1,59 @@
+/*
+ * parport.h: platform-specific PC-style 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_AXP_PARPORT_H
+#define _ASM_AXP_PARPORT_H 1
+
+#include <linux/config.h>
+
+/* Maximum number of ports to support.  It is useless to set this greater
+   than PARPORT_MAX (in <linux/parport.h>).  */
+#define PARPORT_PC_MAX_PORTS  8
+
+/* If parport_cs (PCMCIA) is managing ports for us, we'll need the
+ * probing routines forever; otherwise we can lose them at boot time. */
+#ifdef CONFIG_PARPORT_PC_PCMCIA
+#define __maybe_initdata
+#define __maybe_init
+#else
+#define __maybe_initdata __initdata
+#define __maybe_init __init
+#endif
+
+static int __maybe_init parport_pc_init_pci(int irq, int dma);
+
+static int user_specified __maybe_initdata = 0;
+int __init
+parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
+{
+	int count = 0, i = 0;
+
+	if (io && *io) {
+		/* Only probe the ports we were given. */
+		user_specified = 1;
+		do {
+			if (!*io_hi) *io_hi = 0x400 + *io;
+			if (parport_pc_probe_port(*(io++), *(io_hi++),
+						  *(irq++), *(dma++)))
+				count++;
+		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
+	} else {
+		/* Probe all the likely ports. */
+		if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0]))
+			count++;
+		if (parport_pc_probe_port(0x378, 0x778, irq[0], dma[0]))
+			count++;
+		if (parport_pc_probe_port(0x278, 0x678, irq[0], dma[0]))
+			count++;
+		count += parport_pc_init_pci (irq[0], dma[0]);
+	}
+
+        return count;
+}
+
+#endif /* !(_ASM_AXP_PARPORT_H) */
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.3.12/linux/include/asm-alpha/pgtable.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-alpha/pgtable.h	Thu Jul 29 13:37:22 1999
@@ -46,12 +46,7 @@
 {
 }
 
-__EXTERN_INLINE void
-ev5_flush_tlb_current(struct mm_struct *mm)
-{
-	get_new_mmu_context(current, mm);
-	reload_context(current);
-}
+extern void ev5_flush_tlb_current(struct mm_struct *mm);
 
 __EXTERN_INLINE void
 ev5_flush_tlb_other(struct mm_struct *mm)
@@ -394,22 +389,6 @@
 extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= __DIRTY_BITS; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= __ACCESS_BITS; return pte; }
 
-/* 
- * To set the page-dir. Note the self-mapping in the last entry
- *
- * Also note that if we update the current process ptbr, we need to
- * update the PAL-cached ptbr value as well.. There doesn't seem to
- * be any "wrptbr" PAL-insn, but we can do a dummy swpctx to ourself
- * instead.
- */
-extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
-{
-	pgd_val(pgdir[PTRS_PER_PGD]) = pte_val(mk_pte((unsigned long) pgdir, PAGE_KERNEL));
-	tsk->tss.ptbr = ((unsigned long) pgdir - PAGE_OFFSET) >> PAGE_SHIFT;
-	if (tsk == current)
-		reload_context(tsk);
-}
-
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
 /* to find an entry in a kernel page-table-directory */
@@ -462,6 +441,9 @@
 		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));
+
+		pgd_val(ret[PTRS_PER_PGD])
+		  = pte_val(mk_pte((unsigned long)ret, PAGE_KERNEL));
 	}
 	return ret;
 }
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.3.12/linux/include/asm-alpha/processor.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-alpha/processor.h	Wed Aug  4 15:48:00 1999
@@ -73,7 +73,7 @@
 #define INIT_MMAP { &init_mm, PAGE_OFFSET,  PAGE_OFFSET+0x10000000, \
 	NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
-#define INIT_TSS  { \
+#define INIT_THREAD  { \
 	0, 0, 0, \
 	0, 0, 0, \
 	0, 0, 0, \
@@ -81,6 +81,8 @@
 	KERNEL_DS \
 }
 
+#define THREAD_SIZE (2*PAGE_SIZE)
+
 #include <asm/ptrace.h>
 
 /*
@@ -109,15 +111,16 @@
 	return 0;
 }
 
-/*
- * Do necessary setup to start up a newly executed thread.
- */
+/* Do necessary setup to start up a newly executed thread.  */
 extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-#define copy_segments(nr, tsk, mm)	do { } while (0)
+/* Create a kernel thread without removing it from tasklists.  */
+extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+#define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
 #define forget_segments()		do { } while (0)
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/resource.h linux/include/asm-alpha/resource.h
--- v2.3.12/linux/include/asm-alpha/resource.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-alpha/resource.h	Thu Jul 29 13:37:22 1999
@@ -25,12 +25,12 @@
     {LONG_MAX, LONG_MAX},			/* RLIMIT_CPU */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_FSIZE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_DATA */	\
-    {_STK_LIM, _STK_LIM},			/* RLIMIT_STACK */	\
+    {_STK_LIM, LONG_MAX},			/* RLIMIT_STACK */	\
     {       0, LONG_MAX},			/* RLIMIT_CORE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_RSS */	\
     {INR_OPEN, INR_OPEN},			/* RLIMIT_NOFILE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
-    {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	/* RLIMIT_NPROC */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_NPROC */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
 }
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/string.h linux/include/asm-alpha/string.h
--- v2.3.12/linux/include/asm-alpha/string.h	Mon Jun  7 11:37:13 1999
+++ linux/include/asm-alpha/string.h	Fri Aug  6 10:41:47 1999
@@ -44,6 +44,7 @@
 #define __HAVE_ARCH_STRCHR
 #define __HAVE_ARCH_STRRCHR
 #define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_MEMCHR
 
 /* The following routine is like memset except that it writes 16-bit
    aligned values.  The DEST and COUNT parameters must be even for 
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.3.12/linux/include/asm-alpha/system.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/system.h	Tue Aug  3 08:01:29 1999
@@ -88,11 +88,12 @@
 
 extern void halt(void) __attribute__((noreturn));
 
+#define prepare_to_switch()	do { } while(0)
 #define switch_to(prev,next,last)			\
 do {							\
 	unsigned long pcbb;				\
 	current = (next);				\
-	pcbb = virt_to_phys(&current->tss);		\
+	pcbb = virt_to_phys(&current->thread);		\
 	(last) = alpha_switch_to(pcbb, (prev));		\
 } while (0)
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h
--- v2.3.12/linux/include/asm-alpha/uaccess.h	Sat Apr 24 17:54:08 1999
+++ linux/include/asm-alpha/uaccess.h	Thu Jul 29 13:37:22 1999
@@ -23,9 +23,9 @@
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
-#define get_fs()  (current->tss.fs)
+#define get_fs()  (current->thread.fs)
 #define get_ds()  (KERNEL_DS)
-#define set_fs(x) (current->tss.fs = (x))
+#define set_fs(x) (current->thread.fs = (x))
 
 #define segment_eq(a,b)	((a).seg == (b).seg)
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.3.12/linux/include/asm-alpha/unistd.h	Thu Jan 21 11:26:30 1999
+++ linux/include/asm-alpha/unistd.h	Wed Aug  4 15:48:00 1999
@@ -257,7 +257,7 @@
 #define __NR_munlockall		317
 #define __NR_sysinfo		318
 #define __NR__sysctl		319
-#define __NR_idle		320
+/* 320 was sys_idle.  */
 #define __NR_oldumount		321
 #define __NR_swapon		322
 #define __NR_times		323
@@ -495,13 +495,6 @@
 
 #include <linux/string.h>
 #include <linux/signal.h>
-
-extern long __kernel_thread(unsigned long, int (*)(void *), void *);
-
-static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	return __kernel_thread(flags | CLONE_VM, fn, arg);
-}
 
 extern void sys_idle(void);
 static inline void idle(void)
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/arch-arc/ide.h linux/include/asm-arm/arch-arc/ide.h
--- v2.3.12/linux/include/asm-arm/arch-arc/ide.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/arch-arc/ide.h	Mon Aug  2 10:19:52 1999
@@ -20,7 +20,7 @@
  * This should follow whatever the default interface uses.
  */
 static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
 {
 	ide_ioreg_t reg = (ide_ioreg_t) data_port;
 	int i;
@@ -30,7 +30,7 @@
 		reg += 1;
 	}
 	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-	hw->irq = *irq;
+	hw->irq = irq;
 }
 
 /*
@@ -44,8 +44,7 @@
 
         memset(hw, 0, sizeof(*hw));
 
-	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
-	hw.irq = IRQ_HARDDISK;
+	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
 	ide_register_hw(&hw, NULL);
 #endif
 }
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/mmu_context.h linux/include/asm-arm/mmu_context.h
--- v2.3.12/linux/include/asm-arm/mmu_context.h	Tue May  5 21:33:34 1998
+++ linux/include/asm-arm/mmu_context.h	Mon Aug  2 10:19:52 1999
@@ -9,10 +9,24 @@
 #ifndef __ASM_ARM_MMU_CONTEXT_H
 #define __ASM_ARM_MMU_CONTEXT_H
 
-#define get_mmu_context(x) do { } while (0)
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/arch/memory.h>
 
-#define init_new_context(mm)	do { } while(0)
-#define destroy_context(mm)	do { } while(0)
-#define activate_context(tsk)	do { } while(0)
+#define destroy_context(mm)		do { } while(0)
+#define init_new_context(tsk,mm)	do { } while(0)
+
+/*
+ * This is the actual mm switch as far as the scheduler
+ * is concerned.  No registers are touched.
+ */
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, unsigned int cpu)
+{
+	if (prev != next) {
+		processor.u.armv3v4._set_pgd(__virt_to_phys((unsigned long)next->pgd));
+		clear_bit(cpu, &prev->cpu_vm_mask);
+	}
+	set_bit(cpu, &next->cpu_vm_mask);
+}
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/parport.h linux/include/asm-arm/parport.h
--- v2.3.12/linux/include/asm-arm/parport.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/parport.h	Mon Aug  2 10:19:52 1999
@@ -0,0 +1,46 @@
+/*
+ * parport.h: ia32-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
+
+/* Maximum number of ports to support.  It is useless to set this greater
+   than PARPORT_MAX (in <linux/parport.h>).  */
+#define PARPORT_PC_MAX_PORTS  8
+
+static int __init probe_one_port(unsigned long int base,
+				 unsigned long int base_hi,
+				 int irq, int dma);
+static int __init parport_pc_init_pci(int irq, int dma);
+
+static int user_specified __initdata = 0;
+int __init
+parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
+{
+	int count = 0, i = 0;
+
+	if (io && *io) {
+		/* Only probe the ports we were given. */
+		user_specified = 1;
+		do {
+			if (!*io_hi) *io_hi = 0x400 + *io;
+			count += probe_one_port(*(io++), *(io_hi++),
+						*(irq++), *(dma++));
+		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
+	} else {
+		/* Probe all the likely ports. */
+		count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
+		count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
+		count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
+		count += parport_pc_init_pci (irq[0], dma[0]);
+	}
+
+        return count;
+}
+
+#endif /* !(_ASM_I386_PARPORT_H) */
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h
--- v2.3.12/linux/include/asm-arm/proc-armo/processor.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/proc-armo/processor.h	Mon Aug  2 10:19:52 1999
@@ -77,6 +77,8 @@
 extern unsigned long get_page_8k(int priority);
 extern void free_page_8k(unsigned long page);
 
+#define THREAD_SIZE	(8192)
+
 #define ll_alloc_task_struct()	((struct task_struct *)get_page_8k(GFP_KERNEL))
 #define ll_free_task_struct(p)  free_page_8k((unsigned long)(p))
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/proc-armv/domain.h linux/include/asm-arm/proc-armv/domain.h
--- v2.3.12/linux/include/asm-arm/proc-armv/domain.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armv/domain.h	Mon Aug  2 10:19:52 1999
@@ -0,0 +1,46 @@
+/*
+ * linux/include/asm-arm/proc-armv/domain.h
+ *
+ * Copyright (C) 1999 Russell King.
+ */
+#ifndef __ASM_PROC_DOMAIN_H
+#define __ASM_PROC_DOMAIN_H
+
+/*
+ * Domain numbers
+ *
+ *  DOMAIN_IO     - domain 2 includes all IO only
+ *  DOMAIN_KERNEL - domain 1 includes all kernel memory only
+ *  DOMAIN_USER   - domain 0 includes all user memory only
+ */
+#define DOMAIN_USER	0
+#define DOMAIN_KERNEL	1
+#define DOMAIN_TABLE	1
+#define DOMAIN_IO	2
+
+/*
+ * Domain types
+ */
+#define DOMAIN_NOACCESS	0
+#define DOMAIN_CLIENT	1
+#define DOMAIN_MANAGER	3
+
+#define domain_val(dom,type)	((type) << 2*(dom))
+
+#define set_domain(x)					\
+	do {						\
+	__asm__ __volatile__(				\
+	"mcr	p15, 0, %0, c3, c0	@ set domain"	\
+	  : : "r" (x));					\
+	} while (0)
+
+#define modify_domain(dom,type)				\
+	do {						\
+	unsigned int domain = current->thread.domain;	\
+	domain &= ~domain_val(dom, DOMAIN_MANAGER);	\
+	domain |= domain_val(dom, type);		\
+	current->thread.domain = domain;		\
+	set_domain(current->thread.domain);		\
+	} while (0)
+
+#endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.3.12/linux/include/asm-arm/proc-armv/pgtable.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-arm/proc-armv/pgtable.h	Mon Aug  2 10:19:52 1999
@@ -220,25 +220,6 @@
 } 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)
- */
-#define pgd_none(pgd)		(0)
-#define pgd_bad(pgd)		(0)
-#define pgd_present(pgd)	(1)
-#define pgd_clear(pgdp)
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-/* 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 unsigned long get_page_2k(int priority);
 extern void free_page_2k(unsigned long page);
 
@@ -263,55 +244,6 @@
 #error Pgtable caches have to be per-CPU, so that no locking is needed.
 #endif
 
-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 *)(*ret);
-		ret[0] = ret[1];
-		clean_cache_area(ret, 4);
-		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++;
-}
-
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
-{
-	free_pages((unsigned long) pgd, 2);
-}
-
-#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)
-{
-	struct task_struct * p;
-	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 *)*(unsigned long *)pgd)
-		pgd[address >> PGDIR_SHIFT] = entry;
-}
-
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
 /****************
 * PMD functions *
 ****************/
@@ -406,7 +338,6 @@
 	return __phys_to_virt(ptr);
 }
 
-
 /****************
 * PTE functions *
 ****************/
@@ -552,8 +483,6 @@
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
-
-
 #define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
 
 /*
@@ -569,12 +498,12 @@
 #define PTE_BIT_FUNC(fn,op)			\
 extern inline pte_t fn##(pte_t pte) { pte_val(pte) op##; return pte; }
 
-//PTE_BIT_FUNC(pte_rdprotect, &= ~L_PTE_USER);
+/*PTE_BIT_FUNC(pte_rdprotect, &= ~L_PTE_USER);*/
 PTE_BIT_FUNC(pte_wrprotect, &= ~L_PTE_WRITE);
 PTE_BIT_FUNC(pte_exprotect, &= ~L_PTE_EXEC);
 PTE_BIT_FUNC(pte_mkclean,   &= ~L_PTE_DIRTY);
 PTE_BIT_FUNC(pte_mkold,     &= ~L_PTE_YOUNG);
-//PTE_BIT_FUNC(pte_mkread,    |= L_PTE_USER);
+/*PTE_BIT_FUNC(pte_mkread,    |= L_PTE_USER);*/
 PTE_BIT_FUNC(pte_mkwrite,   |= L_PTE_WRITE);
 PTE_BIT_FUNC(pte_mkexec,    |= L_PTE_EXEC);
 PTE_BIT_FUNC(pte_mkdirty,   |= L_PTE_DIRTY);
@@ -629,6 +558,100 @@
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
 }
+
+/*
+ * 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)
+ */
+#define pgd_none(pgd)		(0)
+#define pgd_bad(pgd)		(0)
+#define pgd_present(pgd)	(1)
+#define pgd_clear(pgdp)
+
+/* 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 {
+		if (pgd) { /* can pgd be NULL? */
+			pmd_t *pmd;
+			pte_t *pte;
+
+			/* pgd is never none and bad - it is
+			 * detected in the pmd macros.
+			 */
+			pmd = pmd_offset(pgd, 0);
+			if (pmd_none(*pmd))
+				break;
+			if (pmd_bad(*pmd)) {
+				printk("free_pgd_slow: bad directory entry %08lx\n", pmd_val(*pmd));
+				pmd_clear(pmd);
+				break;
+			}
+
+			pte = pte_offset(pmd, 0);
+			pmd_clear(pmd);
+			pte_free(pte);
+			pmd_free(pmd);
+		}
+	} while (0);
+	free_pages((unsigned long) pgd, 2);
+}
+
+#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)
+{
+	struct task_struct * p;
+	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;
+}
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 #define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 9)
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h
--- v2.3.12/linux/include/asm-arm/proc-armv/processor.h	Sat May  8 11:06:58 1999
+++ linux/include/asm-arm/proc-armv/processor.h	Mon Aug  2 10:19:52 1999
@@ -1,17 +1,20 @@
 /*
  * linux/include/asm-arm/proc-armv/processor.h
  *
- * Copyright (c) 1996 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
  *
  * Changelog:
  *  20-09-1996	RMK	Created
  *  26-09-1996	RMK	Added 'EXTRA_THREAD_STRUCT*'
  *  28-09-1996	RMK	Moved start_thread into the processor dependencies
  *  09-09-1998	PJB	Delete redundant `wp_works_ok'
+ *  31-07-1999	RMK	Added 'domain' stuff
  */
 #ifndef __ASM_PROC_PROCESSOR_H
 #define __ASM_PROC_PROCESSOR_H
 
+#include <asm/proc/domain.h>
+
 #define KERNEL_STACK_SIZE	PAGE_SIZE
 
 struct context_save_struct {
@@ -28,8 +31,14 @@
 
 #define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0 }
 
-#define EXTRA_THREAD_STRUCT
-#define EXTRA_THREAD_STRUCT_INIT
+#define EXTRA_THREAD_STRUCT						\
+	unsigned int	domain;
+
+#define EXTRA_THREAD_STRUCT_INIT					\
+	, domain_val(DOMAIN_USER, DOMAIN_CLIENT) |			\
+	  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)					\
@@ -52,6 +61,7 @@
 /*
  * NOTE! The task struct and the stack go together
  */
+#define THREAD_SIZE	(PAGE_SIZE * 2)
 #define ll_alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
 #define ll_free_task_struct(p) free_pages((unsigned long)(p),1)
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h
--- v2.3.12/linux/include/asm-arm/proc-armv/uaccess.h	Sat May  8 11:06:58 1999
+++ linux/include/asm-arm/proc-armv/uaccess.h	Mon Aug  2 10:19:52 1999
@@ -2,36 +2,8 @@
  * linux/include/asm-arm/proc-armv/uaccess.h
  */
 
-/*
- * The fs functions are implemented on the ARMV3 and V4 architectures
- * using the domain register.
- *
- *  DOMAIN_IO     - domain 2 includes all IO only
- *  DOMAIN_KERNEL - domain 1 includes all kernel memory only
- *  DOMAIN_USER   - domain 0 includes all user memory only
- */
-
 #include <asm/hardware.h>
-
-#define DOMAIN_CLIENT	1
-#define DOMAIN_MANAGER	3
- 
-#define DOMAIN_USER_CLIENT	((DOMAIN_CLIENT) << 0)
-#define DOMAIN_USER_MANAGER	((DOMAIN_MANAGER) << 0)
-
-#define DOMAIN_KERNEL_CLIENT	((DOMAIN_CLIENT) << 2)
-#define DOMAIN_KERNEL_MANAGER	((DOMAIN_MANAGER) << 2)
-
-#define DOMAIN_IO_CLIENT	((DOMAIN_CLIENT) << 4)
-#define DOMAIN_IO_MANAGER	((DOMAIN_MANAGER) << 4)
-
-/*
- * When we want to access kernel memory in the *_user functions,
- * we change the domain register to KERNEL_DS, thus allowing
- * unrestricted access
- */
-#define KERNEL_DOMAIN	(DOMAIN_USER_CLIENT | DOMAIN_KERNEL_MANAGER | DOMAIN_IO_CLIENT)
-#define USER_DOMAIN	(DOMAIN_USER_CLIENT | DOMAIN_KERNEL_CLIENT  | DOMAIN_IO_CLIENT)
+#include <asm/proc/domain.h>
 
 /*
  * Note that this is actually 0x1,0000,0000
@@ -48,8 +20,7 @@
 {
 	current->addr_limit = fs;
 
-	__asm__ __volatile__("mcr	p15, 0, %0, c3, c0" :
-		: "r" (fs ? USER_DOMAIN : KERNEL_DOMAIN));
+	modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
 }
 
 /* We use 33-bit arithmetic here... */
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.3.12/linux/include/asm-arm/proc-fns.h	Tue May 11 16:30:45 1999
+++ linux/include/asm-arm/proc-fns.h	Mon Aug  2 10:19:52 1999
@@ -19,11 +19,6 @@
 extern struct processor {
 	const char *name;
 	/* MISC
-	 *
-	 * flush caches for task switch
-	 */
-	struct task_struct *(*_switch_to)(struct task_struct *prev, struct task_struct *next);
-	/*
 	 * get data abort address/flags
 	 */
 	void (*_data_abort)(unsigned long pc);
@@ -75,6 +70,10 @@
 			 * flush a specific TLB
 			 */
 			void (*_flush_tlb_area)(unsigned long address, unsigned long end, int flags);
+			/*
+			 * Set the page table
+			 */
+			void (*_set_pgd)(unsigned long pgd_phys);
 			/*
 			 * Set a PMD (handling IMP bit 4)
 			 */
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.3.12/linux/include/asm-arm/processor.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-arm/processor.h	Mon Aug  2 10:19:52 1999
@@ -49,27 +49,29 @@
 };
 
 struct thread_struct {
-	unsigned long			address;	  /* Address of fault	*/
-	unsigned long			trap_no;	  /* Trap number	*/
-	unsigned long			error_code;	  /* Error code of trap	*/
-	union fp_state			fpstate;	  /* FPE save state	*/
-	struct debug_info		debug;		  /* Debug/ptrace	*/
-	struct context_save_struct	*save;		  /* context save	*/
-	unsigned long			memmap;		  /* page tables	*/
+							/* fault info	  */
+	unsigned long			address;
+	unsigned long			trap_no;
+	unsigned long			error_code;
+							/* floating point */
+	union fp_state			fpstate;
+							/* debugging	  */
+	struct debug_info		debug;
+							/* context info	  */
+	struct context_save_struct	*save;
 	EXTRA_THREAD_STRUCT
 };
 
 #define INIT_MMAP \
 { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
-#define INIT_TSS  {				\
+#define INIT_THREAD  {				\
 	0,					\
 	0,					\
 	0,					\
 	{ { { 0, }, }, },			\
 	{ 0, },					\
-	(struct context_save_struct *)0,	\
-	SWAPPER_PG_DIR				\
+	(struct context_save_struct *)0	\
 	EXTRA_THREAD_STRUCT_INIT		\
 }
 
@@ -102,7 +104,7 @@
 extern void release_thread(struct task_struct *);
 
 /* Copy and release all segment info associated with a VM */
-#define copy_segments(nr, tsk, mm)	do { } while (0)
+#define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
 #define forget_segments()		do { } while (0)
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/resource.h linux/include/asm-arm/resource.h
--- v2.3.12/linux/include/asm-arm/resource.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-arm/resource.h	Mon Aug  2 10:19:52 1999
@@ -28,7 +28,7 @@
 	{ _STK_LIM, _STK_LIM },				\
 	{        0, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
-	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
+	{        0,        0 },				\
 	{ INR_OPEN, INR_OPEN },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
diff -u --recursive --new-file v2.3.12/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.3.12/linux/include/asm-arm/system.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-arm/system.h	Tue Aug  3 08:01:29 1999
@@ -141,15 +141,19 @@
 #define wmb() mb()
 #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
 
+#define prepare_to_switch()	do { } while(0)
+
 /*
  * switch_to(prev, next) should switch from task `prev' to `next'
  * `prev' will never be the same as `next'.
  * The `mb' is to tell GCC not to cache `current' across this call.
  */
-#define switch_to(prev,next,last)			\
-	do {			 			\
-		last = processor._switch_to(prev,next);	\
-		mb();					\
+extern struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next);
+
+#define switch_to(prev,next,last)		\
+	do {			 		\
+		last = __switch_to(prev,next);	\
+		mb();				\
 	} while (0)
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.3.12/linux/include/asm-i386/bugs.h	Thu Jul  8 15:42:21 1999
+++ linux/include/asm-i386/bugs.h	Mon Aug  9 12:41:57 1999
@@ -23,21 +23,30 @@
 
 #define CONFIG_BUGi386
 
-__initfunc(static void no_halt(char *s, int *ints))
+static int __init no_halt(char *s)
 {
 	boot_cpu_data.hlt_works_ok = 0;
+	return 1;
 }
 
-__initfunc(static void mca_pentium(char *s, int *ints))
+__setup("no-hlt", no_halt);
+
+static int __init mca_pentium(char *s)
 {
 	mca_pentium_flag = 1;
+	return 1;
 }
 
-__initfunc(static void no_387(char *s, int *ints))
+__setup("mca-pentium", mca_pentium);
+
+static int __init no_387(char *s)
 {
 	boot_cpu_data.hard_math = 0;
 	write_cr0(0xE | read_cr0());
+	return 1;
 }
+
+__setup("no387", no_387);
 
 static char __initdata fpu_error = 0;
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/cache.h linux/include/asm-i386/cache.h
--- v2.3.12/linux/include/asm-i386/cache.h	Mon Mar 15 16:11:55 1999
+++ linux/include/asm-i386/cache.h	Wed Aug  4 15:48:00 1999
@@ -15,4 +15,12 @@
 
 #define        SMP_CACHE_BYTES L1_CACHE_BYTES
 
+#ifdef MODULE
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+#else
+#define __cacheline_aligned					\
+  __attribute__((__aligned__(L1_CACHE_BYTES),			\
+		 __section__(".data.cacheline_aligned")))
+#endif
+
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/ide.h linux/include/asm-i386/ide.h
--- v2.3.12/linux/include/asm-i386/ide.h	Thu May 13 11:00:09 1999
+++ linux/include/asm-i386/ide.h	Mon Aug  9 12:42:03 1999
@@ -13,8 +13,10 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
 #ifndef MAX_HWIFS
-#define MAX_HWIFS	8
+#define MAX_HWIFS	10
 #endif
 
 #define ide__sti()	__sti()
@@ -67,7 +69,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
 	hw_regs_t hw;
 	int index;
 
@@ -76,7 +78,7 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 typedef union {
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/init.h linux/include/asm-i386/init.h
--- v2.3.12/linux/include/asm-i386/init.h	Sun Dec 27 22:45:13 1998
+++ linux/include/asm-i386/init.h	Tue Aug  3 10:27:39 1999
@@ -1,17 +1 @@
-#ifndef _I386_INIT_H
-#define _I386_INIT_H
-
-#define __init __attribute__ ((__section__ (".text.init")))
-#define __initdata __attribute__ ((__section__ (".data.init")))
-#define __initfunc(__arginit) \
-	__arginit __init; \
-	__arginit
-/* For assembly routines */
-#define __INIT		.section	".text.init",#alloc,#execinstr
-#define __FINIT	.previous
-#define __INITDATA	.section	".data.init",#alloc,#write
-
-#define __cacheline_aligned __attribute__ \
-			 ((__section__ (".data.cacheline_aligned")))
-
-#endif
+#error "<asm/init.h> should never be used - use <linux/init.h> instead"
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.3.12/linux/include/asm-i386/mmu_context.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-i386/mmu_context.h	Mon Aug  9 12:42:03 1999
@@ -10,7 +10,7 @@
 #define destroy_context(mm)		do { } while(0)
 #define init_new_context(tsk,mm)	do { } while (0)
 
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, unsigned cpu)
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
 {
 
 	if (prev != next) {
@@ -26,5 +26,8 @@
 	}
 	set_bit(cpu, &next->cpu_vm_mask);
 }
+
+#define activate_mm(prev, next) \
+	switch_mm((prev),(next),NULL,smp_processor_id())
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/parport.h linux/include/asm-i386/parport.h
--- v2.3.12/linux/include/asm-i386/parport.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-i386/parport.h	Fri Aug  6 11:16:54 1999
@@ -9,16 +9,25 @@
 #ifndef _ASM_I386_PARPORT_H
 #define _ASM_I386_PARPORT_H 1
 
+#include <linux/config.h>
+
 /* Maximum number of ports to support.  It is useless to set this greater
    than PARPORT_MAX (in <linux/parport.h>).  */
 #define PARPORT_PC_MAX_PORTS  8
 
-static int __init probe_one_port(unsigned long int base,
-				 unsigned long int base_hi,
-				 int irq, int dma);
-static int __init parport_pc_init_pci(int irq, int dma);
+/* If parport_cs (PCMCIA) is managing ports for us, we'll need the
+ * probing routines forever; otherwise we can lose them at boot time. */
+#ifdef CONFIG_PARPORT_PC_PCMCIA
+#define __maybe_initdata
+#define __maybe_init
+#else
+#define __maybe_initdata __initdata
+#define __maybe_init __init
+#endif
+
+static int __maybe_init parport_pc_init_pci(int irq, int dma);
 
-static int user_specified __initdata = 0;
+static int user_specified __maybe_initdata = 0;
 int __init
 parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
 {
@@ -29,14 +38,18 @@
 		user_specified = 1;
 		do {
 			if (!*io_hi) *io_hi = 0x400 + *io;
-			count += probe_one_port(*(io++), *(io_hi++),
-						*(irq++), *(dma++));
+			if (parport_pc_probe_port(*(io++), *(io_hi++),
+						  *(irq++), *(dma++)))
+				count++;
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
 	} else {
 		/* Probe all the likely ports. */
-		count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
-		count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
-		count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
+		if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0]))
+			count++;
+		if (parport_pc_probe_port(0x378, 0x778, irq[0], dma[0]))
+			count++;
+		if (parport_pc_probe_port(0x278, 0x678, irq[0], dma[0]))
+			count++;
 		count += parport_pc_init_pci (irq[0], dma[0]);
 	}
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.3.12/linux/include/asm-i386/system.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/system.h	Mon Aug  9 12:42:00 1999
@@ -9,6 +9,7 @@
 struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
 extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
 
+#define prepare_to_switch()	do { } while(0)
 #define switch_to(prev,next,last) do {					\
 	asm volatile("pushl %%esi\n\t"					\
 		     "pushl %%edi\n\t"					\
diff -u --recursive --new-file v2.3.12/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.3.12/linux/include/asm-i386/unistd.h	Wed Jan 20 11:06:24 1999
+++ linux/include/asm-i386/unistd.h	Mon Aug  2 13:29:31 1999
@@ -287,7 +287,6 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
 static inline _syscall0(int,pause)
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/cache.h linux/include/asm-m68k/cache.h
--- v2.3.12/linux/include/asm-m68k/cache.h	Mon Mar 15 16:11:55 1999
+++ linux/include/asm-m68k/cache.h	Mon Aug  9 12:27:30 1999
@@ -11,4 +11,12 @@
 
 #define        SMP_CACHE_BYTES L1_CACHE_BYTES
 
+#ifdef MODULE
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+#else
+#define __cacheline_aligned					\
+  __attribute__((__aligned__(L1_CACHE_BYTES),			\
+		 __section__(".data.cacheline_aligned")))
+#endif
+
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h
--- v2.3.12/linux/include/asm-m68k/hardirq.h	Wed Sep  2 09:39:18 1998
+++ linux/include/asm-m68k/hardirq.h	Mon Aug  9 12:27:30 1999
@@ -1,7 +1,7 @@
 #ifndef __M68K_HARDIRQ_H
 #define __M68K_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/irq.h linux/include/asm-m68k/irq.h
--- v2.3.12/linux/include/asm-m68k/irq.h	Fri Apr 17 22:04:44 1998
+++ linux/include/asm-m68k/irq.h	Mon Aug  9 12:27:31 1999
@@ -70,6 +70,9 @@
 extern void (*enable_irq)(unsigned int);
 extern void (*disable_irq)(unsigned int);
 
+#define disable_irq_nosync	disable_irq
+#define enable_irq_nosync	enable_irq
+
 extern int sys_request_irq(unsigned int, 
 	void (*)(int, void *, struct pt_regs *), 
 	unsigned long, const char *, void *);
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h
--- v2.3.12/linux/include/asm-m68k/mmu_context.h	Tue May  5 21:33:34 1998
+++ linux/include/asm-m68k/mmu_context.h	Mon Aug  9 12:27:31 1999
@@ -1,13 +1,93 @@
-#ifndef __68K_MMU_CONTEXT_H
-#define __68K_MMU_CONTEXT_H
+#ifndef __M68K_MMU_CONTEXT_H
+#define __M68K_MMU_CONTEXT_H
 
-/*
- * get a new mmu context.. do we need this on the m68k?
- */
-#define get_mmu_context(x) do { } while (0)
-
-#define init_new_context(mm)	do { } while(0)
-#define destroy_context(mm)	do { } while(0)
-#define activate_context(tsk)	do { } while(0)
+#include <asm/setup.h>
+#include <asm/page.h>
+
+extern inline void
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	mm->context = virt_to_phys(mm->pgd);
+}
+
+#define destroy_context(mm)		do { } while(0)
+
+extern inline void switch_mm_0230(struct mm_struct *mm)
+{
+	unsigned long crp[2] = {
+		0x80000000 | _PAGE_TABLE, mm->context
+	};
+	unsigned long tmp;
+
+	asm volatile (".chip 68030");
+
+	/* flush MC68030/MC68020 caches (they are virtually addressed) */
+	asm volatile (
+		"movec %%cacr,%0;"
+		"orw %1,%0; "
+		"movec %0,%%cacr"
+		: "=d" (tmp) : "di" (FLUSH_I_AND_D));
+
+	/* Switch the root pointer. For a 030-only kernel,
+	 * avoid flushing the whole ATC, we only need to
+	 * flush the user entries. The 68851 does this by
+	 * itself. Avoid a runtime check here.
+	 */
+	asm volatile (
+#ifdef CPU_M68030_ONLY
+		"pmovefd %0,%%crp; "
+		"pflush #0,#4"
+#else
+		"pmove %0,%%crp"
+#endif
+		: : "m" (crp[0]));
+
+	asm volatile (".chip 68k");
+}
+
+extern inline void switch_mm_0460(struct mm_struct *mm)
+{
+	asm volatile (".chip 68040");
+
+	/* flush address translation cache (user entries) */
+	asm volatile ("pflushan");
+
+	/* switch the root pointer */
+	asm volatile ("movec %0,%%urp" : : "r" (mm->context));
+
+	if (CPU_IS_060) {
+		unsigned long tmp;
+
+		/* clear user entries in the branch cache */
+		asm volatile (
+			"movec %%cacr,%0; "
+		        "orl %1,%0; "
+		        "movec %0,%%cacr"
+			: "=d" (tmp): "di" (0x00200000));
+	}
+
+	asm volatile (".chip 68k");
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
+{
+	if (prev != next) {
+		if (CPU_IS_020_OR_030)
+			switch_mm_0230(next);
+		else
+			switch_mm_0460(next);
+	}
+}
+
+extern inline void activate_mm(struct mm_struct *prev_mm,
+			       struct mm_struct *next_mm)
+{
+	next_mm->context = virt_to_phys(next_mm->pgd);
+
+	if (CPU_IS_020_OR_030)
+		switch_mm_0230(next_mm);
+	else
+		switch_mm_0460(next_mm);
+}
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- v2.3.12/linux/include/asm-m68k/page.h	Wed May 12 08:50:00 1999
+++ linux/include/asm-m68k/page.h	Mon Aug  9 12:27:31 1999
@@ -130,6 +130,15 @@
 }
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	asm volatile("illegal"); \
+} while (0)
+
+#define PAGE_BUG(page) do { \
+	BUG(); \
+} while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_PAGE_H */
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.3.12/linux/include/asm-m68k/pgtable.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-m68k/pgtable.h	Mon Aug  9 12:27:31 1999
@@ -6,7 +6,7 @@
 
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 /*
  * This file contains the functions and defines necessary to modify and use
@@ -264,21 +264,6 @@
 #define PTRS_PER_PGD	128
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
-/* the no. of pointers that fit on a page: this will go away */
-#define PTRS_PER_PAGE	(PAGE_SIZE/sizeof(void*))
-
-typedef pgd_t pgd_table[PTRS_PER_PGD];
-typedef pmd_t pmd_table[PTRS_PER_PMD];
-typedef pte_t pte_table[PTRS_PER_PTE];
-
-#define PGD_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pgd_table))
-#define PMD_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pmd_table))
-#define PTE_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pte_table))
-
-typedef pgd_table pgd_tablepage[PGD_TABLES_PER_PAGE];
-typedef pmd_table pmd_tablepage[PMD_TABLES_PER_PAGE];
-typedef pte_table pte_tablepage[PTE_TABLES_PER_PAGE];
-
 /* Virtual address region for use by kernel_map() */
 #define	KMAP_START	0xd0000000
 #define	KMAP_END	0xf0000000
@@ -430,9 +415,9 @@
 {
 	int i;
 	unsigned long ptbl;
-	ptbl = virt_to_phys(ptep);
-	for (i = 0; i < 16; i++, ptbl += sizeof(pte_table)/16)
-		pmdp->pmd[i] = _PAGE_TABLE | _PAGE_ACCESSED | ptbl;
+	ptbl = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
+	for (i = 0; i < 16; i++, ptbl += (sizeof(pte_t)*PTRS_PER_PTE/16))
+		pmdp->pmd[i] = ptbl;
 }
 
 extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
@@ -498,42 +483,6 @@
 	return pte;
 }
 extern inline pte_t pte_mkcache(pte_t pte)	{ pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
-
-/* to set the page-dir */
-extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
-{
-	tsk->tss.crp[0] = 0x80000000 | _PAGE_TABLE;
-	tsk->tss.crp[1] = virt_to_phys(pgdir);
-	if (tsk == current) {
-		if (CPU_IS_040_OR_060)
-			__asm__ __volatile__ (".chip 68040\n\t"
-					      "pflushan\n\t"
-					      "movec %0,%%urp\n\t"
-					      ".chip 68k"
-					      : : "r" (tsk->tss.crp[1]));
-		else {
-			unsigned long tmp;
-			__asm__ __volatile__ ("movec  %%cacr,%0\n\t"
-					      "orw #0x0808,%0\n\t"
-					      "movec %0,%%cacr"
-					      : "=d" (tmp));
-			/* For a 030-only kernel, avoid flushing the whole
-			   ATC, we only need to flush the user entries.
-			   The 68851 does this by itself.  Avoid a runtime
-			   check here.  */
-			__asm__ __volatile__ (
-#ifdef CPU_M68030_ONLY
-					      ".chip 68030\n\t"
-					      "pmovefd %0,%%crp\n\t"
-					      ".chip 68k\n\t"
-					      "pflush #0,#4"
-#else
-					      "pmove %0,%%crp"
-#endif
-					      : : "m" (tsk->tss.crp[0]));
-		}
-	}
-}
 
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.3.12/linux/include/asm-m68k/processor.h	Tue May 25 14:55:05 1999
+++ linux/include/asm-m68k/processor.h	Mon Aug  9 12:27:31 1999
@@ -15,6 +15,18 @@
 
 #include <asm/segment.h>
 #include <asm/fpu.h>
+#include <asm/ptrace.h>
+
+extern inline unsigned long rdusp(void) {
+  	unsigned long usp;
+
+	__asm__ __volatile__("move %/usp,%0" : "=a" (usp));
+	return usp;
+}
+
+extern inline void wrusp(unsigned long usp) {
+	__asm__ __volatile__("move %0,%/usp" : : "a" (usp));
+}
 
 /*
  * User space process size: 3.75GB. This is hardcoded into a few places,
@@ -53,7 +65,7 @@
 
 #define INIT_MMAP { &init_mm, 0, 0x40000000, NULL, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
-#define INIT_TSS  { \
+#define INIT_THREAD  { \
 	sizeof(init_stack) + (unsigned long) init_stack, 0, \
 	PS_S, __KERNEL_DS, \
 	{0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \
@@ -73,6 +85,9 @@
 	wrusp(usp);
 }
 
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
 /* Free all resources held by a thread. */
 static inline void release_thread(struct task_struct *dead_task)
 {
@@ -80,7 +95,7 @@
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-#define copy_segments(nr, tsk, mm)	do { } while (0)
+#define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
 #define forget_segments()		do { } while (0)
 
@@ -106,6 +121,8 @@
 	else
 		return sw->retpc;
 }
+
+#define THREAD_SIZE (2*PAGE_SIZE)
 
 /* Allocation and freeing of basic task resources. */
 #define alloc_task_struct() \
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h
--- v2.3.12/linux/include/asm-m68k/resource.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-m68k/resource.h	Mon Aug  9 12:27:31 1999
@@ -28,7 +28,7 @@
   {_STK_LIM, LONG_MAX}, \
   {       0, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}, \
-  {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
+  {0, 0},		\
   {INR_OPEN, INR_OPEN}, \
   {LONG_MAX, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}  \
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.3.12/linux/include/asm-m68k/semaphore.h	Sat May 15 15:05:37 1999
+++ linux/include/asm-m68k/semaphore.h	Mon Aug  9 12:27:31 1999
@@ -2,6 +2,7 @@
 #define _M68K_SEMAPHORE_H
 
 #include <linux/linkage.h>
+#include <linux/wait.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -19,10 +20,45 @@
 	atomic_t count;
 	atomic_t waking;
 	wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+	long __magic;
+#endif
 };
 
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+		, (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+	__SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+	__SEMAPHORE_INITIALIZER(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+	struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+	sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+	sema_init(sem, 0);
+}
 
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
@@ -34,8 +70,6 @@
 asmlinkage int  __down_trylock(struct semaphore * sem);
 asmlinkage void __up(struct semaphore * sem);
 
-#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
-
 /*
  * This is ugly, but we want the default case to fall through.
  * "down_failed" is a special asm handler that calls the C
@@ -44,6 +78,11 @@
 extern inline void down(struct semaphore * sem)
 {
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
 	__asm__ __volatile__(
 		"| atomic down operation\n\t"
 		"subql #1,%0@\n\t"
@@ -64,6 +103,10 @@
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
 	register int result __asm__ ("%d0");
 
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
 	__asm__ __volatile__(
 		"| atomic interruptible down operation\n\t"
 		"subql #1,%1@\n\t"
@@ -86,6 +129,10 @@
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
 	register int result __asm__ ("%d0");
 
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
 	__asm__ __volatile__(
 		"| atomic down trylock operation\n\t"
 		"subql #1,%1@\n\t"
@@ -112,6 +159,11 @@
 extern inline void up(struct semaphore * sem)
 {
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
 	__asm__ __volatile__(
 		"| atomic up operation\n\t"
 		"addql #1,%0@\n\t"
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/softirq.h linux/include/asm-m68k/softirq.h
--- v2.3.12/linux/include/asm-m68k/softirq.h	Tue Jan  5 11:20:43 1999
+++ linux/include/asm-m68k/softirq.h	Mon Aug  9 12:27:31 1999
@@ -46,6 +46,9 @@
 
 extern unsigned int local_bh_count[NR_CPUS];
 
+#define local_bh_disable()	(local_bh_count[smp_processor_id()]++)
+#define local_bh_enable()	(local_bh_count[smp_processor_id()]--)
+
 extern inline void start_bh_atomic(void)
 {
 	local_bh_count[smp_processor_id()]++;
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/spinlock.h linux/include/asm-m68k/spinlock.h
--- v2.3.12/linux/include/asm-m68k/spinlock.h	Thu Dec 17 09:06:25 1998
+++ linux/include/asm-m68k/spinlock.h	Mon Aug  9 12:27:31 1999
@@ -17,12 +17,14 @@
 #endif
 
 #define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
-#define spin_trylock(lock)	do { } while(0)
+#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
+#define spin_trylock(lock)	(1)
 #define spin_unlock_wait(lock)	do { } while(0)
 #define spin_unlock(lock)	do { } while(0)
 #define spin_lock_irq(lock)	cli()
 #define spin_unlock_irq(lock)	sti()
+#define spin_lock_bh(lock)	local_bh_disable()
+#define spin_unlock_bh(lock)	local_bh_enable()
 
 #define spin_lock_irqsave(lock, flags) \
 	do { save_flags(flags); cli(); } while (0)
@@ -49,14 +51,18 @@
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 #endif
 
-#define read_lock(lock)		do { } while(0)
+#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
 #define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	do { } while(0)
+#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
 #define write_unlock(lock)	do { } while(0)
 #define read_lock_irq(lock)	cli()
 #define read_unlock_irq(lock)	sti()
 #define write_lock_irq(lock)	cli()
 #define write_unlock_irq(lock)	sti()
+#define read_lock_bh(lock)	local_bh_disable()
+#define read_unlock_bh(lock)	local_bh_enable()
+#define write_lock_bh(lock)	local_bh_disable()
+#define write_unlock_bh(lock)	local_bh_enable()
 
 #define read_lock_irqsave(lock, flags)		save_and_cli(flags)
 #define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v2.3.12/linux/include/asm-m68k/system.h	Tue May 11 09:57:14 1999
+++ linux/include/asm-m68k/system.h	Mon Aug  9 12:27:31 1999
@@ -5,16 +5,7 @@
 #include <linux/linkage.h>
 #include <asm/segment.h>
 
-extern inline unsigned long rdusp(void) {
-  	unsigned long usp;
-
-	__asm__ __volatile__("move %/usp,%0" : "=a" (usp));
-	return usp;
-}
-
-extern inline void wrusp(unsigned long usp) {
-	__asm__ __volatile__("move %0,%/usp" : : "a" (usp));
-}
+#define prepare_to_switch()	do { } while(0)
 
 /*
  * switch_to(n) should switch tasks to task ptr, first checking that
diff -u --recursive --new-file v2.3.12/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.3.12/linux/include/asm-m68k/unistd.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/unistd.h	Mon Aug  9 12:27:31 1999
@@ -116,7 +116,7 @@
 #define __NR_olduname		109
 #define __NR_iopl		/* 110 */ not supported
 #define __NR_vhangup		111
-#define __NR_idle		112
+#define __NR_idle		/* 112 */ Obsolete
 #define __NR_vm86		/* 113 */ not supported
 #define __NR_wait4		114
 #define __NR_swapoff		115
@@ -309,7 +309,6 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
 static inline _syscall0(int,pause)
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
diff -u --recursive --new-file v2.3.12/linux/include/asm-mips/ide.h linux/include/asm-mips/ide.h
--- v2.3.12/linux/include/asm-mips/ide.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-mips/ide.h	Fri Aug  6 11:16:54 1999
@@ -14,6 +14,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	6
 #endif
@@ -62,7 +64,7 @@
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
 	hw_regs_t hw;
 	int index;
 
@@ -71,7 +73,7 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 typedef union {
diff -u --recursive --new-file v2.3.12/linux/include/asm-mips/system.h linux/include/asm-mips/system.h
--- v2.3.12/linux/include/asm-mips/system.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-mips/system.h	Tue Aug  3 08:01:29 1999
@@ -143,6 +143,7 @@
 extern asmlinkage void *(*resume)(void *last, void *next);
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
+#define prepare_to_switch()	do { } while(0)
 #define switch_to(prev,next,last) \
 do { \
 	(last) = resume(prev, next); \
diff -u --recursive --new-file v2.3.12/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.3.12/linux/include/asm-ppc/ide.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-ppc/ide.h	Fri Aug  6 11:16:54 1999
@@ -21,6 +21,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/hdreg.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
@@ -105,7 +106,7 @@
 
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
 	hw_regs_t hw;
 	int index;
 
@@ -114,7 +115,7 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
diff -u --recursive --new-file v2.3.12/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.3.12/linux/include/asm-ppc/system.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-ppc/system.h	Tue Aug  3 08:01:29 1999
@@ -80,6 +80,7 @@
 extern void note_scsi_host(struct device_node *, void *);
 
 struct task_struct;
+#define prepare_to_switch()	do { } while(0)
 #define switch_to(prev,next,last) _switch_to((prev),(next),&(last))
 extern void _switch_to(struct task_struct *, struct task_struct *,
 		       struct task_struct **);
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc/resource.h linux/include/asm-sparc/resource.h
--- v2.3.12/linux/include/asm-sparc/resource.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-sparc/resource.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: resource.h,v 1.7 1998/11/19 20:01:44 davem Exp $
+/* $Id: resource.h,v 1.8 1999/07/30 09:37:56 davem Exp $
  * resource.h: Resource definitions.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h
--- v2.3.12/linux/include/asm-sparc/siginfo.h	Wed Apr 28 14:40:07 1999
+++ linux/include/asm-sparc/siginfo.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: siginfo.h,v 1.4 1999/04/28 19:45:20 davem Exp $
+/* $Id: siginfo.h,v 1.5 1999/07/29 12:56:57 jj Exp $
  * siginfo.c:
  */
 
@@ -26,7 +26,7 @@
 		/* kill() */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			unsigned int _uid;	/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -38,20 +38,20 @@
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			unsigned int _uid;	/* sender's uid */
 			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
+			unsigned int _uid;	/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
 		} _sigchld;
 
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
 		struct {
 			void *_addr;	/* faulting insn/memory ref. */
 			int  _trapno;	/* TRAP # which caused the signal */
@@ -85,6 +85,7 @@
  * si_code values
  * Digital reserves positive values for kernel-generated signals.
  */
+#define SI_NOINFO	32767	/* no information in siginfo_t */
 #define SI_USER		0	/* sent by kill, sigsend, raise */
 #define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
 #define SI_QUEUE	-1	/* sent by sigqueue */
@@ -165,6 +166,12 @@
 #define POLL_PRI	5	/* high priority input available */
 #define POLL_HUP	6	/* device disconnected */
 #define NSIGPOLL	6
+
+/*
+ * SIGEMT si_codes
+ */
+#define EMT_TAGOVF	1	/* tag overflow */
+#define NSIGEMT		1
 
 /*
  * sigevent definitions
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/a.out.h linux/include/asm-sparc64/a.out.h
--- v2.3.12/linux/include/asm-sparc64/a.out.h	Thu May 15 16:48:04 1997
+++ linux/include/asm-sparc64/a.out.h	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: a.out.h,v 1.4 1997/05/04 07:21:19 davem Exp $ */
+/* $Id: a.out.h,v 1.6 1999/08/04 07:04:21 jj Exp $ */
 #ifndef __SPARC64_A_OUT_H__
 #define __SPARC64_A_OUT_H__
 
@@ -95,7 +95,7 @@
 
 #ifdef __KERNEL__
 
-#define STACK_TOP (current->tss.flags & SPARC_FLAG_32BIT ? 0xf0000000 : TASK_SIZE)
+#define STACK_TOP (current->thread.flags & SPARC_FLAG_32BIT ? 0xf0000000 : 0x80000000000L)
 
 #endif
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.3.12/linux/include/asm-sparc64/asm_offsets.h	Thu Jul  8 15:42:21 1999
+++ linux/include/asm-sparc64/asm_offsets.h	Mon Aug  2 22:07:16 1999
@@ -4,6 +4,12 @@
 
 #include <linux/config.h>
 
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+# if !((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
+#  error Please issue 'make check_asm' in linux top-level directory first
+# endif
+#endif
+
 #ifndef CONFIG_SMP
 
 #define AOFF_task_state	0x00000000
@@ -36,10 +42,8 @@
 #define ASIZ_task_next_task	0x00000008
 #define AOFF_task_prev_task	0x00000058
 #define ASIZ_task_prev_task	0x00000008
-#define AOFF_task_next_run	0x00000060
-#define ASIZ_task_next_run	0x00000008
-#define AOFF_task_prev_run	0x00000068
-#define ASIZ_task_prev_run	0x00000008
+#define AOFF_task_run_list	0x00000060
+#define ASIZ_task_run_list	0x00000010
 #define AOFF_task_binfmt	0x00000070
 #define ASIZ_task_binfmt	0x00000008
 #define AOFF_task_exit_code	0x00000078
@@ -74,115 +78,115 @@
 #define ASIZ_task_pidhash_next	0x00000008
 #define AOFF_task_pidhash_pprev	0x000000d8
 #define ASIZ_task_pidhash_pprev	0x00000008
-#define AOFF_task_tarray_ptr	0x000000e0
-#define ASIZ_task_tarray_ptr	0x00000008
-#define AOFF_task_wait_chldexit	0x000000e8
-#define ASIZ_task_wait_chldexit	0x00000028
-#define AOFF_task_vfork_sem	0x00000110
+#define AOFF_task_wait_chldexit	0x000000e0
+#define ASIZ_task_wait_chldexit	0x00000020
+#define AOFF_task_vfork_sem	0x00000100
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_policy	0x00000118
+#define AOFF_task_policy	0x00000108
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000120
+#define AOFF_task_rt_priority	0x00000110
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000128
+#define AOFF_task_it_real_value	0x00000118
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000130
+#define AOFF_task_it_prof_value	0x00000120
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000138
+#define AOFF_task_it_virt_value	0x00000128
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000140
+#define AOFF_task_it_real_incr	0x00000130
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000148
+#define AOFF_task_it_prof_incr	0x00000138
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000150
+#define AOFF_task_it_virt_incr	0x00000140
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000158
+#define AOFF_task_real_timer	0x00000148
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000180
+#define AOFF_task_times	0x00000170
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x000001a0
+#define AOFF_task_start_time	0x00000190
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x000001a8
+#define AOFF_task_per_cpu_utime	0x00000198
 #define ASIZ_task_per_cpu_utime	0x00000008
-#define AOFF_task_min_flt	0x000001b8
+#define AOFF_task_min_flt	0x000001a8
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x000001c0
+#define AOFF_task_maj_flt	0x000001b0
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000001c8
+#define AOFF_task_nswap	0x000001b8
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000001d0
+#define AOFF_task_cmin_flt	0x000001c0
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000001d8
+#define AOFF_task_cmaj_flt	0x000001c8
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000001e0
+#define AOFF_task_cnswap	0x000001d0
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000001ec
+#define AOFF_task_uid	0x000001dc
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000001f0
+#define AOFF_task_euid	0x000001e0
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000001f4
+#define AOFF_task_suid	0x000001e4
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000001f8
+#define AOFF_task_fsuid	0x000001e8
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000001fc
+#define AOFF_task_gid	0x000001ec
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x00000200
+#define AOFF_task_egid	0x000001f0
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x00000204
+#define AOFF_task_sgid	0x000001f4
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x00000208
+#define AOFF_task_fsgid	0x000001f8
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x0000020c
+#define AOFF_task_ngroups	0x000001fc
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000210
+#define AOFF_task_groups	0x00000200
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000290
+#define AOFF_task_cap_effective	0x00000280
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000294
+#define AOFF_task_cap_inheritable	0x00000284
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000298
+#define AOFF_task_cap_permitted	0x00000288
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x000002a0
+#define AOFF_task_user	0x00000290
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x000002a8
+#define AOFF_task_rlim	0x00000298
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000348
+#define AOFF_task_used_math	0x00000338
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000034a
+#define AOFF_task_comm	0x0000033a
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000035c
+#define AOFF_task_link_count	0x0000034c
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000360
+#define AOFF_task_tty	0x00000350
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000368
+#define AOFF_task_semundo	0x00000358
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000370
+#define AOFF_task_semsleeping	0x00000360
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000380
-#define ASIZ_task_tss	0x00000460
-#define AOFF_task_fs	0x000007e0
+#define AOFF_task_thread	0x00000370
+#define ASIZ_task_thread	0x00000460
+#define AOFF_task_fs	0x000007d0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000007e8
+#define AOFF_task_files	0x000007d8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000007f0
+#define AOFF_task_mm	0x000007e0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000007f8
-#define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x00000800
+#define AOFF_task_active_mm	0x000007e8
+#define ASIZ_task_active_mm	0x00000008
+#define AOFF_task_sigmask_lock	0x000007f0
+#define ASIZ_task_sigmask_lock	0x00000000
+#define AOFF_task_sig	0x000007f0
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x00000808
+#define AOFF_task_signal	0x000007f8
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000810
+#define AOFF_task_blocked	0x00000800
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000818
+#define AOFF_task_sigqueue	0x00000808
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000820
+#define AOFF_task_sigqueue_tail	0x00000810
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000828
+#define AOFF_task_sas_ss_sp	0x00000818
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000830
+#define AOFF_task_sas_ss_size	0x00000820
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000840
+#define ASIZ_task	0x00000830
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -191,91 +195,95 @@
 #define ASIZ_mm_mmap_cache	0x00000008
 #define AOFF_mm_pgd	0x00000018
 #define ASIZ_mm_pgd	0x00000008
-#define AOFF_mm_count	0x00000020
-#define ASIZ_mm_count	0x00000004
-#define AOFF_mm_map_count	0x00000024
+#define AOFF_mm_mm_users	0x00000020
+#define ASIZ_mm_mm_users	0x00000004
+#define AOFF_mm_mm_count	0x00000024
+#define ASIZ_mm_mm_count	0x00000004
+#define AOFF_mm_map_count	0x00000028
 #define ASIZ_mm_map_count	0x00000004
-#define AOFF_mm_mmap_sem	0x00000028
-#define ASIZ_mm_mmap_sem	0x00000038
+#define AOFF_mm_mmap_sem	0x00000030
+#define ASIZ_mm_mmap_sem	0x00000030
 #define AOFF_mm_page_table_lock	0x00000060
-#define ASIZ_mm_page_table_lock	0x00000001
-#define AOFF_mm_context	0x00000068
+#define ASIZ_mm_page_table_lock	0x00000000
+#define AOFF_mm_context	0x00000060
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000070
+#define AOFF_mm_start_code	0x00000068
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000078
+#define AOFF_mm_end_code	0x00000070
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000080
+#define AOFF_mm_start_data	0x00000078
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000088
+#define AOFF_mm_end_data	0x00000080
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000090
+#define AOFF_mm_start_brk	0x00000088
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000098
+#define AOFF_mm_brk	0x00000090
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x000000a0
+#define AOFF_mm_start_stack	0x00000098
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000a8
+#define AOFF_mm_arg_start	0x000000a0
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000b0
+#define AOFF_mm_arg_end	0x000000a8
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000b8
+#define AOFF_mm_env_start	0x000000b0
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000c0
+#define AOFF_mm_env_end	0x000000b8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000c8
+#define AOFF_mm_rss	0x000000c0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000d0
+#define AOFF_mm_total_vm	0x000000c8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000d8
+#define AOFF_mm_locked_vm	0x000000d0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000e0
+#define AOFF_mm_def_flags	0x000000d8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000e8
+#define AOFF_mm_cpu_vm_mask	0x000000e0
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000f0
+#define AOFF_mm_swap_cnt	0x000000e8
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x000000f8
+#define AOFF_mm_swap_address	0x000000f0
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000100
+#define AOFF_mm_segments	0x000000f8
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000108
+#define ASIZ_mm	0x00000100
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
-#define ASIZ_thread_wstate	0x00000002
-#define AOFF_thread_cwp	0x0000000a
-#define ASIZ_thread_cwp	0x00000002
-#define AOFF_thread_flags	0x0000000c
-#define ASIZ_thread_flags	0x00000002
-#define AOFF_thread_current_ds	0x0000000e
+#define ASIZ_thread_wstate	0x00000001
+#define AOFF_thread_cwp	0x00000009
+#define ASIZ_thread_cwp	0x00000001
+#define AOFF_thread_flags	0x0000000a
+#define ASIZ_thread_flags	0x00000001
+#define AOFF_thread_current_ds	0x0000000b
 #define ASIZ_thread_current_ds	0x00000001
-#define AOFF_thread_w_saved	0x00000010
-#define ASIZ_thread_w_saved	0x00000002
-#define AOFF_thread_new_signal	0x00000012
-#define ASIZ_thread_new_signal	0x00000002
-#define AOFF_thread_ctx	0x00000014
-#define ASIZ_thread_ctx	0x00000002
+#define AOFF_thread_w_saved	0x0000000c
+#define ASIZ_thread_w_saved	0x00000001
+#define AOFF_thread_fpdepth	0x0000000d
+#define ASIZ_thread_fpdepth	0x00000001
+#define AOFF_thread_fpsaved	0x0000000e
+#define ASIZ_thread_fpsaved	0x00000007
+#define AOFF_thread___pad1	0x00000015
+#define ASIZ_thread___pad1	0x00000003
 #define AOFF_thread_kregs	0x00000018
 #define ASIZ_thread_kregs	0x00000008
 #define AOFF_thread_utraps	0x00000020
 #define ASIZ_thread_utraps	0x00000008
-#define AOFF_thread_fpdepth	0x00000028
-#define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x00000029
-#define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread_gsr	0x00000030
+#define AOFF_thread_gsr	0x00000028
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread_xfsr	0x00000038
+#define AOFF_thread___pad2	0x0000002f
+#define ASIZ_thread___pad2	0x00000001
+#define AOFF_thread_sig_address	0x00000030
+#define ASIZ_thread_sig_address	0x00000008
+#define AOFF_thread_sig_desc	0x00000038
+#define ASIZ_thread_sig_desc	0x00000008
+#define AOFF_thread_xfsr	0x00000040
 #define ASIZ_thread_xfsr	0x00000038
-#define AOFF_thread_reg_window	0x00000070
+#define AOFF_thread___pad3	0x00000078
+#define ASIZ_thread___pad3	0x00000008
+#define AOFF_thread_reg_window	0x00000080
 #define ASIZ_thread_reg_window	0x00000380
-#define AOFF_thread_rwbuf_stkptrs	0x000003f0
+#define AOFF_thread_rwbuf_stkptrs	0x00000400
 #define ASIZ_thread_rwbuf_stkptrs	0x00000038
-#define AOFF_thread_sig_address	0x00000428
-#define ASIZ_thread_sig_address	0x00000008
-#define AOFF_thread_sig_desc	0x00000430
-#define ASIZ_thread_sig_desc	0x00000008
 #define AOFF_thread_user_cntd0	0x00000438
 #define ASIZ_thread_user_cntd0	0x00000008
 #define AOFF_thread_user_cntd1	0x00000440
@@ -322,10 +330,8 @@
 #define ASIZ_task_next_task	0x00000008
 #define AOFF_task_prev_task	0x00000058
 #define ASIZ_task_prev_task	0x00000008
-#define AOFF_task_next_run	0x00000060
-#define ASIZ_task_next_run	0x00000008
-#define AOFF_task_prev_run	0x00000068
-#define ASIZ_task_prev_run	0x00000008
+#define AOFF_task_run_list	0x00000060
+#define ASIZ_task_run_list	0x00000010
 #define AOFF_task_binfmt	0x00000070
 #define ASIZ_task_binfmt	0x00000008
 #define AOFF_task_exit_code	0x00000078
@@ -360,115 +366,115 @@
 #define ASIZ_task_pidhash_next	0x00000008
 #define AOFF_task_pidhash_pprev	0x000000d8
 #define ASIZ_task_pidhash_pprev	0x00000008
-#define AOFF_task_tarray_ptr	0x000000e0
-#define ASIZ_task_tarray_ptr	0x00000008
-#define AOFF_task_wait_chldexit	0x000000e8
+#define AOFF_task_wait_chldexit	0x000000e0
 #define ASIZ_task_wait_chldexit	0x00000028
-#define AOFF_task_vfork_sem	0x00000110
+#define AOFF_task_vfork_sem	0x00000108
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_policy	0x00000118
+#define AOFF_task_policy	0x00000110
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000120
+#define AOFF_task_rt_priority	0x00000118
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000128
+#define AOFF_task_it_real_value	0x00000120
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000130
+#define AOFF_task_it_prof_value	0x00000128
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000138
+#define AOFF_task_it_virt_value	0x00000130
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000140
+#define AOFF_task_it_real_incr	0x00000138
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000148
+#define AOFF_task_it_prof_incr	0x00000140
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000150
+#define AOFF_task_it_virt_incr	0x00000148
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000158
+#define AOFF_task_real_timer	0x00000150
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000180
+#define AOFF_task_times	0x00000178
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x000001a0
+#define AOFF_task_start_time	0x00000198
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x000001a8
+#define AOFF_task_per_cpu_utime	0x000001a0
 #define ASIZ_task_per_cpu_utime	0x00000100
-#define AOFF_task_min_flt	0x000003a8
+#define AOFF_task_min_flt	0x000003a0
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x000003b0
+#define AOFF_task_maj_flt	0x000003a8
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000003b8
+#define AOFF_task_nswap	0x000003b0
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000003c0
+#define AOFF_task_cmin_flt	0x000003b8
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000003c8
+#define AOFF_task_cmaj_flt	0x000003c0
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000003d0
+#define AOFF_task_cnswap	0x000003c8
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000003dc
+#define AOFF_task_uid	0x000003d4
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000003e0
+#define AOFF_task_euid	0x000003d8
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000003e4
+#define AOFF_task_suid	0x000003dc
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000003e8
+#define AOFF_task_fsuid	0x000003e0
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000003ec
+#define AOFF_task_gid	0x000003e4
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000003f0
+#define AOFF_task_egid	0x000003e8
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000003f4
+#define AOFF_task_sgid	0x000003ec
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x000003f8
+#define AOFF_task_fsgid	0x000003f0
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x000003fc
+#define AOFF_task_ngroups	0x000003f4
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000400
+#define AOFF_task_groups	0x000003f8
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000480
+#define AOFF_task_cap_effective	0x00000478
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000484
+#define AOFF_task_cap_inheritable	0x0000047c
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000488
+#define AOFF_task_cap_permitted	0x00000480
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000490
+#define AOFF_task_user	0x00000488
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x00000498
+#define AOFF_task_rlim	0x00000490
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000538
+#define AOFF_task_used_math	0x00000530
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x0000053a
+#define AOFF_task_comm	0x00000532
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000054c
+#define AOFF_task_link_count	0x00000544
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000550
+#define AOFF_task_tty	0x00000548
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000558
+#define AOFF_task_semundo	0x00000550
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000560
+#define AOFF_task_semsleeping	0x00000558
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000570
-#define ASIZ_task_tss	0x00000460
-#define AOFF_task_fs	0x000009d0
+#define AOFF_task_thread	0x00000560
+#define ASIZ_task_thread	0x00000460
+#define AOFF_task_fs	0x000009c0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000009d8
+#define AOFF_task_files	0x000009c8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000009e0
+#define AOFF_task_mm	0x000009d0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009e8
+#define AOFF_task_active_mm	0x000009d8
+#define ASIZ_task_active_mm	0x00000008
+#define AOFF_task_sigmask_lock	0x000009e0
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x000009f0
+#define AOFF_task_sig	0x000009e8
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000009f8
+#define AOFF_task_signal	0x000009f0
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000a00
+#define AOFF_task_blocked	0x000009f8
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000a08
+#define AOFF_task_sigqueue	0x00000a00
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000a10
+#define AOFF_task_sigqueue_tail	0x00000a08
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000a18
+#define AOFF_task_sas_ss_sp	0x00000a10
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a20
+#define AOFF_task_sas_ss_size	0x00000a18
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000a30
+#define ASIZ_task	0x00000a20
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -477,91 +483,95 @@
 #define ASIZ_mm_mmap_cache	0x00000008
 #define AOFF_mm_pgd	0x00000018
 #define ASIZ_mm_pgd	0x00000008
-#define AOFF_mm_count	0x00000020
-#define ASIZ_mm_count	0x00000004
-#define AOFF_mm_map_count	0x00000024
+#define AOFF_mm_mm_users	0x00000020
+#define ASIZ_mm_mm_users	0x00000004
+#define AOFF_mm_mm_count	0x00000024
+#define ASIZ_mm_mm_count	0x00000004
+#define AOFF_mm_map_count	0x00000028
 #define ASIZ_mm_map_count	0x00000004
-#define AOFF_mm_mmap_sem	0x00000028
+#define AOFF_mm_mmap_sem	0x00000030
 #define ASIZ_mm_mmap_sem	0x00000038
-#define AOFF_mm_page_table_lock	0x00000060
+#define AOFF_mm_page_table_lock	0x00000068
 #define ASIZ_mm_page_table_lock	0x00000001
-#define AOFF_mm_context	0x00000068
+#define AOFF_mm_context	0x00000070
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000070
+#define AOFF_mm_start_code	0x00000078
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000078
+#define AOFF_mm_end_code	0x00000080
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000080
+#define AOFF_mm_start_data	0x00000088
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000088
+#define AOFF_mm_end_data	0x00000090
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x00000090
+#define AOFF_mm_start_brk	0x00000098
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x00000098
+#define AOFF_mm_brk	0x000000a0
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x000000a0
+#define AOFF_mm_start_stack	0x000000a8
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000a8
+#define AOFF_mm_arg_start	0x000000b0
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000b0
+#define AOFF_mm_arg_end	0x000000b8
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000b8
+#define AOFF_mm_env_start	0x000000c0
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000c0
+#define AOFF_mm_env_end	0x000000c8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000c8
+#define AOFF_mm_rss	0x000000d0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000d0
+#define AOFF_mm_total_vm	0x000000d8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000d8
+#define AOFF_mm_locked_vm	0x000000e0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000e0
+#define AOFF_mm_def_flags	0x000000e8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000e8
+#define AOFF_mm_cpu_vm_mask	0x000000f0
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x000000f0
+#define AOFF_mm_swap_cnt	0x000000f8
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x000000f8
+#define AOFF_mm_swap_address	0x00000100
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000100
+#define AOFF_mm_segments	0x00000108
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000108
+#define ASIZ_mm	0x00000110
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
-#define ASIZ_thread_wstate	0x00000002
-#define AOFF_thread_cwp	0x0000000a
-#define ASIZ_thread_cwp	0x00000002
-#define AOFF_thread_flags	0x0000000c
-#define ASIZ_thread_flags	0x00000002
-#define AOFF_thread_current_ds	0x0000000e
+#define ASIZ_thread_wstate	0x00000001
+#define AOFF_thread_cwp	0x00000009
+#define ASIZ_thread_cwp	0x00000001
+#define AOFF_thread_flags	0x0000000a
+#define ASIZ_thread_flags	0x00000001
+#define AOFF_thread_current_ds	0x0000000b
 #define ASIZ_thread_current_ds	0x00000001
-#define AOFF_thread_w_saved	0x00000010
-#define ASIZ_thread_w_saved	0x00000002
-#define AOFF_thread_new_signal	0x00000012
-#define ASIZ_thread_new_signal	0x00000002
-#define AOFF_thread_ctx	0x00000014
-#define ASIZ_thread_ctx	0x00000002
+#define AOFF_thread_w_saved	0x0000000c
+#define ASIZ_thread_w_saved	0x00000001
+#define AOFF_thread_fpdepth	0x0000000d
+#define ASIZ_thread_fpdepth	0x00000001
+#define AOFF_thread_fpsaved	0x0000000e
+#define ASIZ_thread_fpsaved	0x00000007
+#define AOFF_thread___pad1	0x00000015
+#define ASIZ_thread___pad1	0x00000003
 #define AOFF_thread_kregs	0x00000018
 #define ASIZ_thread_kregs	0x00000008
 #define AOFF_thread_utraps	0x00000020
 #define ASIZ_thread_utraps	0x00000008
-#define AOFF_thread_fpdepth	0x00000028
-#define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x00000029
-#define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread_gsr	0x00000030
+#define AOFF_thread_gsr	0x00000028
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread_xfsr	0x00000038
+#define AOFF_thread___pad2	0x0000002f
+#define ASIZ_thread___pad2	0x00000001
+#define AOFF_thread_sig_address	0x00000030
+#define ASIZ_thread_sig_address	0x00000008
+#define AOFF_thread_sig_desc	0x00000038
+#define ASIZ_thread_sig_desc	0x00000008
+#define AOFF_thread_xfsr	0x00000040
 #define ASIZ_thread_xfsr	0x00000038
-#define AOFF_thread_reg_window	0x00000070
+#define AOFF_thread___pad3	0x00000078
+#define ASIZ_thread___pad3	0x00000008
+#define AOFF_thread_reg_window	0x00000080
 #define ASIZ_thread_reg_window	0x00000380
-#define AOFF_thread_rwbuf_stkptrs	0x000003f0
+#define AOFF_thread_rwbuf_stkptrs	0x00000400
 #define ASIZ_thread_rwbuf_stkptrs	0x00000038
-#define AOFF_thread_sig_address	0x00000428
-#define ASIZ_thread_sig_address	0x00000008
-#define AOFF_thread_sig_desc	0x00000430
-#define ASIZ_thread_sig_desc	0x00000008
 #define AOFF_thread_user_cntd0	0x00000438
 #define ASIZ_thread_user_cntd0	0x00000008
 #define AOFF_thread_user_cntd1	0x00000440
@@ -606,10 +616,8 @@
 #define ASIZ_task_next_task	0x00000008
 #define AOFF_task_prev_task	0x00000058
 #define ASIZ_task_prev_task	0x00000008
-#define AOFF_task_next_run	0x00000060
-#define ASIZ_task_next_run	0x00000008
-#define AOFF_task_prev_run	0x00000068
-#define ASIZ_task_prev_run	0x00000008
+#define AOFF_task_run_list	0x00000060
+#define ASIZ_task_run_list	0x00000010
 #define AOFF_task_binfmt	0x00000070
 #define ASIZ_task_binfmt	0x00000008
 #define AOFF_task_exit_code	0x00000078
@@ -644,115 +652,115 @@
 #define ASIZ_task_pidhash_next	0x00000008
 #define AOFF_task_pidhash_pprev	0x000000d8
 #define ASIZ_task_pidhash_pprev	0x00000008
-#define AOFF_task_tarray_ptr	0x000000e0
-#define ASIZ_task_tarray_ptr	0x00000008
-#define AOFF_task_wait_chldexit	0x000000e8
+#define AOFF_task_wait_chldexit	0x000000e0
 #define ASIZ_task_wait_chldexit	0x00000030
-#define AOFF_task_vfork_sem	0x00000118
+#define AOFF_task_vfork_sem	0x00000110
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_policy	0x00000120
+#define AOFF_task_policy	0x00000118
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000128
+#define AOFF_task_rt_priority	0x00000120
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000130
+#define AOFF_task_it_real_value	0x00000128
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000138
+#define AOFF_task_it_prof_value	0x00000130
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000140
+#define AOFF_task_it_virt_value	0x00000138
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000148
+#define AOFF_task_it_real_incr	0x00000140
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000150
+#define AOFF_task_it_prof_incr	0x00000148
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000158
+#define AOFF_task_it_virt_incr	0x00000150
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000160
+#define AOFF_task_real_timer	0x00000158
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000188
+#define AOFF_task_times	0x00000180
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x000001a8
+#define AOFF_task_start_time	0x000001a0
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x000001b0
+#define AOFF_task_per_cpu_utime	0x000001a8
 #define ASIZ_task_per_cpu_utime	0x00000100
-#define AOFF_task_min_flt	0x000003b0
+#define AOFF_task_min_flt	0x000003a8
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x000003b8
+#define AOFF_task_maj_flt	0x000003b0
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000003c0
+#define AOFF_task_nswap	0x000003b8
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000003c8
+#define AOFF_task_cmin_flt	0x000003c0
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000003d0
+#define AOFF_task_cmaj_flt	0x000003c8
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000003d8
+#define AOFF_task_cnswap	0x000003d0
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000003e4
+#define AOFF_task_uid	0x000003dc
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000003e8
+#define AOFF_task_euid	0x000003e0
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000003ec
+#define AOFF_task_suid	0x000003e4
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000003f0
+#define AOFF_task_fsuid	0x000003e8
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000003f4
+#define AOFF_task_gid	0x000003ec
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000003f8
+#define AOFF_task_egid	0x000003f0
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000003fc
+#define AOFF_task_sgid	0x000003f4
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x00000400
+#define AOFF_task_fsgid	0x000003f8
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x00000404
+#define AOFF_task_ngroups	0x000003fc
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000408
+#define AOFF_task_groups	0x00000400
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000488
+#define AOFF_task_cap_effective	0x00000480
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x0000048c
+#define AOFF_task_cap_inheritable	0x00000484
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000490
+#define AOFF_task_cap_permitted	0x00000488
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000498
+#define AOFF_task_user	0x00000490
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x000004a0
+#define AOFF_task_rlim	0x00000498
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000540
+#define AOFF_task_used_math	0x00000538
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x00000542
+#define AOFF_task_comm	0x0000053a
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x00000554
+#define AOFF_task_link_count	0x0000054c
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000558
+#define AOFF_task_tty	0x00000550
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000560
+#define AOFF_task_semundo	0x00000558
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000568
+#define AOFF_task_semsleeping	0x00000560
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000570
-#define ASIZ_task_tss	0x00000460
+#define AOFF_task_thread	0x00000570
+#define ASIZ_task_thread	0x00000460
 #define AOFF_task_fs	0x000009d0
 #define ASIZ_task_fs	0x00000008
 #define AOFF_task_files	0x000009d8
 #define ASIZ_task_files	0x00000008
 #define AOFF_task_mm	0x000009e0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009e8
+#define AOFF_task_active_mm	0x000009e8
+#define ASIZ_task_active_mm	0x00000008
+#define AOFF_task_sigmask_lock	0x000009f0
 #define ASIZ_task_sigmask_lock	0x0000000c
-#define AOFF_task_sig	0x000009f8
+#define AOFF_task_sig	0x00000a00
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x00000a00
+#define AOFF_task_signal	0x00000a08
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000a08
+#define AOFF_task_blocked	0x00000a10
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000a10
+#define AOFF_task_sigqueue	0x00000a18
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000a18
+#define AOFF_task_sigqueue_tail	0x00000a20
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000a20
+#define AOFF_task_sas_ss_sp	0x00000a28
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a28
+#define AOFF_task_sas_ss_size	0x00000a30
 #define ASIZ_task_sas_ss_size	0x00000008
-#define ASIZ_task	0x00000a30
+#define ASIZ_task	0x00000a40
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -761,91 +769,95 @@
 #define ASIZ_mm_mmap_cache	0x00000008
 #define AOFF_mm_pgd	0x00000018
 #define ASIZ_mm_pgd	0x00000008
-#define AOFF_mm_count	0x00000020
-#define ASIZ_mm_count	0x00000004
-#define AOFF_mm_map_count	0x00000024
+#define AOFF_mm_mm_users	0x00000020
+#define ASIZ_mm_mm_users	0x00000004
+#define AOFF_mm_mm_count	0x00000024
+#define ASIZ_mm_mm_count	0x00000004
+#define AOFF_mm_map_count	0x00000028
 #define ASIZ_mm_map_count	0x00000004
-#define AOFF_mm_mmap_sem	0x00000028
+#define AOFF_mm_mmap_sem	0x00000030
 #define ASIZ_mm_mmap_sem	0x00000040
-#define AOFF_mm_page_table_lock	0x00000068
+#define AOFF_mm_page_table_lock	0x00000070
 #define ASIZ_mm_page_table_lock	0x0000000c
-#define AOFF_mm_context	0x00000078
+#define AOFF_mm_context	0x00000080
 #define ASIZ_mm_context	0x00000008
-#define AOFF_mm_start_code	0x00000080
+#define AOFF_mm_start_code	0x00000088
 #define ASIZ_mm_start_code	0x00000008
-#define AOFF_mm_end_code	0x00000088
+#define AOFF_mm_end_code	0x00000090
 #define ASIZ_mm_end_code	0x00000008
-#define AOFF_mm_start_data	0x00000090
+#define AOFF_mm_start_data	0x00000098
 #define ASIZ_mm_start_data	0x00000008
-#define AOFF_mm_end_data	0x00000098
+#define AOFF_mm_end_data	0x000000a0
 #define ASIZ_mm_end_data	0x00000008
-#define AOFF_mm_start_brk	0x000000a0
+#define AOFF_mm_start_brk	0x000000a8
 #define ASIZ_mm_start_brk	0x00000008
-#define AOFF_mm_brk	0x000000a8
+#define AOFF_mm_brk	0x000000b0
 #define ASIZ_mm_brk	0x00000008
-#define AOFF_mm_start_stack	0x000000b0
+#define AOFF_mm_start_stack	0x000000b8
 #define ASIZ_mm_start_stack	0x00000008
-#define AOFF_mm_arg_start	0x000000b8
+#define AOFF_mm_arg_start	0x000000c0
 #define ASIZ_mm_arg_start	0x00000008
-#define AOFF_mm_arg_end	0x000000c0
+#define AOFF_mm_arg_end	0x000000c8
 #define ASIZ_mm_arg_end	0x00000008
-#define AOFF_mm_env_start	0x000000c8
+#define AOFF_mm_env_start	0x000000d0
 #define ASIZ_mm_env_start	0x00000008
-#define AOFF_mm_env_end	0x000000d0
+#define AOFF_mm_env_end	0x000000d8
 #define ASIZ_mm_env_end	0x00000008
-#define AOFF_mm_rss	0x000000d8
+#define AOFF_mm_rss	0x000000e0
 #define ASIZ_mm_rss	0x00000008
-#define AOFF_mm_total_vm	0x000000e0
+#define AOFF_mm_total_vm	0x000000e8
 #define ASIZ_mm_total_vm	0x00000008
-#define AOFF_mm_locked_vm	0x000000e8
+#define AOFF_mm_locked_vm	0x000000f0
 #define ASIZ_mm_locked_vm	0x00000008
-#define AOFF_mm_def_flags	0x000000f0
+#define AOFF_mm_def_flags	0x000000f8
 #define ASIZ_mm_def_flags	0x00000008
-#define AOFF_mm_cpu_vm_mask	0x000000f8
+#define AOFF_mm_cpu_vm_mask	0x00000100
 #define ASIZ_mm_cpu_vm_mask	0x00000008
-#define AOFF_mm_swap_cnt	0x00000100
+#define AOFF_mm_swap_cnt	0x00000108
 #define ASIZ_mm_swap_cnt	0x00000008
-#define AOFF_mm_swap_address	0x00000108
+#define AOFF_mm_swap_address	0x00000110
 #define ASIZ_mm_swap_address	0x00000008
-#define AOFF_mm_segments	0x00000110
+#define AOFF_mm_segments	0x00000118
 #define ASIZ_mm_segments	0x00000008
-#define ASIZ_mm	0x00000118
+#define ASIZ_mm	0x00000120
 #define AOFF_thread_ksp	0x00000000
 #define ASIZ_thread_ksp	0x00000008
 #define AOFF_thread_wstate	0x00000008
-#define ASIZ_thread_wstate	0x00000002
-#define AOFF_thread_cwp	0x0000000a
-#define ASIZ_thread_cwp	0x00000002
-#define AOFF_thread_flags	0x0000000c
-#define ASIZ_thread_flags	0x00000002
-#define AOFF_thread_current_ds	0x0000000e
+#define ASIZ_thread_wstate	0x00000001
+#define AOFF_thread_cwp	0x00000009
+#define ASIZ_thread_cwp	0x00000001
+#define AOFF_thread_flags	0x0000000a
+#define ASIZ_thread_flags	0x00000001
+#define AOFF_thread_current_ds	0x0000000b
 #define ASIZ_thread_current_ds	0x00000001
-#define AOFF_thread_w_saved	0x00000010
-#define ASIZ_thread_w_saved	0x00000002
-#define AOFF_thread_new_signal	0x00000012
-#define ASIZ_thread_new_signal	0x00000002
-#define AOFF_thread_ctx	0x00000014
-#define ASIZ_thread_ctx	0x00000002
+#define AOFF_thread_w_saved	0x0000000c
+#define ASIZ_thread_w_saved	0x00000001
+#define AOFF_thread_fpdepth	0x0000000d
+#define ASIZ_thread_fpdepth	0x00000001
+#define AOFF_thread_fpsaved	0x0000000e
+#define ASIZ_thread_fpsaved	0x00000007
+#define AOFF_thread___pad1	0x00000015
+#define ASIZ_thread___pad1	0x00000003
 #define AOFF_thread_kregs	0x00000018
 #define ASIZ_thread_kregs	0x00000008
 #define AOFF_thread_utraps	0x00000020
 #define ASIZ_thread_utraps	0x00000008
-#define AOFF_thread_fpdepth	0x00000028
-#define ASIZ_thread_fpdepth	0x00000001
-#define AOFF_thread_fpsaved	0x00000029
-#define ASIZ_thread_fpsaved	0x00000007
-#define AOFF_thread_gsr	0x00000030
+#define AOFF_thread_gsr	0x00000028
 #define ASIZ_thread_gsr	0x00000007
-#define AOFF_thread_xfsr	0x00000038
+#define AOFF_thread___pad2	0x0000002f
+#define ASIZ_thread___pad2	0x00000001
+#define AOFF_thread_sig_address	0x00000030
+#define ASIZ_thread_sig_address	0x00000008
+#define AOFF_thread_sig_desc	0x00000038
+#define ASIZ_thread_sig_desc	0x00000008
+#define AOFF_thread_xfsr	0x00000040
 #define ASIZ_thread_xfsr	0x00000038
-#define AOFF_thread_reg_window	0x00000070
+#define AOFF_thread___pad3	0x00000078
+#define ASIZ_thread___pad3	0x00000008
+#define AOFF_thread_reg_window	0x00000080
 #define ASIZ_thread_reg_window	0x00000380
-#define AOFF_thread_rwbuf_stkptrs	0x000003f0
+#define AOFF_thread_rwbuf_stkptrs	0x00000400
 #define ASIZ_thread_rwbuf_stkptrs	0x00000038
-#define AOFF_thread_sig_address	0x00000428
-#define ASIZ_thread_sig_address	0x00000008
-#define AOFF_thread_sig_desc	0x00000430
-#define ASIZ_thread_sig_desc	0x00000008
 #define AOFF_thread_user_cntd0	0x00000438
 #define ASIZ_thread_user_cntd0	0x00000008
 #define AOFF_thread_user_cntd1	0x00000440
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/cache.h linux/include/asm-sparc64/cache.h
--- v2.3.12/linux/include/asm-sparc64/cache.h	Wed Mar 10 16:53:38 1999
+++ linux/include/asm-sparc64/cache.h	Fri Aug  6 11:58:00 1999
@@ -11,4 +11,12 @@
 
 #define        SMP_CACHE_BYTES		64 /* L2 cache line size. */
 
+#ifdef MODULE
+#define __cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
+#else
+#define __cacheline_aligned					\
+  __attribute__((__aligned__(SMP_CACHE_BYTES),			\
+		 __section__(".data.cacheline_aligned")))
+#endif
+
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h
--- v2.3.12/linux/include/asm-sparc64/checksum.h	Thu May 27 09:55:22 1999
+++ linux/include/asm-sparc64/checksum.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.12 1999/05/25 16:53:36 jj Exp $ */
+/* $Id: checksum.h,v 1.13 1999/07/30 09:31:13 davem Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -50,7 +50,7 @@
 			   unsigned int sum)
 {
 	int ret;
-	unsigned char cur_ds = current->tss.current_ds.seg;
+	unsigned char cur_ds = current->thread.current_ds.seg;
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
 	ret = csum_partial_copy_sparc64(src, dst, len, sum);
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (cur_ds));
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- v2.3.12/linux/include/asm-sparc64/elf.h	Thu Jun 17 01:08:50 1999
+++ linux/include/asm-sparc64/elf.h	Fri Aug  6 11:58:00 1999
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.19 1999/06/11 13:26:04 jj Exp $ */
+/* $Id: elf.h,v 1.21 1999/08/04 07:04:23 jj Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -48,7 +48,7 @@
    that it will "exec", and that there is sufficient room for the brk.  */
 
 #ifndef ELF_ET_DYN_BASE
-#define ELF_ET_DYN_BASE         0x50000000000
+#define ELF_ET_DYN_BASE         0xfffff80000000000UL
 #endif
 
 
@@ -67,17 +67,30 @@
 #define ELF_PLATFORM	(NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2)				\
-do {								\
-	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)		\
-		current->tss.flags |= SPARC_FLAG_32BIT;		\
-	else							\
-		current->tss.flags &= ~SPARC_FLAG_32BIT;	\
-								\
-	if (ibcs2)						\
-		current->personality = PER_SVR4;		\
-	else if (current->personality != PER_LINUX32)		\
-		current->personality = PER_LINUX;		\
+#define SET_PERSONALITY(ex, ibcs2)			\
+do {	unsigned char flags = current->thread.flags;	\
+	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)	\
+		flags |= SPARC_FLAG_32BIT;		\
+	else						\
+		flags &= ~SPARC_FLAG_32BIT;		\
+	if (flags != current->thread.flags) {		\
+		unsigned long pgd_cache = 0UL;		\
+		if (flags & SPARC_FLAG_32BIT)		\
+		  pgd_cache =				\
+		    pgd_val(current->mm->pgd[0])<<11UL;	\
+		__asm__ __volatile__(			\
+			"stxa\t%0, [%1] %2"		\
+			: /* no outputs */		\
+			: "r" (pgd_cache),		\
+			  "r" (TSB_REG),		\
+			  "i" (ASI_DMMU));		\
+		current->thread.flags = flags;		\
+	}						\
+							\
+	if (ibcs2)					\
+		current->personality = PER_SVR4;	\
+	else if (current->personality != PER_LINUX32)	\
+		current->personality = PER_LINUX;	\
 } while (0)
 #endif
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.3.12/linux/include/asm-sparc64/floppy.h	Sun Mar 21 07:23:38 1999
+++ linux/include/asm-sparc64/floppy.h	Wed Aug  4 15:39:46 1999
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.18 1999/03/21 10:51:38 davem Exp $
+/* $Id: floppy.h,v 1.19 1999/08/03 08:01:15 davem Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -548,6 +548,7 @@
 #ifdef CONFIG_PCI
 		struct linux_ebus *ebus;
 		struct linux_ebus_device *edev = 0;
+		unsigned long auxio_reg;
 
 		for_each_ebus(ebus) {
 			for_each_ebusdev(edev, ebus) {
@@ -575,6 +576,12 @@
 
 		sun_fdc = (struct sun_flpy_controller *)edev->base_address[0];
 		FLOPPY_IRQ = edev->irqs[0];
+
+		/* Make sure the high density bit is set, some systems
+		 * (most notably Ultra5/Ultra10) come up with it clear.
+		 */
+		auxio_reg = edev->base_address[2];
+		writel(readl(auxio_reg)|0x2, auxio_reg);
 
 		sun_pci_fd_ebus_dma = (struct linux_ebus_dma *)
 							edev->base_address[1];
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/ide.h linux/include/asm-sparc64/ide.h
--- v2.3.12/linux/include/asm-sparc64/ide.h	Sat May 15 11:12:10 1999
+++ linux/include/asm-sparc64/ide.h	Mon Aug  9 11:29:37 1999
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.14 1999/05/15 05:02:35 davem Exp $
+/* $Id: ide.h,v 1.15 1999/08/08 01:38:18 davem Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/hdreg.h>
@@ -53,7 +54,7 @@
  */
 static __inline__ void ide_init_default_hwifs(void)
 {
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
 	hw_regs_t hw;
 	int index;
 
@@ -62,7 +63,7 @@
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
 	}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
 typedef union {
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/init.h linux/include/asm-sparc64/init.h
--- v2.3.12/linux/include/asm-sparc64/init.h	Wed Mar 10 16:53:38 1999
+++ linux/include/asm-sparc64/init.h	Wed Aug  4 15:39:46 1999
@@ -1,16 +1 @@
-#ifndef _SPARC_INIT_H
-#define _SPARC_INIT_H
-
-#define __init __attribute__ ((__section__ (".text.init")))
-#define __initdata __attribute__ ((__section__ (".data.init")))
-#define __initfunc(__arginit) \
-	__arginit __init; \
-	__arginit
-/* For assembly routines */
-#define __INIT		.section	".text.init",#alloc,#execinstr
-#define __FINIT	.previous
-#define __INITDATA	.section	".data.init",#alloc,#write
-
-#define __cacheline_aligned __attribute__ ((aligned (64)))
-
-#endif
+#error "<asm/init.h> should never be used - use <linux/init.h> instead"
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.3.12/linux/include/asm-sparc64/mmu_context.h	Thu May 27 09:55:22 1999
+++ linux/include/asm-sparc64/mmu_context.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.36 1999/05/25 16:53:34 jj Exp $ */
+/* $Id: mmu_context.h,v 1.39 1999/08/02 08:39:57 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -8,122 +8,140 @@
 #include <asm/spitfire.h>
 #include <asm/spinlock.h>
 
-#define NO_CONTEXT     0
-
 #ifndef __ASSEMBLY__
 
+extern spinlock_t ctx_alloc_lock;
 extern unsigned long tlb_context_cache;
 extern unsigned long mmu_context_bmap[];
 
 #define CTX_VERSION_SHIFT	(PAGE_SHIFT - 3)
 #define CTX_VERSION_MASK	((~0UL) << CTX_VERSION_SHIFT)
 #define CTX_FIRST_VERSION	((1UL << CTX_VERSION_SHIFT) + 1UL)
+#define CTX_VALID(__ctx)	\
+	 (!(((__ctx) ^ tlb_context_cache) & CTX_VERSION_MASK))
+#define CTX_HWBITS(__ctx)	((__ctx) & ~CTX_VERSION_MASK)
 
 extern void get_new_mmu_context(struct mm_struct *mm);
 
-/* Initialize/destroy the context related info for a new mm_struct
- * instance.
+/* Initialize a new mmu context.  This is invoked when a new
+ * address space instance (unique or shared) is instantiated.
+ * A fresh mm_struct is cleared out to zeros, so this need not
+ * do anything on Sparc64 since the only thing we care about
+ * is that mm->context is an invalid context (ie. zero).
  */
-#define init_new_context(__mm)	((__mm)->context = NO_CONTEXT)
+#define init_new_context(__tsk, __mm)	do { } while(0)
 
-/* Kernel threads like rpciod and nfsd drop their mm, and then use
- * init_mm, when this happens we must make sure the secondary context is
- * updated as well.  Otherwise we have disasters relating to
- * set_fs/get_fs usage later on.
- *
- * Also we can only clear the mmu_context_bmap bit when this is
- * the final reference to the address space.
+/* Destroy a dead context.  This occurs when mmput drops the
+ * mm_users count to zero, the mmaps have been released, and
+ * all the page tables have been flushed.  Our job is to destroy
+ * any remaining processor-specific state, and in the sparc64
+ * case this just means freeing up the mmu context ID held by
+ * this task if valid.
  */
-#define destroy_context(__mm)	do { 						\
-	if ((__mm)->context != NO_CONTEXT &&					\
-	    atomic_read(&(__mm)->count) == 1) { 				\
-		if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
-			clear_bit((__mm)->context & ~(CTX_VERSION_MASK),	\
-				  mmu_context_bmap);				\
-		(__mm)->context = NO_CONTEXT; 					\
-		if(current->mm == (__mm)) {					\
-			current->tss.ctx = 0;					\
-			spitfire_set_secondary_context(0);			\
-			__asm__ __volatile__("flush %g6");			\
-		}								\
-	} 									\
-} while (0)
+#define destroy_context(__mm)					\
+do {	spin_lock(&ctx_alloc_lock);				\
+	if (CTX_VALID((__mm)->context)) {			\
+		unsigned long nr = CTX_HWBITS((__mm)->context);	\
+		mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));	\
+	}							\
+	spin_unlock(&ctx_alloc_lock);				\
+} while(0)
+
+/* Reload the two core values used by TLB miss handler
+ * processing on sparc64.  They are:
+ * 1) The physical address of mm->pgd, when full page
+ *    table walks are necessary, this is where the
+ *    search begins.
+ * 2) A "PGD cache".  For 32-bit tasks only pgd[0] is
+ *    ever used since that maps the entire low 4GB
+ *    completely.  To speed up TLB miss processing we
+ *    make this value available to the handlers.  This
+ *    decreases the amount of memory traffic incurred.
+ */
+#define reload_tlbmiss_state(__tsk, __mm) \
+do { \
+	register unsigned long paddr asm("o5"); \
+	register unsigned long pgd_cache asm("o4"); \
+	paddr = __pa((__mm)->pgd); \
+	pgd_cache = 0UL; \
+	if ((__tsk)->thread.flags & SPARC_FLAG_32BIT) \
+		pgd_cache = pgd_val((__mm)->pgd[0]) << 11UL; \
+	__asm__ __volatile__("wrpr	%%g0, 0x494, %%pstate\n\t" \
+			     "mov	%3, %%g4\n\t" \
+			     "mov	%0, %%g7\n\t" \
+			     "stxa	%1, [%%g4] %2\n\t" \
+			     "wrpr	%%g0, 0x096, %%pstate" \
+			     : /* no outputs */ \
+			     : "r" (paddr), "r" (pgd_cache),\
+			       "i" (ASI_DMMU), "i" (TSB_REG)); \
+} while(0)
 
-/* The caller must flush the current set of user windows
- * to the stack (if necessary) before we get here.
+/* Set MMU context in the actual hardware. */
+#define load_secondary_context(__mm) \
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t" \
+			     "flush	%%g6" \
+			     : /* No outputs */ \
+			     : "r" (CTX_HWBITS((__mm)->context)), \
+			       "r" (0x10), "i" (0x58))
+
+/* Clean out potential stale TLB entries due to previous
+ * users of this TLB context.  We flush TLB contexts
+ * lazily on sparc64.
  */
-extern __inline__ void __get_mmu_context(struct task_struct *tsk)
+#define clean_secondary_context() \
+	__asm__ __volatile__("stxa	%%g0, [%0] %1\n\t" \
+			     "stxa	%%g0, [%0] %2\n\t" \
+			     "flush	%%g6" \
+			     : /* No outputs */ \
+			     : "r" (0x50), "i" (0x5f), "i" (0x57))
+
+/* Switch the current MM context. */
+static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
 {
-	register unsigned long paddr asm("o5");
-	register unsigned long pgd_cache asm("o4");
-	struct mm_struct *mm = tsk->mm;
-	unsigned long asi;
-
-	if(!(tsk->tss.flags & SPARC_FLAG_KTHREAD)	&&
-	   !(tsk->flags & PF_EXITING)) {
-		unsigned long ctx = tlb_context_cache;
-		if((mm->context ^ ctx) & CTX_VERSION_MASK)
+	long dirty;
+
+	spin_lock(&mm->page_table_lock);
+	if (CTX_VALID(mm->context))
+		dirty = 0;
+	else
+		dirty = 1;
+	if (dirty || (old_mm != mm)) {
+		unsigned long vm_mask;
+
+		if (dirty)
 			get_new_mmu_context(mm);
-		tsk->tss.ctx = mm->context & 0x3ff;
-		spitfire_set_secondary_context(mm->context & 0x3ff);
-		__asm__ __volatile__("flush %g6");
-		if(!(mm->cpu_vm_mask & (1UL<<smp_processor_id()))) {
-			spitfire_flush_dtlb_secondary_context();
-			spitfire_flush_itlb_secondary_context();
-			__asm__ __volatile__("flush %g6");
+
+		vm_mask = (1UL << cpu);
+		if (!(mm->cpu_vm_mask & vm_mask)) {
+			mm->cpu_vm_mask |= vm_mask;
+			dirty = 1;
 		}
-		asi = tsk->tss.current_ds.seg;
-	} else {
-		tsk->tss.ctx = 0;
-		spitfire_set_secondary_context(0);
-		__asm__ __volatile__("flush %g6");
-		asi = ASI_P;
+
+		load_secondary_context(mm);
+		if (dirty != 0)
+			clean_secondary_context();
+		reload_tlbmiss_state(tsk, mm);
 	}
-	/* Sigh, damned include loops... just poke seg directly.  */
-	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (asi));
-	paddr = __pa(mm->pgd);
-	if((tsk->tss.flags & (SPARC_FLAG_32BIT|SPARC_FLAG_KTHREAD)) ==
-	   (SPARC_FLAG_32BIT))
-		pgd_cache = ((unsigned long) mm->pgd[0]) << 11UL;
-	else
-		pgd_cache = 0;
-	__asm__ __volatile__("
-		rdpr		%%pstate, %%o2
-		andn		%%o2, %2, %%o3
-		wrpr		%%o3, %5, %%pstate
-		mov		%4, %%g4
-		mov		%0, %%g7
-		stxa		%1, [%%g4] %3
-		wrpr		%%o2, 0x0, %%pstate
-	" : /* no outputs */
-	  : "r" (paddr), "r" (pgd_cache), "i" (PSTATE_IE),
-	    "i" (ASI_DMMU), "i" (TSB_REG), "i" (PSTATE_MG)
-	  : "o2", "o3");
+	spin_unlock(&mm->page_table_lock);
 }
 
-/* Now we define this as a do nothing macro, because the only
- * generic user right now is the scheduler, and we handle all
- * the atomicity issues by having switch_to() call the above
- * function itself.
- */
-#define get_mmu_context(x)	do { } while(0)
+/* Activate a new MM instance for the current task. */
+static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
+{
+	unsigned long vm_mask;
 
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings.  Currently,
- * this is always called for 'current', if that changes put appropriate
- * checks here.
- *
- * We set the cpu_vm_mask first to zero to enforce a tlb flush for
- * the new context above, then we set it to the current cpu so the
- * smp tlb flush routines do not get confused.
- */
-#define activate_context(__tsk)		\
-do {	flushw_user();			\
-	(__tsk)->mm->cpu_vm_mask = 0;	\
-	__get_mmu_context(__tsk);	\
-	(__tsk)->mm->cpu_vm_mask = (1UL<<smp_processor_id()); \
-} while(0)
+	spin_lock(&mm->page_table_lock);
+	if (!CTX_VALID(mm->context))
+		get_new_mmu_context(mm);
+	vm_mask = (1UL << smp_processor_id());
+	if (!(mm->cpu_vm_mask & vm_mask))
+		mm->cpu_vm_mask |= vm_mask;
+	spin_unlock(&mm->page_table_lock);
+
+	load_secondary_context(mm);
+	clean_secondary_context();
+	reload_tlbmiss_state(current, mm);
+}
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.3.12/linux/include/asm-sparc64/page.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-sparc64/page.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.25 1999/06/23 03:53:15 davem Exp $ */
+/* $Id: page.h,v 1.27 1999/07/31 00:07:25 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -18,9 +18,8 @@
 
 #ifndef __ASSEMBLY__
 
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
-#define PAGE_BUG(page) do { \
-				BUG(); } while (0)
+#define BUG()		__builtin_trap()
+#define PAGE_BUG(page)	BUG()
 
 extern void clear_page(unsigned long page);
 extern void copy_page(unsigned long to, unsigned long from);
@@ -85,7 +84,7 @@
 
 #endif /* (STRICT_MM_TYPECHECKS) */
 
-#define TASK_UNMAPPED_BASE	((current->tss.flags & SPARC_FLAG_32BIT) ? \
+#define TASK_UNMAPPED_BASE	((current->thread.flags & SPARC_FLAG_32BIT) ? \
 				 (0x0000000070000000UL) : (PAGE_OFFSET))
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/parport.h linux/include/asm-sparc64/parport.h
--- v2.3.12/linux/include/asm-sparc64/parport.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-sparc64/parport.h	Mon Aug  9 11:29:37 1999
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: parport.h,v 1.4 1999/08/08 01:38:18 davem Exp $
  * parport.h: sparc64 specific parport initialization and dma.
  *
  * Copyright (C) 1999  Eddie C. Dost  (ecd@skynet.be)
@@ -7,21 +7,33 @@
 #ifndef _ASM_SPARC64_PARPORT_H
 #define _ASM_SPARC64_PARPORT_H 1
 
+#include <linux/config.h>
 #include <asm/ebus.h>
 #include <asm/ns87303.h>
 
-static struct linux_ebus_dma *sparc_ebus_dmas[PARPORT_MAX];
+#ifdef CONFIG_PARPORT_PC_PCMCIA
+#define __maybe_init
+#define __maybe_initdata
+#else
+#define __maybe_init __init
+#define __maybe_initdata __initdata
+#endif
+
+#undef HAVE_SLOW_DEVICES
+
+#define PARPORT_PC_MAX_PORTS	PARPORT_MAX
+
+static struct linux_ebus_dma *sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
 
 static __inline__ void
 reset_dma(unsigned int dmanr)
 {
 	unsigned int dcsr;
 
-	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr) & EBUS_DCSR_INT_EN;
 	writel(EBUS_DCSR_RESET, &sparc_ebus_dmas[dmanr]->dcsr);
-
-	dcsr |= EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
-	        EBUS_DCSR_EN_CNT;
+	udelay(1);
+	dcsr = EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
+	       EBUS_DCSR_EN_CNT;
 	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
 }
 
@@ -41,14 +53,21 @@
 	unsigned int dcsr;
 
 	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-	while (dcsr & EBUS_DCSR_DRAIN)
+	if (dcsr & EBUS_DCSR_EN_DMA) {
+		while (dcsr & EBUS_DCSR_DRAIN) {
+			udelay(1);
+			dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
+		}
+		dcsr &= ~(EBUS_DCSR_EN_DMA);
+		writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+
 		dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-	dcsr &= ~(EBUS_DCSR_EN_DMA);
-	if (dcsr & EBUS_DCSR_ERR_PEND) {
-		reset_dma(dmanr);
-		dcsr &= ~(EBUS_DCSR_ERR_PEND);
+		if (dcsr & EBUS_DCSR_ERR_PEND) {
+			reset_dma(dmanr);
+			dcsr &= ~(EBUS_DCSR_ERR_PEND);
+		}
+		writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
 	}
-	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
 }
 
 static __inline__ void
@@ -86,13 +105,21 @@
 static __inline__ int
 get_dma_residue(unsigned int dmanr)
 {
-	return readl(&sparc_ebus_dmas[dmanr]->dbcr);
+	unsigned int dcsr;
+	int res;
+
+	res = readl(&sparc_ebus_dmas[dmanr]->dbcr);
+	if (res != 0) {
+		dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
+		reset_dma(dmanr);
+		writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+	}
+	return res;
 }
 
-static int __init probe_one_port(unsigned long int base,
-				 unsigned long int base_hi,
-				 int irq, int dma);
-static int __init parport_pc_init_pci(int irq, int dma);
+static int __maybe_init parport_pc_init_pci(int irq, int dma);
+
+static int user_specified __initdata = 0;
 
 int __init
 parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
@@ -114,6 +141,7 @@
 				sparc_ebus_dmas[count] =
 						(struct linux_ebus_dma *)
 							edev->base_address[2];
+				reset_dma(count);
 
 				/* Enable ECP, set bit 2 of the CTR first */
 				outb(0x04, base + 0x02);
@@ -139,8 +167,10 @@
 				ns87303_writeb(config, FCR, cfg);
 #endif
 
-				count += probe_one_port(base, base + 0x400,
-						        edev->irqs[0], count);
+				if (parport_pc_probe_port(base, base + 0x400,
+							  edev->irqs[0],
+							  count))
+					count++;
 			}
 		}
 	}
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.12/linux/include/asm-sparc64/pgtable.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-sparc64/pgtable.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.106 1999/06/27 00:38:33 davem Exp $
+/* $Id: pgtable.h,v 1.109 1999/08/02 08:57:46 jj Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -47,14 +47,14 @@
  * is different so we can optimize correctly for 32-bit tasks.
  */
 #define REAL_PTRS_PER_PMD	(1UL << (PAGE_SHIFT-2))
-#define PTRS_PER_PMD		((const int)((current->tss.flags & SPARC_FLAG_32BIT) ? \
+#define PTRS_PER_PMD		((const int)((current->thread.flags & SPARC_FLAG_32BIT) ? \
 				 (REAL_PTRS_PER_PMD >> 2) : (REAL_PTRS_PER_PMD)))
 
 /* We cannot use the top 16G because VPTE table lives there. */
 #define PTRS_PER_PGD		((1UL << (PAGE_SHIFT-3))-1)
 
 /* Kernel has a separate 44bit address space. */
-#define USER_PTRS_PER_PGD	((const int)((current->tss.flags & SPARC_FLAG_32BIT) ? \
+#define USER_PTRS_PER_PGD	((const int)((current->thread.flags & SPARC_FLAG_32BIT) ? \
 				 (1) : (PTRS_PER_PGD)))
 
 #define PTE_TABLE_SIZE	0x2000	/* 1024 entries 8 bytes each */
@@ -167,9 +167,12 @@
 /* Cache and TLB flush operations. */
 
 /* These are the same regardless of whether this is an SMP kernel or not. */
-#define flush_cache_mm(mm)			flushw_user()
-#define flush_cache_range(mm, start, end)	flushw_user()
-#define flush_cache_page(vma, page)		flushw_user()
+#define flush_cache_mm(__mm) \
+	do { if ((__mm) == current->mm) flushw_user(); } while(0)
+#define flush_cache_range(mm, start, end) \
+	flush_cache_mm(mm)
+#define flush_cache_page(vma, page) \
+	flush_cache_mm((vma)->vm_mm)
 
 /* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_icache_range(start, end)		do { } while (0)
@@ -191,16 +194,16 @@
 #define flush_cache_all()	__flush_cache_all()
 #define flush_tlb_all()		__flush_tlb_all()
 
-#define flush_tlb_mm(mm) \
-do { if((mm)->context != NO_CONTEXT) \
-	__flush_tlb_mm((mm)->context & 0x3ff, SECONDARY_CONTEXT); \
+#define flush_tlb_mm(__mm) \
+do { if(CTX_VALID((__mm)->context)) \
+	__flush_tlb_mm(CTX_HWBITS((__mm)->context), SECONDARY_CONTEXT); \
 } while(0)
 
-#define flush_tlb_range(mm, start, end) \
-do { if((mm)->context != NO_CONTEXT) { \
+#define flush_tlb_range(__mm, start, end) \
+do { if(CTX_VALID((__mm)->context)) { \
 	unsigned long __start = (start)&PAGE_MASK; \
 	unsigned long __end = (end)&PAGE_MASK; \
-	__flush_tlb_range((mm)->context & 0x3ff, __start, \
+	__flush_tlb_range(CTX_HWBITS((__mm)->context), __start, \
 			  SECONDARY_CONTEXT, __end, PAGE_SIZE, \
 			  (__end - __start)); \
      } \
@@ -208,8 +211,8 @@
 
 #define flush_tlb_page(vma, page) \
 do { struct mm_struct *__mm = (vma)->vm_mm; \
-     if(__mm->context != NO_CONTEXT) \
-	__flush_tlb_page(__mm->context & 0x3ff, (page)&PAGE_MASK, \
+     if(CTX_VALID(__mm->context)) \
+	__flush_tlb_page(CTX_HWBITS(__mm->context), (page)&PAGE_MASK, \
 			 SECONDARY_CONTEXT); \
 } while(0)
 
@@ -227,14 +230,14 @@
 
 extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
 {
-	if(mm->context != NO_CONTEXT)
+	if (CTX_VALID(mm->context))
 		smp_flush_tlb_mm(mm);
 }
 
 extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
 				       unsigned long end)
 {
-	if(mm->context != NO_CONTEXT)
+	if (CTX_VALID(mm->context))
 		smp_flush_tlb_range(mm, start, end);
 }
 
@@ -242,7 +245,7 @@
 {
 	struct mm_struct *mm = vma->vm_mm;
 
-	if(mm->context != NO_CONTEXT)
+	if (CTX_VALID(mm->context))
 		smp_flush_tlb_page(mm, page);
 }
 
@@ -520,28 +523,6 @@
 #define set_pgdir(address, entry)	do { } while(0)
 
 extern pgd_t swapper_pg_dir[1];
-
-extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
-{
-	if(pgdir != swapper_pg_dir && tsk == current) {
-		register unsigned long paddr asm("o5");
-
-		paddr = __pa(pgdir);
-		__asm__ __volatile__ ("
-			rdpr		%%pstate, %%o4
-			wrpr		%%o4, %1, %%pstate
-			mov		%3, %%g4
-			mov		%0, %%g7
-			stxa		%%g0, [%%g4] %2
-			wrpr		%%o4, 0x0, %%pstate
-		" : /* No outputs */
-		  : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE),
-		    "i" (ASI_DMMU), "i" (TSB_REG)
-		  : "o4");
-		flush_tlb_mm(current->mm);
-	}
-}
-
 /* Routines for getting a dvma scsi buffer. */
 struct mmu_sglist {
 	char *addr;
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.3.12/linux/include/asm-sparc64/processor.h	Thu May 27 09:55:22 1999
+++ linux/include/asm-sparc64/processor.h	Wed Aug  4 15:39:46 1999
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.55 1999/05/27 04:52:54 davem Exp $
+/* $Id: processor.h,v 1.57 1999/08/04 03:20:05 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -47,66 +47,61 @@
 
 /* The Sparc processor specific thread struct. */
 struct thread_struct {
-/*DC1*/	unsigned long ksp __attribute__ ((aligned(16)));
-	unsigned short wstate;
-	unsigned short cwp;
-	unsigned short flags;
+	/* D$ line 1 */
+	unsigned long ksp __attribute__ ((aligned(16)));
+	unsigned char wstate, cwp, flags;
 	mm_segment_t current_ds;
-
-/*DC2*/	unsigned short w_saved;
-	unsigned short new_signal;
-	unsigned short ctx;
-	struct pt_regs *kregs;
-
-/*DC3*/ unsigned long *utraps;
-	unsigned char fpdepth;
+	unsigned char w_saved, fpdepth;
 	unsigned char fpsaved[7];
+	unsigned char __pad1[3];
+	struct pt_regs *kregs;
+	
+	/* D$ line 2 */
+	unsigned long *utraps;
+	unsigned char gsr[7];
+	unsigned char __pad2;
+	unsigned long sig_address;
+	unsigned long sig_desc;
 	
-/*DC4*/	unsigned char gsr[7];
+	/* D$ lines 3 and 4 */
 	unsigned long xfsr[7];
+	unsigned long __pad3;
 
-	struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16)));
-	unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8)));
-	
-	unsigned long sig_address __attribute__ ((aligned (8)));
-	unsigned long sig_desc;
+	struct reg_window reg_window[NSWINS];
+	unsigned long rwbuf_stkptrs[NSWINS];
 	
 	/* Performance counter state */
 	u64 *user_cntd0, *user_cntd1;
 	u64 kernel_cntd0, kernel_cntd1;
 	u64 pcr_reg;
-
 };
 
 #endif /* !(__ASSEMBLY__) */
 
-#define SPARC_FLAG_KTHREAD      0x010    /* task is a kernel thread */
-#define SPARC_FLAG_UNALIGNED    0x020    /* is allowed to do unaligned accesses */
-#define SPARC_FLAG_NEWSIGNALS   0x040    /* task wants new-style signals */
-#define SPARC_FLAG_32BIT        0x080    /* task is older 32-bit binary */
-#define SPARC_FLAG_NEWCHILD     0x100    /* task is just-spawned child process */
-#define SPARC_FLAG_PERFCTR	0x200    /* task has performance counters active */
+#define SPARC_FLAG_UNALIGNED    0x01    /* is allowed to do unaligned accesses */
+#define SPARC_FLAG_NEWSIGNALS   0x02    /* task wants new-style signals */
+#define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary */
+#define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process */
+#define SPARC_FLAG_PERFCTR	0x10    /* task has performance counters active */
 
 #define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
 		    NULL, PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
-#define INIT_TSS  {						\
-/* ksp, wstate, cwp, flags,              current_ds, */ 	\
-   0,   0,      0,   SPARC_FLAG_KTHREAD, KERNEL_DS,		\
-/* w_saved, new_signal, ctx,		 kregs, */		\
-   0,       0,          0,		 0,			\
-/* utraps, */							\
-   0,								\
-/* fpdepth, fpsaved, gsr,   xfsr */				\
-   0,       { 0 },   { 0 }, { 0 },				\
-/* reg_window */						\
-   { { { 0, }, { 0, } }, }, 					\
-/* rwbuf_stkptrs */						\
-   { 0, 0, 0, 0, 0, 0, 0, },					\
-/* sig_address, sig_desc */					\
-   0,           0,						\
+#define INIT_THREAD  {					\
+/* ksp, wstate, cwp, flags, current_ds, */ 		\
+   0,   0,      0,   0,     KERNEL_DS,			\
+/* w_saved, fpdepth, fpsaved, pad1,  kregs, */		\
+   0,       0,       { 0 },   { 0 }, 0,			\
+/* utraps, gsr,   pad2,  sig_address, sig_desc, */	\
+   0,	   { 0 }, 0,     0,	      0,		\
+/* xfsr,  pad3, */					\
+   { 0 }, 0,						\
+/* reg_window */					\
+   { { { 0, }, { 0, } }, }, 				\
+/* rwbuf_stkptrs */					\
+   { 0, 0, 0, 0, 0, 0, 0, },				\
 /* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
-   0,          0,          0,		 0,            0,	\
+   0,          0,          0,		 0,            0, \
 }
 
 #ifndef __ASSEMBLY__
@@ -134,14 +129,13 @@
 	regs->tpc = ((pc & (~3)) - 4); \
 	regs->tnpc = regs->tpc + 4; \
 	regs->y = 0; \
-	current->tss.flags &= ~SPARC_FLAG_32BIT; \
-	current->tss.wstate = (1 << 3); \
-	if (current->tss.utraps) { \
-		if (*(current->tss.utraps) < 2) \
-			kfree (current->tss.utraps); \
+	current->thread.wstate = (1 << 3); \
+	if (current->thread.utraps) { \
+		if (*(current->thread.utraps) < 2) \
+			kfree (current->thread.utraps); \
 		else \
-			(*(current->tss.utraps))--; \
-		current->tss.utraps = NULL; \
+			(*(current->thread.utraps))--; \
+		current->thread.utraps = NULL; \
 	} \
 	__asm__ __volatile__( \
 	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
@@ -175,17 +169,15 @@
 	regs->tpc = ((pc & (~3)) - 4); \
 	regs->tnpc = regs->tpc + 4; \
 	regs->y = 0; \
-	current->tss.flags |= SPARC_FLAG_32BIT; \
-	current->tss.wstate = (2 << 3); \
-	if (current->tss.utraps) { \
-		if (*(current->tss.utraps) < 2) \
-			kfree (current->tss.utraps); \
+	current->thread.wstate = (2 << 3); \
+	if (current->thread.utraps) { \
+		if (*(current->thread.utraps) < 2) \
+			kfree (current->thread.utraps); \
 		else \
-			(*(current->tss.utraps))--; \
-		current->tss.utraps = NULL; \
+			(*(current->thread.utraps))--; \
+		current->thread.utraps = NULL; \
 	} \
 	__asm__ __volatile__( \
-	"stxa		%3, [%4] %5\n\t" \
 	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
 	"stx		%%g0, [%0 + %2 + 0x08]\n\t" \
 	"stx		%%g0, [%0 + %2 + 0x10]\n\t" \
@@ -205,19 +197,20 @@
 	"wrpr		%%g0, (2 << 3), %%wstate\n\t" \
 	: \
 	: "r" (regs), "r" (sp - REGWIN32_SZ), \
-	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])), \
-	  "r" (((unsigned long)current->mm->pgd[0])<<11UL), \
-	  "r" (TSB_REG), "i" (ASI_DMMU)); \
+	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
 } while(0)
 
 /* Free all resources held by a thread. */
 #define release_thread(tsk)		do { } while(0)
 
-#define copy_segments(nr, tsk, mm)	do { } while (0)
+extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+#define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
 #define forget_segments()		do { } while (0)
 
 #ifdef __KERNEL__
+#define THREAD_SIZE (2*PAGE_SIZE)
 /* Allocation and freeing of task_struct and kernel stack. */
 #define alloc_task_struct()   ((struct task_struct *)__get_free_pages(GFP_KERNEL, 1))
 #define free_task_struct(tsk) free_pages((unsigned long)(tsk),1)
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/resource.h linux/include/asm-sparc64/resource.h
--- v2.3.12/linux/include/asm-sparc64/resource.h	Wed Jul 28 14:47:42 1999
+++ linux/include/asm-sparc64/resource.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: resource.h,v 1.4 1998/11/19 20:01:49 davem Exp $
+/* $Id: resource.h,v 1.5 1999/07/30 09:31:21 davem Exp $
  * resource.h: Resource definitions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -25,13 +25,13 @@
 #define RLIM_NLIMITS	10
 
 #ifdef __KERNEL__
-#define INIT_RLIMITS							\
-{									\
-    {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
-    {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX},				\
-    {       0, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
-    {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
-    {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}                          \
+#define INIT_RLIMITS				\
+{						\
+    {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},	\
+    {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX},	\
+    {       0, LONG_MAX}, {LONG_MAX, LONG_MAX},	\
+    {INR_OPEN, INR_OPEN}, {0, 0},			\
+    {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}	\
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/siginfo.h linux/include/asm-sparc64/siginfo.h
--- v2.3.12/linux/include/asm-sparc64/siginfo.h	Mon Apr 26 15:55:54 1999
+++ linux/include/asm-sparc64/siginfo.h	Mon Aug  2 22:07:16 1999
@@ -57,7 +57,7 @@
 			clock_t _stime;
 		} _sigchld;
 
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
 		struct {
 			void *_addr; /* faulting insn/memory ref. */
 			int  _trapno; /* TRAP # which caused the signal */
@@ -84,7 +84,7 @@
 		/* kill() */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
-			__kernel_uid_t32 _uid;		/* sender's uid */
+			unsigned int _uid;		/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -96,19 +96,20 @@
 		/* POSIX.1b signals */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
-			__kernel_uid_t32 _uid;		/* sender's uid */
+			unsigned int _uid;		/* sender's uid */
 			sigval_t32 _sigval;
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			__kernel_pid_t32 _pid;		/* which child */
-			int _status;		/* exit code */
+			unsigned int _uid;		/* sender's uid */
+			int _status;			/* exit code */
 			__kernel_clock_t32 _utime;
 			__kernel_clock_t32 _stime;
 		} _sigchld;
 
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
 		struct {
 			u32 _addr; /* faulting insn/memory ref. */
 			int _trapno;
@@ -144,6 +145,7 @@
  * si_code values
  * Digital reserves positive values for kernel-generated signals.
  */
+#define SI_NOINFO	32767	/* no information in siginfo_t */
 #define SI_USER		0	/* sent by kill, sigsend, raise */
 #define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
 #define SI_QUEUE	-1	/* sent by sigqueue */
@@ -224,6 +226,12 @@
 #define POLL_PRI	5	/* high priority input available */
 #define POLL_HUP	6	/* device disconnected */
 #define NSIGPOLL	6
+
+/*
+ * SIGEMT si_codes
+ */
+#define EMT_TAGOVF	1	/* tag overflow */
+#define NSIGEMT		1
 
 /*
  * sigevent definitions
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.3.12/linux/include/asm-sparc64/smp.h	Sun Mar 28 09:07:47 1999
+++ linux/include/asm-sparc64/smp.h	Mon Aug  2 22:07:16 1999
@@ -6,7 +6,7 @@
 #ifndef _SPARC64_SMP_H
 #define _SPARC64_SMP_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <asm/asi.h>
 
 #ifndef __ASSEMBLY__
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.3.12/linux/include/asm-sparc64/spinlock.h	Thu Jul  8 15:42:21 1999
+++ linux/include/asm-sparc64/spinlock.h	Mon Aug  2 22:07:16 1999
@@ -10,11 +10,16 @@
 
 #ifndef __SMP__
 
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED 0
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } spinlock_t;
+# define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+  typedef unsigned char spinlock_t;
+# define SPIN_LOCK_UNLOCKED 0
+#endif
 
 #define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
+#define spin_lock(lock)		(void)(lock)	/* Avoid warnings about unused variable */
 #define spin_trylock(lock)	(1)
 #define spin_unlock_wait(lock)	do { } while(0)
 #define spin_unlock(lock)	do { } while(0)
@@ -42,12 +47,17 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-typedef unsigned int rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } rwlock_t;
+# define RW_LOCK_UNLOCKED (rwlock_t) { }
+#else
+  typedef unsigned int rwlock_t;
+# define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
-#define read_lock(lock)		do { } while(0)
+#define read_lock(lock)		(void)(lock)	/* Avoid warnings about unused variable */
 #define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	do { } while(0)
+#define write_lock(lock)	(void)(lock)	/* Likewise */
 #define write_unlock(lock)	do { } while(0)
 #define read_lock_irq(lock)	cli()
 #define read_unlock_irq(lock)	sti()
@@ -372,4 +382,4 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-#endif /* !(__SPARC64_SPIN%0_H) */
+#endif /* !(__SPARC64_SPINLOCK_H) */
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.3.12/linux/include/asm-sparc64/system.h	Tue May 11 08:24:32 1999
+++ linux/include/asm-sparc64/system.h	Wed Aug  4 15:39:46 1999
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.50 1999/05/08 03:03:22 davem Exp $ */
+/* $Id: system.h,v 1.53 1999/08/03 05:16:14 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -124,6 +124,8 @@
 }
 
 #define flush_user_windows flushw_user
+#define flush_register_windows flushw_all
+#define prepare_to_switch flushw_all
 
 	/* See what happens when you design the chip correctly?
 	 *
@@ -135,20 +137,19 @@
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
 #define switch_to(prev, next, last)						\
-do {	if (current->tss.flags & SPARC_FLAG_PERFCTR) {				\
+do {	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		unsigned long __tmp;						\
 		read_pcr(__tmp);						\
-		current->tss.pcr_reg = __tmp;					\
+		current->thread.pcr_reg = __tmp;				\
 		read_pic(__tmp);						\
-		current->tss.kernel_cntd0 += (unsigned int)(__tmp);		\
-		current->tss.kernel_cntd1 += ((__tmp) >> 32);			\
+		current->thread.kernel_cntd0 += (unsigned int)(__tmp);		\
+		current->thread.kernel_cntd1 += ((__tmp) >> 32);		\
 	}									\
 	save_and_clear_fpu();							\
-	__asm__ __volatile__(							\
-	"flushw\n\t"								\
-	"wrpr	%g0, 0x94, %pstate\n\t");					\
-	__get_mmu_context(next);						\
-	(next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());			\
+	/* If you are tempted to conditionalize the following */		\
+	/* so that ASI is only written if it changes, think again. */		\
+	__asm__ __volatile__("wr %%g0, %0, %%asi"				\
+			     : : "r" (next->thread.current_ds.seg));		\
 	__asm__ __volatile__(							\
 	"mov	%%g6, %%g5\n\t"							\
 	"wrpr	%%g0, 0x95, %%pstate\n\t"					\
@@ -156,15 +157,15 @@
 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"					\
 	"rdpr	%%wstate, %%o5\n\t"						\
 	"stx	%%o6, [%%g6 + %3]\n\t"						\
-	"sth	%%o5, [%%g6 + %2]\n\t"						\
+	"stb	%%o5, [%%g6 + %2]\n\t"						\
 	"rdpr	%%cwp, %%o5\n\t"						\
-	"sth	%%o5, [%%g6 + %5]\n\t"						\
+	"stb	%%o5, [%%g6 + %5]\n\t"						\
 	"mov	%1, %%g6\n\t"							\
-	"lduh	[%1 + %5], %%g1\n\t"						\
+	"ldub	[%1 + %5], %%g1\n\t"						\
 	"wrpr	%%g1, %%cwp\n\t"						\
 	"ldx	[%%g6 + %3], %%o6\n\t"						\
-	"lduh	[%%g6 + %2], %%o5\n\t"						\
-	"lduh	[%%g6 + %4], %%o7\n\t"						\
+	"ldub	[%%g6 + %2], %%o5\n\t"						\
+	"ldub	[%%g6 + %4], %%o7\n\t"						\
 	"mov	%%g6, %%l2\n\t"							\
 	"wrpr	%%o5, 0x0, %%wstate\n\t"					\
 	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"					\
@@ -172,22 +173,23 @@
 	"wrpr	%%g0, 0x94, %%pstate\n\t"					\
 	"mov	%%l2, %%g6\n\t"							\
 	"wrpr	%%g0, 0x96, %%pstate\n\t"					\
-	"andcc	%%o7, 0x100, %%g0\n\t"						\
+	"andcc	%%o7, %6, %%g0\n\t"						\
 	"bne,pn	%%icc, ret_from_syscall\n\t"					\
 	" mov	%%g5, %0\n\t"							\
 	: "=&r" (last)								\
 	: "r" (next),								\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),	\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),	\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.flags)),	\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))	\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.wstate)),\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.ksp)),	\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.flags)),\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.cwp)),	\
+	  "i" (SPARC_FLAG_NEWCHILD)						\
 	: "cc", "g1", "g2", "g3", "g5", "g7",					\
 	  "l2", "l3", "l4", "l5", "l6", "l7",					\
 	  "i0", "i1", "i2", "i3", "i4", "i5",					\
 	  "o0", "o1", "o2", "o3", "o4", "o5", "o7");				\
 	/* If you fuck with this, update ret_from_syscall code too. */		\
-	if (current->tss.flags & SPARC_FLAG_PERFCTR) {				\
-		write_pcr(current->tss.pcr_reg);				\
+	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
+		write_pcr(current->thread.pcr_reg);				\
 		reset_pic();							\
 	}									\
 } while(0)
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- v2.3.12/linux/include/asm-sparc64/ttable.h	Thu Apr 22 19:24:52 1999
+++ linux/include/asm-sparc64/ttable.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.11 1999/03/29 12:38:12 jj Exp $ */
+/* $Id: ttable.h,v 1.12 1999/07/30 09:31:24 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -91,7 +91,7 @@
 	nop;nop;nop;
 	
 #define TRAP_UTRAP(handler,lvl)						\
-	ldx	[%g6 + AOFF_task_tss + AOFF_thread_utraps], %g1;	\
+	ldx	[%g6 + AOFF_task_thread + AOFF_thread_utraps], %g1;	\
 	sethi	%hi(109f), %g7;						\
 	brz,pn	%g1, utrap;						\
 	 or	%g7, %lo(109f), %g7;					\
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.3.12/linux/include/asm-sparc64/uaccess.h	Thu May 27 09:55:22 1999
+++ linux/include/asm-sparc64/uaccess.h	Mon Aug  2 22:07:16 1999
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.30 1999/05/25 16:53:32 jj Exp $ */
+/* $Id: uaccess.h,v 1.31 1999/07/30 09:31:24 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -36,14 +36,14 @@
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
-#define get_fs() (current->tss.current_ds)
+#define get_fs() (current->thread.current_ds)
 #define get_ds() (KERNEL_DS)
 
 #define segment_eq(a,b)  ((a).seg == (b).seg)
 
 #define set_fs(val)								\
 do {										\
-	current->tss.current_ds = (val);					\
+	current->thread.current_ds = (val);					\
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg));	\
 } while(0)
 
diff -u --recursive --new-file v2.3.12/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.3.12/linux/include/asm-sparc64/unistd.h	Thu Apr 22 19:24:52 1999
+++ linux/include/asm-sparc64/unistd.h	Wed Aug  4 15:39:46 1999
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.28 1999/04/07 17:14:19 davem Exp $ */
+/* $Id: unistd.h,v 1.31 1999/08/04 03:20:06 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -225,7 +225,7 @@
 #define __NR_syslog             207 /* Linux Specific                              */
 /* #define __NR_olduname        208    Linux Specific                              */
 /* #define __NR_iopl            209    Linux Specific - i386 specific, unused      */
-#define __NR_idle               210 /* Linux Specific                              */
+/* #define __NR_idle            210    Linux Specific - was sys_idle, now unused   */
 /* #define __NR_vm86            211    Linux Specific - i386 specific, unused      */
 #define __NR_waitpid            212 /* Linux Specific                              */
 #define __NR_swapoff            213 /* Linux Specific                              */
@@ -411,7 +411,6 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static __inline__ _syscall0(int,idle)
 static __inline__ _syscall0(int,pause)
 static __inline__ _syscall0(int,sync)
 static __inline__ _syscall0(pid_t,setsid)
@@ -430,8 +429,6 @@
 {
 	return waitpid(-1,wait_stat,0);
 }
-
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 #endif /* __KERNEL_SYSCALLS__ */
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h
--- v2.3.12/linux/include/linux/apm_bios.h	Sat Nov 28 17:18:54 1998
+++ linux/include/linux/apm_bios.h	Fri Aug  6 11:09:40 1999
@@ -76,9 +76,6 @@
  */
 extern struct apm_bios_info	apm_bios_info;
 
-extern void		apm_bios_init(void);
-extern void		apm_setup(char *, int *);
-
 extern int		apm_register_callback(int (*callback)(apm_event_t));
 extern void		apm_unregister_callback(int (*callback)(apm_event_t));
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.3.12/linux/include/linux/binfmts.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/binfmts.h	Mon Aug  9 12:42:08 1999
@@ -50,15 +50,6 @@
 
 extern int open_dentry(struct dentry *, int mode);
 
-extern int init_elf_binfmt(void);
-extern int init_elf32_binfmt(void);
-extern int init_irix_binfmt(void);
-extern int init_aout_binfmt(void);
-extern int init_aout32_binfmt(void);
-extern int init_script_binfmt(void);
-extern int init_em86_binfmt(void);
-extern int init_misc_binfmt(void);
-
 extern int prepare_binprm(struct linux_binprm *);
 extern void remove_arg_zero(struct linux_binprm *);
 extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
diff -u --recursive --new-file v2.3.12/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.12/linux/include/linux/blk.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/blk.h	Mon Aug  9 12:43:56 1999
@@ -333,24 +333,6 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
-#elif (MAJOR_NR == MFM_ACORN_MAJOR)
-
-#define DEVICE_NAME "mfm disk"
-#define DEVICE_INTR do_mfm
-#define DEVICE_REQUEST do_mfm_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-
-#elif (MAJOR_NR == MFM_ACORN_MAJOR)
-
-#define DEVICE_NAME "mfm disk"
-#define DEVICE_INTR do_mfm
-#define DEVICE_REQUEST do_mfm_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
diff -u --recursive --new-file v2.3.12/linux/include/linux/busmouse.h linux/include/linux/busmouse.h
--- v2.3.12/linux/include/linux/busmouse.h	Wed May 12 13:27:37 1999
+++ linux/include/linux/busmouse.h	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-#ifndef _LINUX_BUSMOUSE_H
-#define _LINUX_BUSMOUSE_H
-
-/*
- * linux/include/linux/busmouse.h: header file for Logitech Bus Mouse driver
- * by James Banks
- *
- * based on information gleamed from various mouse drivers on the net
- *
- * Heavily modified by David giller (rafetmad@oxy.edu)
- *
- * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
- * gt7080a@prism.gatech.edu (13JUL92)
- *
- * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
- *
- * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
- *    8/28/92
- *
- * Microsoft Bus Mouse support folded into 0.97pl4 code
- *    by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
- * Changes:  Logitech and Microsoft support in the same kernel.
- *           Defined new constants in busmouse.h for MS mice.
- *           Added int mse_busmouse_type to distinguish busmouse types
- *           Added a couple of new functions to handle differences in using
- *             MS vs. Logitech (where the int variable wasn't appropriate).
- *
- */
-
-#define MOUSE_IRQ		5
-#define LOGITECH_BUSMOUSE       0   /* Minor device # for Logitech  */
-#define MICROSOFT_BUSMOUSE      2   /* Minor device # for Microsoft */
-
-/*--------- LOGITECH BUSMOUSE ITEMS -------------*/
-
-#define	LOGIBM_BASE		0x23c
-#define	MSE_DATA_PORT		0x23c
-#define	MSE_SIGNATURE_PORT	0x23d
-#define	MSE_CONTROL_PORT	0x23e
-#define	MSE_INTERRUPT_PORT	0x23e
-#define	MSE_CONFIG_PORT		0x23f
-#define	LOGIBM_EXTENT		0x4
-
-#define	MSE_ENABLE_INTERRUPTS	0x00
-#define	MSE_DISABLE_INTERRUPTS	0x10
-
-#define	MSE_READ_X_LOW		0x80
-#define	MSE_READ_X_HIGH		0xa0
-#define	MSE_READ_Y_LOW		0xc0
-#define	MSE_READ_Y_HIGH		0xe0
-
-/* Magic number used to check if the mouse exists */
-#define MSE_CONFIG_BYTE		0x91
-#define MSE_DEFAULT_MODE	0x90
-#define MSE_SIGNATURE_BYTE	0xa5
-
-/* useful Logitech Mouse macros */
-
-#define MSE_INT_OFF()	outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
-#define MSE_INT_ON()	outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
-
-/*--------- MICROSOFT BUSMOUSE ITEMS -------------*/
-
-#define	MSBM_BASE			0x23d
-#define	MS_MSE_DATA_PORT	        0x23d
-#define	MS_MSE_SIGNATURE_PORT	        0x23e
-#define	MS_MSE_CONTROL_PORT	        0x23c
-#define	MS_MSE_CONFIG_PORT		0x23f
-#define	MSBM_EXTENT			0x3
-
-#define	MS_MSE_ENABLE_INTERRUPTS	0x11
-#define	MS_MSE_DISABLE_INTERRUPTS	0x10
-
-#define	MS_MSE_READ_BUTTONS             0x00
-#define	MS_MSE_READ_X		        0x01
-#define	MS_MSE_READ_Y                   0x02
-
-#define MS_MSE_START                    0x80
-#define MS_MSE_COMMAND_MODE             0x07
-
-/* useful microsoft busmouse macros */
-
-#define MS_MSE_INT_OFF() {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \
-			    outb(MS_MSE_DISABLE_INTERRUPTS, MS_MSE_DATA_PORT);}
-#define MS_MSE_INT_ON()  {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \
-			    outb(MS_MSE_ENABLE_INTERRUPTS, MS_MSE_DATA_PORT);}
-
- 
-struct mouse_status {
-	unsigned char	buttons;
-	unsigned char	latch_buttons;
-	int		dx;
-	int		dy;	
-	int 		present;
-	int		ready;
-	int		active;
-	wait_queue_head_t wait;
-	struct fasync_struct *fasyncptr;
-};
-
-/* Function Prototypes */
-
-#endif
-
diff -u --recursive --new-file v2.3.12/linux/include/linux/capability.h linux/include/linux/capability.h
--- v2.3.12/linux/include/linux/capability.h	Tue Jun 22 14:41:43 1999
+++ linux/include/linux/capability.h	Mon Aug  9 12:42:07 1999
@@ -264,6 +264,10 @@
 #define CAP_SYS_TTY_CONFIG   26
 
 #ifdef __KERNEL__
+/* 
+ * Bounding set
+ */
+extern kernel_cap_t cap_bset;
 
 /*
  * Internal kernel functions only
@@ -289,7 +293,7 @@
 #define CAP_TO_MASK(x) (1 << (x))
 #define cap_raise(c, flag)   (cap_t(c) |=  CAP_TO_MASK(flag))
 #define cap_lower(c, flag)   (cap_t(c) &= ~CAP_TO_MASK(flag))
-#define cap_raised(c, flag)  (cap_t(c) &   CAP_TO_MASK(flag))
+#define cap_raised(c, flag)  (cap_t(c) & CAP_TO_MASK(flag) & cap_bset)
 
 static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
 {
diff -u --recursive --new-file v2.3.12/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.3.12/linux/include/linux/cdrom.h	Sun Mar 21 18:37:56 1999
+++ linux/include/linux/cdrom.h	Thu Aug  5 16:24:15 1999
@@ -119,6 +119,14 @@
 /* This ioctl is only used by sbpcd at the moment */
 #define CDROMAUDIOBUFSIZ        0x5382	/* set the audio buffer size */
 
+/* DVD-ROM Specific ioctls */
+#define DVD_READ_STRUCT		0x5390  /* Read structure */
+#define DVD_WRITE_STRUCT	0x5391  /* Write structure */
+#define DVD_AUTH		0x5392  /* Authentication */
+
+#define CDROM_SEND_PACKET	0x5393	/* send a packet to the drive */
+#define CDROM_BLANK		0x5394	/* blank */
+
 /*******************************************************
  * CDROM IOCTL structures
  *******************************************************/
@@ -243,6 +251,17 @@
 	unsigned short len;
 };
 
+#define CDROM_PACKET_SIZE	12
+
+/* for CDROM_PACKET_COMMAND ioctl */
+struct cdrom_generic_command
+{
+	unsigned char 	cmd[CDROM_PACKET_SIZE];
+	unsigned char 	*buffer;
+	unsigned int 	buflen;
+	int		stat;
+};
+
 
 /*
  * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, 
@@ -342,6 +361,12 @@
 #define CDC_RESET               0x200   /* hard reset device */
 #define CDC_IOCTLS              0x400   /* driver has non-standard ioctls */
 #define CDC_DRIVE_STATUS        0x800   /* driver implements drive status */
+#define CDC_GENERIC_PACKET	0x1000	/* driver implements generic packets */
+#define CDC_CD_R		0x2000	/* drive is a CD-R */
+#define CDC_CD_RW		0x4000	/* drive is a CD-RW */
+#define CDC_DVD			0x8000	/* drive is a DVD */
+#define CDC_DVD_R		0x10000	/* drive can write DVD-R */
+#define CDC_DVD_RAM		0x20000	/* drive can write DVD-RAM */
 
 /* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
 #define CDS_NO_INFO		0	/* if not implemented */
@@ -370,6 +395,172 @@
 #define CDSL_NONE       	((int) (~0U>>1)-1)
 #define CDSL_CURRENT    	((int) (~0U>>1))
 
+/*********************************************************************
+ * MMC commands and such
+ *********************************************************************/
+
+#define DVD_SEND_KEY		0xa3
+#define DVD_REPORT_KEY		0xa4
+#define DVD_READ_STRUCTURE	0xad
+
+#define DVD_STRUCT_PHYSICAL	0x00
+#define DVD_STRUCT_COPYRIGHT	0x01
+#define DVD_STRUCT_DISCKEY	0x02
+#define DVD_STRUCT_BCA		0x03
+#define DVD_STRUCT_MANUFACT	0x04
+
+struct dvd_layer {
+	u_char book_version	: 4;
+	u_char book_type	: 4;
+	u_char min_rate		: 4;
+	u_char disc_size	: 4;
+	u_char layer_type	: 4;
+	u_char track_path	: 1;
+	u_char nlayers		: 2;
+	u_char track_density	: 4;
+	u_char linear_density	: 4;
+	u_char bca		: 1;
+	u_char start_sector;
+	u_char end_sector;
+	u_char end_sector_l0;
+};
+
+struct dvd_physical {
+	u_char type;
+	u_char layer_num;
+	struct dvd_layer layer[4];
+};
+
+struct dvd_copyright {
+	u_char type;
+
+	u_char layer_num;
+	u_char cpst;
+	u_char rmi;
+};
+
+struct dvd_disckey {
+	u_char type;
+
+	unsigned agid			: 2;
+	u_char value[2048];
+};
+
+struct dvd_bca {
+	u_char type;
+
+	int len;
+	u_char value[188];
+};
+
+struct dvd_manufact {
+	u_char type;
+
+	u_char layer_num;
+	int len;
+	u_char value[2048];
+};
+
+typedef union {
+	u_char type;
+
+	struct dvd_physical	physical;
+	struct dvd_copyright	copyright;
+	struct dvd_disckey	disckey;
+	struct dvd_bca		bca;
+	struct dvd_manufact	manufact;
+} dvd_struct;
+
+/*
+ * DVD authentication ioctl
+ */
+
+/* Authentication states */
+#define DVD_LU_SEND_AGID	0
+#define DVD_HOST_SEND_CHALLENGE	1
+#define DVD_LU_SEND_KEY1	2
+#define DVD_LU_SEND_CHALLENGE	3
+#define DVD_HOST_SEND_KEY2	4
+
+/* Termination states */
+#define DVD_AUTH_ESTABLISHED	5
+#define DVD_AUTH_FAILURE	6
+
+/* Other functions */
+#define DVD_LU_SEND_TITLE_KEY	7
+#define DVD_LU_SEND_ASF		8
+#define DVD_INVALIDATE_AGID	9
+
+/* State data */
+typedef u_char dvd_key[5];		/* 40-bit value, MSB is first elem. */
+typedef u_char dvd_challenge[10];	/* 80-bit value, MSB is first elem. */
+
+struct dvd_lu_send_agid {
+	u_char type;
+	unsigned agid		: 2;
+};
+
+struct dvd_host_send_challenge {
+	u_char type;
+	unsigned agid		: 2;
+
+	dvd_challenge chal;
+};
+
+struct dvd_send_key {
+	u_char type;
+	unsigned agid		: 2;
+
+	dvd_key key;
+};
+
+struct dvd_lu_send_challenge {
+	u_char type;
+	unsigned agid		: 2;
+
+	dvd_challenge chal;
+};
+
+#define DVD_CPM_NO_COPYRIGHT	0
+#define DVD_CPM_COPYRIGHTED	1
+
+#define DVD_CP_SEC_NONE		0
+#define DVD_CP_SEC_EXIST	1
+
+#define DVD_CGMS_UNRESTRICTED	0
+#define DVD_CGMS_SINGLE		2
+#define DVD_CGMS_RESTRICTED	3
+
+struct dvd_lu_send_title_key {
+	u_char type;
+	unsigned agid		: 2;
+
+	dvd_key title_key;
+	int lba;
+	unsigned cpm		: 1;
+	unsigned cp_sec		: 1;
+	unsigned cgms		: 2;
+};
+
+struct dvd_lu_send_asf {
+	u_char type;
+	unsigned agid		: 2;
+
+	unsigned asf		: 1;
+};
+
+typedef union {
+	u_char type;
+
+	struct dvd_lu_send_agid		lsa;
+	struct dvd_host_send_challenge	hsc;
+	struct dvd_send_key		lsk;
+	struct dvd_lu_send_challenge	lsc;
+	struct dvd_send_key		hsk;
+	struct dvd_lu_send_title_key	lstk;
+	struct dvd_lu_send_asf		lsasf;
+} dvd_authinfo;
+
 #ifdef __KERNEL__
 /* Uniform cdrom data structures for cdrom.c */
 struct cdrom_device_info {
@@ -413,6 +604,9 @@
 /* driver specifications */
 	const int capability;   /* capability flags */
 	int n_minors;           /* number of active minor devices */
+	/* handle uniform packets for scsi type devices (scsi,atapi) */
+	int (*generic_packet) (struct cdrom_device_info *,
+			       struct cdrom_generic_command *);
 };
 
 /* the general file operations structure: */
diff -u --recursive --new-file v2.3.12/linux/include/linux/fat_cvf.h linux/include/linux/fat_cvf.h
--- v2.3.12/linux/include/linux/fat_cvf.h	Thu Jan  8 14:02:41 1998
+++ linux/include/linux/fat_cvf.h	Mon Aug  9 11:43:49 1999
@@ -27,7 +27,6 @@
   int (*fat_access) (struct super_block *sb,int nr,int new_value);
   int (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
   int (*cvf_bmap) (struct inode *inode,int block);
-  int (*cvf_smap) (struct inode *inode,int sector);
   ssize_t (*cvf_file_read) ( struct file *, char *, size_t, loff_t *);
   ssize_t (*cvf_file_write) ( struct file *, const char *, size_t, loff_t *);
   int (*cvf_mmap) (struct file *, struct vm_area_struct *);
diff -u --recursive --new-file v2.3.12/linux/include/linux/fb.h linux/include/linux/fb.h
--- v2.3.12/linux/include/linux/fb.h	Sat Apr 24 17:51:48 1999
+++ linux/include/linux/fb.h	Mon Aug  9 11:56:26 1999
@@ -39,6 +39,10 @@
 #define FB_AUX_TEXT_MGA_STEP16	3	/* MGA Millenium I: text, attr, 14 reserved bytes */
 #define FB_AUX_TEXT_MGA_STEP8	4	/* other MGAs:      text, attr,  6 reserved bytes */
 
+#define FB_AUX_VGA_PLANES_VGA4		0	/* 16 color planes (EGA/VGA) */
+#define FB_AUX_VGA_PLANES_CFB4		1	/* CFB4 in planes (VGA) */
+#define FB_AUX_VGA_PLANES_CFB8		2	/* CFB8 in planes (VGA) */
+
 #define FB_VISUAL_MONO01		0	/* Monochr. 1=Black 0=White */
 #define FB_VISUAL_MONO10		1	/* Monochr. 1=White 0=Black */
 #define FB_VISUAL_TRUECOLOR		2	/* True color	*/
@@ -69,9 +73,13 @@
 #define FB_ACCEL_MATROX_MGAG100	20	/* Matrox G100 (Productiva G100) */
 #define FB_ACCEL_MATROX_MGAG200	21	/* Matrox G200 (Myst, Mill, ...) */
 #define FB_ACCEL_SUN_CG14	22	/* Sun cgfourteen		 */
-#define FB_ACCEL_SUN_BWTWO	23	/* Sun bwtwo			 */
-#define FB_ACCEL_SUN_CGTHREE	24	/* Sun cgthree			 */
-#define FB_ACCEL_SUN_TCX	25	/* Sun tcx			 */
+#define FB_ACCEL_SUN_BWTWO	23	/* Sun bwtwo			*/
+#define FB_ACCEL_SUN_CGTHREE	24	/* Sun cgthree			*/
+#define FB_ACCEL_SUN_TCX	25	/* Sun tcx			*/
+#define FB_ACCEL_MATROX_MGAG400	26	/* Matrox G400			*/
+#define FB_ACCEL_NV3		27	/* nVidia RIVA 128              */
+#define FB_ACCEL_NV4		28	/* nVidia RIVA TNT		*/
+#define FB_ACCEL_NV5		29	/* nVidia RIVA TNT2		*/
 
 struct fb_fix_screeninfo {
 	char id[16];			/* identification string eg "TT Builtin" */
diff -u --recursive --new-file v2.3.12/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.12/linux/include/linux/fs.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/fs.h	Mon Aug  9 12:42:06 1999
@@ -63,7 +63,7 @@
 #define READ 0
 #define WRITE 1
 #define READA 2		/* read-ahead  - don't block if no resources */
-#define WRITEA 3	/* write-ahead - don't block if no resources */
+
 #define WRITERAW 5	/* raw write - don't play with buffer lists */
 
 #ifndef NULL
@@ -898,6 +898,7 @@
 extern int block_read_full_page(struct file *, struct page *);
 extern int block_write_full_page (struct file *, struct page *);
 extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *);
+extern int block_write_cont_page (struct file *, struct page *, unsigned long, unsigned long, const char *);
 extern int block_flushpage(struct inode *, struct page *, unsigned long);
 
 extern int generic_file_mmap(struct file *, struct vm_area_struct *);
diff -u --recursive --new-file v2.3.12/linux/include/linux/hfmodem.h linux/include/linux/hfmodem.h
--- v2.3.12/linux/include/linux/hfmodem.h	Wed May 12 13:27:37 1999
+++ linux/include/linux/hfmodem.h	Wed Dec 31 16:00:00 1969
@@ -1,256 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      hfmodem.h  --  Linux soundcard HF FSK driver.
- *
- *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *        Swiss Federal Institute of Technology (ETH), Electronics Lab
- *
- *      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 is the Linux realtime sound output driver
- */
-
-/*****************************************************************************/
-
-#ifndef _HFMODEM_H
-#define _HFMODEM_H
-/* --------------------------------------------------------------------- */
-
-#include <linux/version.h>
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#if LINUX_VERSION_CODE >= 0x20100
-#include <linux/poll.h>
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#define HFMODEM_MINOR         145
-
-#define HFMODEM_SRATE        8000
-#define HFMODEM_MAXBITS      4800   /* required for GTOR 300 baud mode */
-#define HFMODEM_MINBAUD        40
-#define HFMODEM_MAXBAUD       400
-#define HFMODEM_MAXCORRLEN   ((HFMODEM_SRATE+HFMODEM_MINBAUD-1)/HFMODEM_MINBAUD)
-
-/* --------------------------------------------------------------------- */
-
-typedef unsigned long hfmodem_time_t;
-typedef int hfmodem_soft_t;
-typedef unsigned long hfmodem_id_t;
-
-/* --------------------------------------------------------------------- */
-
-struct hfmodem_ioctl_fsk_tx_request {
-	hfmodem_time_t tstart;
-	hfmodem_time_t tinc;
-	int inv;
-	hfmodem_id_t id;
-	unsigned int nbits;
-	unsigned char *data;
-	unsigned int freq[2];
-};
-
-struct hfmodem_ioctl_fsk_rx_request {
-	hfmodem_time_t tstart;
-	hfmodem_time_t tinc;
-	unsigned int baud;
-	hfmodem_id_t id;
-	unsigned int nbits;
-	hfmodem_soft_t *data;
-	unsigned int freq[2];
-};
-
-struct hfmodem_ioctl_mixer_params {
-	int src;
-	int igain;
-	int ogain;
-};
-
-struct hfmodem_ioctl_sample_params {
-	__s16 *data;
-	int len;
-};
-
-#define HFMODEM_IOCTL_FSKTXREQUEST    _IOW('H', 0, struct hfmodem_ioctl_fsk_tx_request)
-#define HFMODEM_IOCTL_FSKRXREQUEST    _IOW('H', 1, struct hfmodem_ioctl_fsk_rx_request)
-#define HFMODEM_IOCTL_CLEARRQ         _IO('H',  3)
-#define HFMODEM_IOCTL_GETCURTIME      _IOR('H', 4, hfmodem_time_t)
-#define HFMODEM_IOCTL_WAITRQ          _IOR('H', 5, hfmodem_id_t)
-#define HFMODEM_IOCTL_MIXERPARAMS     _IOW('H', 6, struct hfmodem_ioctl_mixer_params)
-#define HFMODEM_IOCTL_SAMPLESTART     _IOW('H', 7, struct hfmodem_ioctl_sample_params)
-#define HFMODEM_IOCTL_SAMPLEFINISHED  _IO('H',  8)
-
-/* --------------------------------------------------------------------- */
-#ifdef __KERNEL__
-
-#include <linux/parport.h>
-
-#define DMA_MODE_AUTOINIT      0x10
-
-#define NR_DEVICE 1
-
-#define HFMODEM_FRAGSAMPLES (HFMODEM_SRATE/100)
-#define HFMODEM_FRAGSIZE    (HFMODEM_FRAGSAMPLES*2)
-#define HFMODEM_NUMFRAGS    8
-#define HFMODEM_EXCESSFRAGS 3
-
-#define HFMODEM_NUMRXSLOTS 20
-#define HFMODEM_NUMTXSLOTS 4
-
-#define HFMODEM_CORRELATOR_CACHE 8
-
-enum slot_st { ss_unused = 0, ss_ready, ss_oper, ss_retired };
-typedef int hfmodem_conv_t;
-
-struct hfmodem_state {
-	const struct hfmodem_scops *scops;
-
-	/* io params */
-	struct {
-		unsigned int base_addr;
-		unsigned int dma;
-		unsigned int irq;
-	} io;
-
-	struct {
-		unsigned int seriobase;
-		unsigned int pariobase;
-		unsigned int midiiobase;
-		unsigned int flags;
-		struct pardevice *pardev;
-	} ptt_out;
-
-	struct {
-		__s16 *buf;
-		unsigned int lastfrag;
-		unsigned int fragptr;
-		unsigned int last_dmaptr;
-		int ptt_frames;
-	} dma;
-
-	struct {
-		unsigned int last_tvusec;
-		unsigned long long time_cnt;
-		hfmodem_time_t lasttime;
-#ifdef __i386__
-		unsigned int starttime_lo, starttime_hi;
-#endif /* __i386__ */
-	} clk;
-
-	int active;
-	wait_queue_head_t wait;
-
-	struct {
-		__s16 *kbuf;
-		__s16 *ubuf;
-		__s16 *kptr;
-		unsigned int size;
-		int rem;
-	} sbuf;
-
-	struct {
-		hfmodem_time_t last_time; 
-		unsigned int tx_phase;
-		
-		struct hfmodem_l1_rxslot {
-			enum slot_st state;
-			hfmodem_time_t tstart, tinc;
-			hfmodem_soft_t *data;
-			hfmodem_soft_t *userdata;
-			unsigned int nbits;
-			unsigned int cntbits;
-			hfmodem_id_t id;
-			unsigned int corrlen;
-			hfmodem_conv_t scale;
-			unsigned int corr_cache;
-		} rxslots[HFMODEM_NUMRXSLOTS];
-		
-		struct hfmodem_l1_txslot {
-			enum slot_st state;
-			hfmodem_time_t tstart, tinc;
-			unsigned char *data;
-			unsigned int nbits;
-			unsigned int cntbits;
-			hfmodem_id_t id;
-			unsigned char inv;
-			unsigned int phinc;
-			unsigned int phase_incs[2];
-		} txslots[HFMODEM_NUMTXSLOTS];
-	} l1;
-};
-
-struct hfmodem_correlator_cache {
-	int refcnt;
-	int lru;
-	unsigned short phase_incs[2];
-	hfmodem_conv_t correlator[2][2][HFMODEM_MAXCORRLEN];
-};
-
-struct hfmodem_scops {
-	unsigned int extent;
-
-	void (*init)(struct hfmodem_state *dev);
-	void (*prepare_input)(struct hfmodem_state *dev);
-	void (*trigger_input)(struct hfmodem_state *dev);
-	void (*prepare_output)(struct hfmodem_state *dev);
-	void (*trigger_output)(struct hfmodem_state *dev);
-	void (*stop)(struct hfmodem_state *dev);
-	unsigned int (*intack)(struct hfmodem_state *dev);
-	void (*mixer)(struct hfmodem_state *dev, int src, int igain, int ogain);
-};
-
-/* --------------------------------------------------------------------- */
-
-extern int hfmodem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-#if LINUX_VERSION_CODE >= 0x20100
-extern unsigned int hfmodem_poll(struct file *file, poll_table *wait);
-#else
-extern int hfmodem_select(struct inode *inode, struct file *file, int sel_type, select_table *wait);
-#endif
-
-extern void hfmodem_clear_rq(struct hfmodem_state *dev);
-extern void hfmodem_input_samples(struct hfmodem_state *dev, hfmodem_time_t tstart, 
-				hfmodem_time_t tinc, __s16 *samples);
-extern int hfmodem_output_samples(struct hfmodem_state *dev, hfmodem_time_t tstart, 
-				hfmodem_time_t tinc, __s16 *samples);
-extern long hfmodem_next_tx_event(struct hfmodem_state *dev, hfmodem_time_t curr);
-extern void hfmodem_finish_pending_rx_requests(struct hfmodem_state *dev);
-extern void hfmodem_wakeup(struct hfmodem_state *dev);
-
-
-extern int hfmodem_sbcprobe(struct hfmodem_state *dev);
-extern int hfmodem_wssprobe(struct hfmodem_state *dev);
-
-extern void hfmodem_refclock_probe(void);
-extern void hfmodem_refclock_init(struct hfmodem_state *dev);
-extern hfmodem_time_t hfmodem_refclock_current(struct hfmodem_state *dev, hfmodem_time_t expected, int exp_valid);
-
-/* --------------------------------------------------------------------- */
-
-extern const char hfmodem_drvname[];
-extern const char hfmodem_drvinfo[];
-
-extern struct hfmodem_state hfmodem_state[NR_DEVICE];
-extern struct hfmodem_correlator_cache hfmodem_correlator_cache[HFMODEM_CORRELATOR_CACHE];
-
-/* --------------------------------------------------------------------- */
-#endif /* __KERNEL__ */
-/* --------------------------------------------------------------------- */
-#endif /* _HFMODEM_H */
diff -u --recursive --new-file v2.3.12/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.12/linux/include/linux/i2o.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/i2o.h	Fri Aug  6 11:16:54 1999
@@ -11,12 +11,16 @@
 #define MAX_I2O_CONTROLLERS	32
 
 
+
 #ifdef __KERNEL__   /* ioctl stuff only thing exported to users */
 
+#define I2O_MAX_MANAGERS	4
+
 /*
  *	I2O Interface Objects
  */
 
+#include <linux/config.h>
 #include <linux/notifier.h>
 #include <asm/atomic.h>
 
@@ -152,20 +156,28 @@
 	int i2oversion;		/* I2O version supported. Actually there
 				 * should be high and low version */
 	struct proc_dir_entry* proc_entry;	/* /proc dir */
-	struct i2o_driver *owner;		/* Owning device */
+
+	/* Primary user */
+	struct i2o_handler *owner;
+
+	/* Management users */
+	struct i2o_handler *managers[I2O_MAX_MANAGERS];		
+	int num_managers;
+
 	struct i2o_controller *controller;	/* Controlling IOP */
 	struct i2o_device *next;	/* Chain */
 	char dev_name[8];		/* linux /dev name if available */
 };
 
+#ifdef CONFIG_I2O_PCI_MODULE
 /*
  *	Resource data for each PCI I2O controller
  */	 	
-
 struct i2o_pci
 {
 	int irq;
 };
+#endif
 
 /*
  *	Each I2O controller has one of these objects
@@ -178,7 +190,9 @@
 	int status;				/* I2O status */
 	int i2oversion;
 	int type;
+
 #define I2O_TYPE_PCI		0x01		/* PCI I2O controller */	
+
 	struct notifier_block *event_notifer;	/* Events */
 	atomic_t users;
 	struct i2o_device *devices;		/* I2O device chain */
@@ -201,9 +215,13 @@
 	{					/* Bus information */
 		struct i2o_pci pci;
 	} bus;
-	void (*destructor)(struct i2o_controller *);			/* Bus specific destructor */
-	int (*bind)(struct i2o_controller *, struct i2o_device *);	/* Bus specific attach/detach */
+	/* Bus specific destructor */
+	void (*destructor)(struct i2o_controller *);		
+	/* Bus specific attach/detach */
+	int (*bind)(struct i2o_controller *, struct i2o_device *);	
+	/* Bus specific initiator */
 	int (*unbind)(struct i2o_controller *, struct i2o_device *);
+
 	void *page_frame;		/* Message buffers */
 	int inbound_size;		/* Inbound queue size */
 };
@@ -213,9 +231,33 @@
 	void (*reply)(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);
 	char *name;
 	int context;		/* Low 8 bits of the transaction info */
+	u32 class;			/* I2O classes that this driver handles */
 	/* User data follows */
 };
 
+#ifdef MODULE
+/*
+ * Used by bus specific modules to communicate with the core
+ *
+ * This is needed because the bus modules cannot make direct
+ * calls to the core as this results in the i2o_bus_specific_module
+ * being dependent on the core, not the otherway around.
+ * In that case, a 'modprobe i2o_lan' loads i2o_core & i2o_lan,
+ * but _not_ i2o_pci...which makes the whole thing pretty useless :)
+ *
+ */
+struct i2o_core_func_table
+{
+	int	(*install)(struct i2o_controller *);
+	int	(*activate)(struct i2o_controller *);
+	struct i2o_controller*	
+		(*find)(int);
+	void	(*unlock)(struct i2o_controller *);
+	void	(*run_queue)(struct i2o_controller *c);
+	int	(*delete)(struct i2o_controller *);
+};
+#endif
+
 /*
  *	Messenger inlines
  */
@@ -282,12 +324,12 @@
 
 extern int i2o_install_device(struct i2o_controller *, struct i2o_device *);
 extern int i2o_delete_device(struct i2o_device *);
-extern int i2o_claim_device(struct i2o_device *, struct i2o_driver *);
-extern int i2o_release_device(struct i2o_device *);
+extern int i2o_claim_device(struct i2o_device *, struct i2o_handler *, u32);
+extern int i2o_release_device(struct i2o_device *, struct i2o_handler *, u32);
 
 extern int i2o_post_this(struct i2o_controller *, int, u32 *, int);
 extern int i2o_post_wait(struct i2o_controller *, int, u32 *, int, int *, int);
-extern int i2o_issue_claim(struct i2o_controller *, int, int, int, int *);
+extern int i2o_issue_claim(struct i2o_controller *, int, int, int, int *, u32);
 
 extern int i2o_query_scalar(struct i2o_controller *, int, int, int, int, 
 			void *, int, int *);
@@ -559,6 +601,12 @@
 #define I2O_DSC_UNSUPPORTED_VERSION            0x001A
 #define I2O_DSC_DEVICE_BUSY                    0x001B
 #define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
+
+/* Device Claim Types */
+#define	I2O_CLAIM_PRIMARY						0x01000000
+#define	I2O_CLAIM_MANAGEMENT					0x02000000
+#define	I2O_CLAIM_AUTHORIZED					0x03000000
+#define	I2O_CLAIM_SECONDARY					0x04000000
  
 /* Message header defines for VersionOffset */
 #define I2OVER15	0x0001
diff -u --recursive --new-file v2.3.12/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.12/linux/include/linux/ide.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/ide.h	Mon Aug  9 12:42:26 1999
@@ -1,7 +1,7 @@
 #ifndef _IDE_H
 #define _IDE_H
 /*
- *  linux/drivers/block/ide.h
+ *  linux/include/linux/ide.h
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors
  */
@@ -318,7 +318,8 @@
 typedef enum {	ide_dma_read,	ide_dma_write,		ide_dma_begin,
 		ide_dma_end,	ide_dma_check,		ide_dma_on,
 		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
-		ide_dma_bad_drive,			ide_dma_good_drive
+		ide_dma_bad_drive,			ide_dma_good_drive,
+		ide_dma_lostirq,			ide_dma_timeout
 	} ide_dma_action_t;
 
 typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
@@ -757,6 +758,12 @@
 #endif
 #if MAX_HWIFS > 7
 void do_ide7_request (void);
+#endif
+#if MAX_HWIFS > 8
+void do_ide8_request (void);
+#endif
+#if MAX_HWIFS > 9
+void do_ide9_request (void);
 #endif
 void ide_init_subdrivers (void);
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/if_ppp.h linux/include/linux/if_ppp.h
--- v2.3.12/linux/include/linux/if_ppp.h	Tue Apr 27 00:38:28 1999
+++ linux/include/linux/if_ppp.h	Fri Aug  6 10:44:11 1999
@@ -21,7 +21,7 @@
  */
 
 /*
- *  ==FILEVERSION 990331==
+ *  ==FILEVERSION 990806==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the above date.
@@ -41,8 +41,6 @@
 
 #define	PPP_MTU		1500	/* Default MTU (size of Info field) */
 #define PPP_MAXMRU	65000	/* Largest MRU we allow */
-#define PPP_VERSION	"2.3.7"
-#define PPP_MAGIC	0x5002	/* Magic value for the ppp structure */
 #define PROTO_IPX	0x002b	/* protocol numbers */
 #define PROTO_DNA_RT    0x0027  /* DNA Routing */
 
@@ -60,6 +58,8 @@
 #define SC_CCP_OPEN	0x00000040	/* Look at CCP packets */
 #define SC_CCP_UP	0x00000080	/* May send/recv compressed packets */
 #define SC_ENABLE_IP	0x00000100	/* IP packets may be exchanged */
+#define SC_LOOP_TRAFFIC	0x00000200	/* send traffic to pppd */
+#define SC_MULTILINK	0x00000400	/* do multilink encapsulation */
 #define SC_COMP_RUN	0x00001000	/* compressor has been inited */
 #define SC_DECOMP_RUN	0x00002000	/* decompressor has been inited */
 #define SC_DEBUG	0x00010000	/* enable debug messages */
@@ -68,7 +68,7 @@
 #define SC_LOG_RAWIN	0x00080000	/* log all chars received */
 #define SC_LOG_FLUSH	0x00100000	/* log all chars flushed */
 #define	SC_SYNC		0x00200000	/* synchronous serial mode */
-#define	SC_MASK		0x0f2000ff	/* bits that user can change */
+#define	SC_MASK		0x0f200fff	/* bits that user can change */
 
 /* state bits */
 #define SC_XMIT_BUSY	0x10000000	/* (used by isdn_ppp?) */
@@ -131,6 +131,9 @@
 #define PPPIOCGDEBUG	_IOR('t', 65, int)	/* Read debug level */
 #define PPPIOCSDEBUG	_IOW('t', 64, int)	/* Set debug level */
 #define PPPIOCGIDLE	_IOR('t', 63, struct ppp_idle) /* get idle time */
+#define PPPIOCNEWUNIT	_IOWR('t', 62, int)	/* create new ppp unit */
+#define PPPIOCATTACH	_IOW('t', 61, int)	/* attach to ppp unit */
+#define PPPIOCDETACH	_IOW('t', 60, int)	/* detach from ppp unit */
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
 #define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)	/* NEVER change this!! */
diff -u --recursive --new-file v2.3.12/linux/include/linux/if_pppvar.h linux/include/linux/if_pppvar.h
--- v2.3.12/linux/include/linux/if_pppvar.h	Wed May 12 08:41:15 1999
+++ linux/include/linux/if_pppvar.h	Fri Aug  6 10:44:11 1999
@@ -42,7 +42,7 @@
  */
 
 /*
- *  ==FILEVERSION 990325==
+ *  ==FILEVERSION 990806==
  *
  *  NOTE TO MAINTAINERS:
  *   If you modify this file at all, please set the above date.
@@ -133,3 +133,6 @@
 	/* tty output buffer */
 	unsigned char	obuf[OBUFSIZE];	/* buffer for characters to send */
 };
+
+#define PPP_MAGIC	0x5002
+#define PPP_VERSION	"2.3.7"
diff -u --recursive --new-file v2.3.12/linux/include/linux/if_shaper.h linux/include/linux/if_shaper.h
--- v2.3.12/linux/include/linux/if_shaper.h	Wed May 12 13:27:37 1999
+++ linux/include/linux/if_shaper.h	Thu Aug  5 14:35:52 1999
@@ -23,7 +23,8 @@
 	__u32 shapeclock;
 	__u32 recovery;		/* Time we can next clock a packet out on
 				   an empty queue */
-	unsigned long locked;
+        unsigned long locked;
+        struct net_device_stats stats;
 	struct device *dev;
 	int  (*hard_start_xmit) (struct sk_buff *skb,
 		struct device *dev);
diff -u --recursive --new-file v2.3.12/linux/include/linux/init.h linux/include/linux/init.h
--- v2.3.12/linux/include/linux/init.h	Sun Dec 27 23:08:10 1998
+++ linux/include/linux/init.h	Fri Aug  6 11:56:54 1999
@@ -48,18 +48,83 @@
  */
 
 #ifndef MODULE
-#include <asm/init.h>
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Used for initialization calls..
+ */
+typedef int (*initcall_t)(void);
+
+extern initcall_t __initcall_start, __initcall_end;
+
+#define __initcall(fn)								\
+	static initcall_t __initcall_##fn __init_call = fn
+
+/*
+ * Used for kernel command line parameter setup
+ */
+struct kernel_param {
+	const char *str;
+	int (*setup_func)(char *);
+};
+
+extern struct kernel_param __setup_start, __setup_end;
+
+#define __setup(str, fn)								\
+	static char __setup_str_##fn[] __initdata = str;				\
+	static struct kernel_param __setup_##fn __initsetup = { __setup_str_##fn, fn }
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Mark functions and data as being only used at initialization
+ * or exit time.
+ */
+#define __init		__attribute__ ((__section__ (".text.init")))
+#define __exit		__attribute__ ((unused, __section__(".text.init")))
+#define __initdata	__attribute__ ((__section__ (".data.init")))
+#define __exitdata	__attribute__ ((unused, __section__ (".data.init")))
+#define __initsetup	__attribute__ ((unused,__section__ (".setup.init")))
+#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
+
+#define __initfunc(__arginit) \
+	__arginit __init; \
+	__arginit
+
+/* For assembly routines */
+#define __INIT		.section	".text.init","ax"
+#define __FINIT		.previous
+#define __INITDATA	.section	".data.init","aw"
+
+#define module_init(x)	__initcall(x);
+#define module_exit(x)	/* nothing */
+
 #else
+
 #define __init
+#define __exit
 #define __initdata
+#define __exitdata
 #define __initfunc(__arginit) __arginit
+#define __initcall
 /* For assembly routines */
 #define __INIT
 #define __FINIT
 #define __INITDATA
+
+/* Not sure what version aliases were introduced in, but certainly in 2.95.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define module_init(x)	int init_module(void) __attribute__((alias(#x)));
+#define module_exit(x)	void cleanup_module(void) __attribute__((alias(#x)));
+#else
+#define module_init(x)	int init_module(void) { return x(); }
+#define module_exit(x)	void cleanup_module(void) { x(); }
+#endif
+
 #endif
 
-#if __GNUC__ >= 2 && __GNUC_MINOR__ >= 8
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
 #define __initlocaldata  __initdata
 #else
 #define __initlocaldata
diff -u --recursive --new-file v2.3.12/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v2.3.12/linux/include/linux/ioport.h	Wed Jul 21 15:46:48 1999
+++ linux/include/linux/ioport.h	Thu Aug  5 16:33:50 1999
@@ -19,11 +19,20 @@
 	struct resource *parent, *sibling, *child;
 };
 
+/*
+ * PCI-like IO resources have these defined flags.
+ * The low four bits come directly from the PCI specs,
+ * the rest are extended sw flags..
+ */
+#define IORESOURCE_IOPORT	0x01	/* 0 - memory mapped, 1 - IO ports */
+#define IORESOURCE_MEMTYPE_MASK	0x06	/* PCI-specific mapping info */
+#define IORESOURCE_PREFETCH	0x08	/* No side effects */
+#define IORESOURCE_BUSY		0x10	/* Driver uses this resource */
+
 /* PC/ISA/whatever - the normal PC address spaces: IO and memory */
 extern struct resource ioport_resource;
 extern struct resource iomem_resource;
 
-extern void reserve_setup(char *str, int *ints);
 extern int get_resource_list(struct resource *, char *buf, int size);
 
 extern int request_resource(struct resource *root, struct resource *new);
diff -u --recursive --new-file v2.3.12/linux/include/linux/isicom.h linux/include/linux/isicom.h
--- v2.3.12/linux/include/linux/isicom.h	Wed May 12 13:27:37 1999
+++ linux/include/linux/isicom.h	Thu Aug  5 14:34:01 1999
@@ -52,6 +52,13 @@
 #define		ISICOM_NAME	"ISICom"
 
 /*
+ *      PCI definitions
+ */
+
+ #define        DEVID_COUNT     9
+ #define        VENDOR_ID       0x10b5
+
+/*
  *	These are now officially allocated numbers
  */
 
@@ -129,6 +136,7 @@
 	unsigned short		shift_count;
 	struct isi_port		* ports;
 	signed char		count;
+	unsigned char		isa;
 };
 
 struct	isi_port {
@@ -166,7 +174,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr.\n");
@@ -186,7 +194,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr.\n");
@@ -205,7 +213,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in raise_rts.\n");
@@ -224,7 +232,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in drop_rts.\n");
@@ -243,7 +251,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr_rts.\n");
@@ -262,7 +270,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr_rts.\n");
@@ -282,7 +290,7 @@
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
 	unsigned char channel = port->channel;
-	short wait=300;
+	short wait=400;
 	while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
 	if (wait <= 0) {
 		printk(KERN_WARNING "ISICOM: Card found busy in kill_queue.\n");
diff -u --recursive --new-file v2.3.12/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.3.12/linux/include/linux/kernel.h	Tue May 25 14:55:05 1999
+++ linux/include/linux/kernel.h	Fri Aug  6 11:43:09 1999
@@ -21,6 +21,8 @@
 
 #define STACK_MAGIC	0xdeadbeef
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
 #define	KERN_EMERG	"<0>"	/* system is unusable			*/
 #define	KERN_ALERT	"<1>"	/* action must be taken immediately	*/
 #define	KERN_CRIT	"<2>"	/* critical conditions			*/
@@ -49,6 +51,8 @@
 extern long simple_strtol(const char *,char **,unsigned int);
 extern int sprintf(char * buf, const char * fmt, ...);
 extern int vsprintf(char *buf, const char *, va_list);
+extern int get_option(char **str, int *pint);
+extern char *get_options(char *str, int nints, int *ints);
 
 extern int session_of_pgrp(int pgrp);
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/logibusmouse.h linux/include/linux/logibusmouse.h
--- v2.3.12/linux/include/linux/logibusmouse.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/logibusmouse.h	Mon Aug  2 09:54:29 1999
@@ -0,0 +1,104 @@
+#ifndef _LINUX_BUSMOUSE_H
+#define _LINUX_BUSMOUSE_H
+
+/*
+ * linux/include/linux/busmouse.h: header file for Logitech Bus Mouse driver
+ * by James Banks
+ *
+ * based on information gleamed from various mouse drivers on the net
+ *
+ * Heavily modified by David giller (rafetmad@oxy.edu)
+ *
+ * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
+ * gt7080a@prism.gatech.edu (13JUL92)
+ *
+ * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
+ *
+ * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
+ *    8/28/92
+ *
+ * Microsoft Bus Mouse support folded into 0.97pl4 code
+ *    by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
+ * Changes:  Logitech and Microsoft support in the same kernel.
+ *           Defined new constants in busmouse.h for MS mice.
+ *           Added int mse_busmouse_type to distinguish busmouse types
+ *           Added a couple of new functions to handle differences in using
+ *             MS vs. Logitech (where the int variable wasn't appropriate).
+ *
+ */
+
+#define MOUSE_IRQ		5
+#define LOGITECH_BUSMOUSE       0   /* Minor device # for Logitech  */
+#define MICROSOFT_BUSMOUSE      2   /* Minor device # for Microsoft */
+
+/*--------- LOGITECH BUSMOUSE ITEMS -------------*/
+
+#define	LOGIBM_BASE		0x23c
+#define	MSE_DATA_PORT		0x23c
+#define	MSE_SIGNATURE_PORT	0x23d
+#define	MSE_CONTROL_PORT	0x23e
+#define	MSE_INTERRUPT_PORT	0x23e
+#define	MSE_CONFIG_PORT		0x23f
+#define	LOGIBM_EXTENT		0x4
+
+#define	MSE_ENABLE_INTERRUPTS	0x00
+#define	MSE_DISABLE_INTERRUPTS	0x10
+
+#define	MSE_READ_X_LOW		0x80
+#define	MSE_READ_X_HIGH		0xa0
+#define	MSE_READ_Y_LOW		0xc0
+#define	MSE_READ_Y_HIGH		0xe0
+
+/* Magic number used to check if the mouse exists */
+#define MSE_CONFIG_BYTE		0x91
+#define MSE_DEFAULT_MODE	0x90
+#define MSE_SIGNATURE_BYTE	0xa5
+
+/* useful Logitech Mouse macros */
+
+#define MSE_INT_OFF()	outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
+#define MSE_INT_ON()	outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
+
+/*--------- MICROSOFT BUSMOUSE ITEMS -------------*/
+
+#define	MSBM_BASE			0x23d
+#define	MS_MSE_DATA_PORT	        0x23d
+#define	MS_MSE_SIGNATURE_PORT	        0x23e
+#define	MS_MSE_CONTROL_PORT	        0x23c
+#define	MS_MSE_CONFIG_PORT		0x23f
+#define	MSBM_EXTENT			0x3
+
+#define	MS_MSE_ENABLE_INTERRUPTS	0x11
+#define	MS_MSE_DISABLE_INTERRUPTS	0x10
+
+#define	MS_MSE_READ_BUTTONS             0x00
+#define	MS_MSE_READ_X		        0x01
+#define	MS_MSE_READ_Y                   0x02
+
+#define MS_MSE_START                    0x80
+#define MS_MSE_COMMAND_MODE             0x07
+
+/* useful microsoft busmouse macros */
+
+#define MS_MSE_INT_OFF() {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \
+			    outb(MS_MSE_DISABLE_INTERRUPTS, MS_MSE_DATA_PORT);}
+#define MS_MSE_INT_ON()  {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \
+			    outb(MS_MSE_ENABLE_INTERRUPTS, MS_MSE_DATA_PORT);}
+
+ 
+struct mouse_status {
+	unsigned char	buttons;
+	unsigned char	latch_buttons;
+	int		dx;
+	int		dy;	
+	int 		present;
+	int		ready;
+	int		active;
+	wait_queue_head_t wait;
+	struct fasync_struct *fasyncptr;
+};
+
+/* Function Prototypes */
+
+#endif
+
diff -u --recursive --new-file v2.3.12/linux/include/linux/major.h linux/include/linux/major.h
--- v2.3.12/linux/include/linux/major.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/major.h	Thu Aug  5 18:48:45 1999
@@ -112,6 +112,8 @@
 
 #define IDE6_MAJOR	88
 #define IDE7_MAJOR	89
+#define IDE8_MAJOR	90
+#define IDE9_MAJOR	91
 
 #define AURORA_MAJOR 79
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.3.12/linux/include/linux/minix_fs.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/minix_fs.h	Mon Aug  9 12:29:00 1999
@@ -100,11 +100,11 @@
 extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev);
 extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
 			struct inode * new_dir, struct dentry *new_dentry);
-extern struct inode * minix_new_inode(const struct inode * dir);
+extern struct inode * minix_new_inode(const struct inode * dir, int * error);
 extern void minix_free_inode(struct inode * inode);
 extern unsigned long minix_count_free_inodes(struct super_block *sb);
-extern int minix_new_block(struct super_block * sb);
-extern void minix_free_block(struct super_block * sb, int block);
+extern int minix_new_block(struct inode * inode);
+extern void minix_free_block(struct inode * inode, int block);
 extern unsigned long minix_count_free_blocks(struct super_block *sb);
 
 extern int minix_bmap(struct inode *,int);
diff -u --recursive --new-file v2.3.12/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.12/linux/include/linux/mm.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/mm.h	Mon Aug  9 12:42:10 1999
@@ -152,6 +152,7 @@
 #define PG_Slab			 8
 #define PG_swap_cache		 9
 #define PG_skip			10
+#define PG_swap_entry		11
 				/* bits 21-30 unused */
 #define PG_reserved		31
 
@@ -291,8 +292,6 @@
 		clear_page(page);
 	return page;
 }
-
-extern int low_on_memory;
 
 /* memory.c & swap.c*/
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/module.h linux/include/linux/module.h
--- v2.3.12/linux/include/linux/module.h	Tue Jun 22 14:41:39 1999
+++ linux/include/linux/module.h	Mon Aug  9 12:42:01 1999
@@ -191,9 +191,10 @@
 /* Define the module variable, and usage macros.  */
 extern struct module __this_module;
 
-#define MOD_INC_USE_COUNT	__MOD_INC_USE_COUNT(&__this_module)
-#define MOD_DEC_USE_COUNT	__MOD_DEC_USE_COUNT(&__this_module)
-#define MOD_IN_USE		__MOD_IN_USE(&__this_module)
+#define THIS_MODULE		(&__this_module)
+#define MOD_INC_USE_COUNT	__MOD_INC_USE_COUNT(THIS_MODULE)
+#define MOD_DEC_USE_COUNT	__MOD_DEC_USE_COUNT(THIS_MODULE)
+#define MOD_IN_USE		__MOD_IN_USE(THIS_MODULE)
 
 #ifndef __NO_VERSION__
 #include <linux/version.h>
@@ -215,6 +216,7 @@
 
 #ifndef __GENKSYMS__
 
+#define THIS_MODULE		NULL
 #define MOD_INC_USE_COUNT	do { } while (0)
 #define MOD_DEC_USE_COUNT	do { } while (0)
 #define MOD_IN_USE		1
diff -u --recursive --new-file v2.3.12/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.3.12/linux/include/linux/msdos_fs.h	Tue Jun 22 14:43:20 1999
+++ linux/include/linux/msdos_fs.h	Mon Aug  9 12:44:01 1999
@@ -196,7 +196,7 @@
 extern void lock_fat(struct super_block *sb);
 extern void unlock_fat(struct super_block *sb);
 extern int fat_add_cluster(struct inode *inode);
-extern struct buffer_head *fat_add_cluster1(struct inode *inode);
+extern struct buffer_head *fat_extend_dir(struct inode *inode);
 extern int date_dos2unix(__u16 time, __u16 date);
 extern void fat_fs_panic(struct super_block *s,const char *msg);
 extern void fat_lock_creation(void);
@@ -225,7 +225,6 @@
 
 /* fat.c */
 extern int fat_access(struct super_block *sb,int nr,int new_value);
-extern int fat_smap(struct inode *inode,int sector);
 extern int fat_free(struct inode *inode,int skip);
 void fat_cache_inval_inode(struct inode *inode);
 void fat_cache_inval_dev(kdev_t device);
@@ -237,6 +236,7 @@
 /* inode.c */
 extern void fat_hash_init(void);
 extern int fat_bmap(struct inode *inode,int block);
+extern int fat_get_block(struct inode *, long, struct buffer_head *, int);
 extern int fat_notify_change(struct dentry *, struct iattr *);
 extern void fat_clear_inode(struct inode *inode);
 extern void fat_delete_inode(struct inode *inode);
@@ -261,6 +261,7 @@
 int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
 		  struct msdos_dir_entry **de, int *ino);
 int fat_dir_empty(struct inode *dir);
+int fat_new_dir(struct inode *inode, struct inode *parent, int is_vfat);
 
 /* file.c */
 extern struct inode_operations fat_file_inode_operations;
diff -u --recursive --new-file v2.3.12/linux/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h
--- v2.3.12/linux/include/linux/msdos_fs_i.h	Wed Jun 16 19:26:27 1999
+++ linux/include/linux/msdos_fs_i.h	Mon Aug  9 11:43:49 1999
@@ -10,12 +10,10 @@
 	int i_logstart;	/* logical first cluster */
 	int i_attrs;	/* unused attribute bits */
 	int i_ctime_ms;	/* unused change time in milliseconds */
-	int i_busy;	/* file is either deleted but still open, or
-			   inconsistent (mkdir) */
-	int i_binary;	/* file contains non-text data */
 	int i_location;	/* on-disk position of directory entry or 0 */
 	struct inode *i_fat_inode;	/* struct inode of this one */
 	struct list_head i_fat_hash;	/* hash by i_location */
+	int i_realsize;
 };
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.12/linux/include/linux/parport.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/parport.h	Mon Aug  9 12:43:06 1999
@@ -53,6 +53,7 @@
 #define PARPORT_MODE_ECP	(1<<3) /* Hardware ECP. */
 #define PARPORT_MODE_COMPAT	(1<<4) /* Hardware 'printer protocol'. */
 #define PARPORT_MODE_DMA	(1<<5) /* Hardware can DMA. */
+#define PARPORT_MODE_SAFEININT	(1<<6) /* SPP registers accessible in IRQ. */
 
 /* IEEE1284 modes: 
    Nibble mode, byte mode, ECP, ECPRLE and EPP are their own
@@ -76,6 +77,9 @@
 #define IEEE1284_ADDR			(1<<13)	/* This is a flag */
 #define IEEE1284_DATA			 0	/* So is this */
 
+/* Flags for block transfer operations. */
+#define PARPORT_EPP_FAST		(1<<0) /* Unreliable counts. */
+
 /* The rest is for the kernel only */
 #ifdef __KERNEL__
 
@@ -144,8 +148,6 @@
 	void (*data_reverse) (struct parport *);
 
 	/* For core parport code. */
-	void (*interrupt)(int, void *, struct pt_regs *);
-
 	void (*init_state)(struct pardevice *, struct parport_state *);
 	void (*save_state)(struct parport *, struct parport_state *);
 	void (*restore_state)(struct parport *, struct parport_state *);
@@ -489,7 +491,7 @@
 extern void inc_parport_count(void);
 
 /* If PC hardware is the only type supported, we can optimise a bit.  */
-#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !defined(CONFIG_PARPORT_OTHER) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE))
 #undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
 #define parport_write_data(p,x)            parport_pc_write_data(p,x)
diff -u --recursive --new-file v2.3.12/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.3.12/linux/include/linux/parport_pc.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/parport_pc.h	Mon Aug  9 12:42:16 1999
@@ -53,12 +53,16 @@
 						unsigned char mask,
 						unsigned char val)
 {
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
 	struct parport_pc_private *priv = p->physport->private_data;
 	unsigned char ctr = priv->ctr;
 	ctr = (ctr & ~mask) ^ val;
 	ctr &= priv->ctr_writable; /* only write writable bits. */
 	outb (ctr, CONTROL (p));
-	return priv->ctr = ctr; /* update soft copy */
+	return priv->ctr = ctr & wm; /* update soft copy */
 }
 
 extern __inline__ void parport_pc_data_reverse (struct parport *p)
@@ -146,5 +150,10 @@
 extern void parport_pc_inc_use_count(void);
 
 extern void parport_pc_dec_use_count(void);
+
+/* PCMCIA code will want to get us to look at a port.  Provide a mechanism. */
+extern struct parport *parport_pc_probe_port (unsigned long base,
+					      unsigned long base_hi,
+					      int irq, int dma);
 
 #endif
diff -u --recursive --new-file v2.3.12/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.12/linux/include/linux/pci.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/pci.h	Mon Aug  9 12:42:03 1999
@@ -458,13 +458,17 @@
 #define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_501		0x0406
 #define PCI_DEVICE_ID_SI_496		0x0496
+#define PCI_DEVICE_ID_SI_530		0x0530
 #define PCI_DEVICE_ID_SI_601		0x0601
+#define PCI_DEVICE_ID_SI_620		0x0620
 #define PCI_DEVICE_ID_SI_5107		0x5107
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
 #define PCI_DEVICE_ID_SI_5571		0x5571
 #define PCI_DEVICE_ID_SI_5591		0x5591
 #define PCI_DEVICE_ID_SI_5597		0x5597
+#define PCI_DEVICE_ID_SI_5600		0x5600
+#define PCI_DEVICE_ID_SI_6306		0x6306
 #define PCI_DEVICE_ID_SI_7001		0x7001
 
 #define PCI_VENDOR_ID_HP		0x103c
@@ -748,6 +752,7 @@
 
 #define PCI_VENDOR_ID_TTI		0x1103
 #define PCI_DEVICE_ID_TTI_HPT343	0x0003
+#define PCI_DEVICE_ID_TTI_HPT366	0x0004
 
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
@@ -757,16 +762,24 @@
 #define PCI_DEVICE_ID_VIA_82C585	0x0585
 #define PCI_DEVICE_ID_VIA_82C586_0	0x0586
 #define PCI_DEVICE_ID_VIA_82C595	0x0595
+#define PCI_DEVICE_ID_VIA_82C596	0x0596
 #define PCI_DEVICE_ID_VIA_82C597_0	0x0597
-#define PCI_DEVICE_ID_VIA_82C598_0      0x0598
+#define PCI_DEVICE_ID_VIA_82C598_0	0x0598
+#define PCI_DEVICE_ID_VIA_82C680	0x0680
+#define PCI_DEVICE_ID_VIA_82C686	0x0686
+#define PCI_DEVICE_ID_VIA_82C691	0x0691
+#define PCI_DEVICE_ID_VIA_82C693	0x0693
 #define PCI_DEVICE_ID_VIA_82C926	0x0926
 #define PCI_DEVICE_ID_VIA_82C416	0x1571
 #define PCI_DEVICE_ID_VIA_82C595_97	0x1595
 #define PCI_DEVICE_ID_VIA_82C586_2	0x3038
 #define PCI_DEVICE_ID_VIA_82C586_3	0x3040
+#define PCI_DEVICE_ID_VIA_82C686_4	0x3057
+#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
+#define PCI_DEVICE_ID_VIA_82C686_6	0x3068
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
 #define PCI_DEVICE_ID_VIA_82C597_1	0x8597
-#define PCI_DEVICE_ID_VIA_82C598_1      0x8598
+#define PCI_DEVICE_ID_VIA_82C598_1	0x8598
 
 #define PCI_VENDOR_ID_SMC2             0x1113
 #define PCI_DEVICE_ID_SMC2_1211TX      0x1211
@@ -948,6 +961,7 @@
 #define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
 #define PCI_DEVICE_ID_3DFX_VOODOO2	0x0002
 #define PCI_DEVICE_ID_3DFX_BANSHEE      0x0003
+#define PCI_DEVICE_ID_3DFX_VOODOO3	0x0005
 
 #define PCI_VENDOR_ID_SIGMADES		0x1236
 #define PCI_DEVICE_ID_SIGMADES_6425	0x6401
@@ -971,6 +985,9 @@
 #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
 #define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
 
+#define PCI_VENDOR_ID_ESS		0x125d
+#define PCI_DEVICE_ID_ESS_AUDIOPCI	0x1969
+
 #define PCI_VENDOR_ID_SATSAGEM		0x1267
 #define PCI_DEVICE_ID_SATSAGEM_PCR2101	0x5352
 #define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
@@ -1189,6 +1206,7 @@
 
 #include <linux/types.h>
 #include <linux/config.h>
+#include <linux/ioport.h>
 
 /*
  * There is one pci_dev structure for each slot-number/function-number
@@ -1208,6 +1226,9 @@
 	unsigned int	class;		/* 3 bytes: (base,sub,prog-if) */
 	unsigned int	hdr_type;	/* PCI header type */
 	unsigned int	master : 1;	/* set if device is master capable */
+
+	char		name[48];
+
 	/*
 	 * In theory, the irq level can be read from configuration
 	 * space and all would be fine.  However, old PCI chips don't
@@ -1224,7 +1245,7 @@
 	/* Base registers for this device, can be adjusted by
 	 * pcibios_fixup() as necessary.
 	 */
-	unsigned long	base_address[6];
+	struct resource resource[6];
 	unsigned long	rom_address;
 };
 
@@ -1289,12 +1310,9 @@
 /* Generic PCI interface functions */
 
 void pci_init(void);
-void pci_setup(char *str, int *ints);
 void pci_quirks_init(void);
 unsigned int pci_scan_bus(struct pci_bus *bus);
 struct pci_bus *pci_scan_peer_bridge(int bus);
-void pci_proc_init(void);
-void proc_old_pci_init(void);
 int get_pci_list(char *buf);
 int pci_proc_attach_device(struct pci_dev *dev);
 int pci_proc_detach_device(struct pci_dev *dev);
diff -u --recursive --new-file v2.3.12/linux/include/linux/personality.h linux/include/linux/personality.h
--- v2.3.12/linux/include/linux/personality.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/personality.h	Mon Aug  2 10:19:52 1999
@@ -27,6 +27,7 @@
 #define PER_IRIX32              (0x0009 | STICKY_TIMEOUTS) /* IRIX5 32-bit     */
 #define PER_IRIXN32             (0x000a | STICKY_TIMEOUTS) /* IRIX6 new 32-bit */
 #define PER_IRIX64              (0x000b | STICKY_TIMEOUTS) /* IRIX6 64-bit     */
+#define PER_RISCOS		(0x000c)
 
 /* Prototype for an lcall7 syscall handler. */
 typedef void (*lcall7_func)(struct pt_regs *);
diff -u --recursive --new-file v2.3.12/linux/include/linux/ppp-comp.h linux/include/linux/ppp-comp.h
--- v2.3.12/linux/include/linux/ppp-comp.h	Fri Mar 27 17:45:16 1998
+++ linux/include/linux/ppp-comp.h	Fri Aug  6 10:44:11 1999
@@ -195,4 +195,9 @@
 #define CI_PREDICTOR_2		2	/* config option for Predictor-2 */
 #define CILEN_PREDICTOR_2	2	/* length of its config option */
 
+#ifdef __KERNEL__
+extern int ppp_register_compressor(struct compressor *);
+extern void ppp_unregister_compressor(struct compressor *);
+#endif /* __KERNEL__ */
+
 #endif /* _NET_PPP_COMP_H */
diff -u --recursive --new-file v2.3.12/linux/include/linux/ppp_channel.h linux/include/linux/ppp_channel.h
--- v2.3.12/linux/include/linux/ppp_channel.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/ppp_channel.h	Fri Aug  6 10:44:11 1999
@@ -0,0 +1,62 @@
+/*
+ * Definitions for the interface between the generic PPP code
+ * and a PPP channel.
+ *
+ * A PPP channel provides a way for the generic PPP code to send
+ * and receive packets over some sort of communications medium.
+ * Packets are stored in sk_buffs and have the 2-byte PPP protocol
+ * number at the start, but not the address and control bytes.
+ *
+ * Copyright 1999 Paul Mackerras.
+ *
+ *  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.
+ *
+ * ==FILEVERSION 990717==
+ */
+
+/* $Id$ */
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+struct ppp_channel;
+
+struct ppp_channel_ops {
+	/* Send a packet (or multilink fragment) on this channel.
+	   Returns 1 if it was accepted, 0 if not. */
+	int	(*start_xmit)(struct ppp_channel *, struct sk_buff *);
+
+};
+
+struct ppp_channel {
+	void		*private;	/* channel private data */
+	struct ppp_channel_ops *ops;	/* operations for this channel */
+	int		xmit_qlen;	/* length of transmit queue (bytes) */
+	int		speed;		/* transfer rate (bytes/second) */
+	int		latency;	/* overhead time in milliseconds */
+	struct list_head list;		/* link in list of channels per unit */
+	void		*ppp;		/* opaque to channel */
+};
+
+#ifdef __KERNEL__
+/* Called by the channel when it can send some more data. */
+extern void ppp_output_wakeup(struct ppp_channel *);
+
+/* Called by the channel to process a received PPP packet.
+   The packet should have just the 2-byte PPP protocol header. */
+extern void ppp_input(struct ppp_channel *, struct sk_buff *);
+
+/* Called by the channel when an input error occurs, indicating
+   that we may have missed a packet. */
+extern void ppp_input_error(struct ppp_channel *, int code);
+
+/* Attach a channel to a given PPP unit. */
+extern int ppp_register_channel(struct ppp_channel *, int unit);
+
+/* Detach a channel from its PPP unit (e.g. on hangup). */
+extern void ppp_unregister_channel(struct ppp_channel *);
+
+#endif /* __KERNEL__ */
diff -u --recursive --new-file v2.3.12/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.12/linux/include/linux/proc_fs.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/proc_fs.h	Mon Aug  9 12:42:42 1999
@@ -231,6 +231,7 @@
 	PROC_BUS_PCI_DEVICES,
 	PROC_BUS_ZORRO,
 	PROC_BUS_ZORRO_DEVICES,
+	PROC_BUS_ECARD_DEVICES,
 	PROC_BUS_LAST
 };
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.12/linux/include/linux/sched.h	Wed Jul 28 14:47:42 1999
+++ linux/include/linux/sched.h	Mon Aug  9 12:42:10 1999
@@ -250,7 +250,7 @@
 						0-0xFFFFFFFF for kernel-thread
 					 */
 	struct exec_domain *exec_domain;
-	long need_resched;
+	volatile long need_resched;
 
 /* various fields */
 	long counter;
diff -u --recursive --new-file v2.3.12/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.3.12/linux/include/linux/slab.h	Tue Jun 22 14:41:47 1999
+++ linux/include/linux/slab.h	Mon Aug  9 12:42:12 1999
@@ -51,6 +51,7 @@
 extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
 				       void (*)(void *, kmem_cache_t *, unsigned long),
 				       void (*)(void *, kmem_cache_t *, unsigned long));
+extern int kmem_cache_destroy(kmem_cache_t *);
 extern int kmem_cache_shrink(kmem_cache_t *);
 extern void *kmem_cache_alloc(kmem_cache_t *, int);
 extern void kmem_cache_free(kmem_cache_t *, void *);
diff -u --recursive --new-file v2.3.12/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.12/linux/include/linux/swap.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/swap.h	Mon Aug  9 12:42:02 1999
@@ -100,6 +100,8 @@
 extern struct page * read_swap_cache_async(unsigned long, 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);
+
 /*
  * Make these inline later once they are working properly.
  */
diff -u --recursive --new-file v2.3.12/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.12/linux/include/linux/sysctl.h	Wed Jul 21 15:46:48 1999
+++ linux/include/linux/sysctl.h	Thu Aug  5 16:24:15 1999
@@ -78,7 +78,7 @@
 	KERN_NODENAME=7,
 	KERN_DOMAINNAME=8,
 
-	KERN_SECURELVL=14,	/* int: system security level */
+	KERN_CAP_BSET=14,	/* int: capability bounding set */
 	KERN_PANIC=15,		/* int: panic timeout */
 	KERN_REALROOTDEV=16,	/* real root device to mount after initrd */
 
@@ -100,8 +100,9 @@
 	KERN_SHMMAX=34,         /* int: Maximum shared memory segment */
 	KERN_MSGMAX=35,         /* int: Maximum size of a messege */
 	KERN_MSGMNB=36,         /* int: Maximum message queue size */
-	KERN_MSGPOOL=37,        /* int: Maximum system message pool size */
-	KERN_MAX_THREADS=38     /* int: Maximum nr of threads in the system */
+	KERN_MSGPOOL=37,         /* int: Maximum system message pool size */
+	KERN_SYSRQ=38,		/* int: Sysreq enable */
+	KERN_MAX_THREADS=39     /* int: Maximum nr of threads in the system */
 };
 
 
@@ -457,7 +458,12 @@
 
 /* /proc/sys/dev/cdrom */
 enum {
-	DEV_CDROM_INFO=1
+	DEV_CDROM_INFO=1,
+	DEV_CDROM_AUTOCLOSE=2,
+	DEV_CDROM_AUTOEJECT=3,
+	DEV_CDROM_DEBUG=4,
+	DEV_CDROM_LOCK=5,
+	DEV_CDROM_CHECK_MEDIA=6
 };
 
 /* /proc/sys/dev/parport */
@@ -508,6 +514,8 @@
 			 void *, size_t *);
 extern int proc_dointvec(ctl_table *, int, struct file *,
 			 void *, size_t *);
+extern int proc_dointvec_bset(ctl_table *, int, struct file *,
+			      void *, size_t *);
 extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
 				void *, size_t *);
 extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
diff -u --recursive --new-file v2.3.12/linux/include/linux/sysrq.h linux/include/linux/sysrq.h
--- v2.3.12/linux/include/linux/sysrq.h	Tue Jun 22 14:41:39 1999
+++ linux/include/linux/sysrq.h	Mon Aug  9 12:42:03 1999
@@ -36,3 +36,5 @@
 #else
 #define CHECK_EMERGENCY_SYNC
 #endif
+
+extern int sysrq_enabled;
diff -u --recursive --new-file v2.3.12/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v2.3.12/linux/include/linux/umsdos_fs.h	Tue Jun 22 14:43:20 1999
+++ linux/include/linux/umsdos_fs.h	Mon Aug  9 12:44:01 1999
@@ -174,10 +174,6 @@
 #endif
 
 extern struct inode_operations umsdos_dir_inode_operations;
-extern struct file_operations umsdos_file_operations;
-extern struct inode_operations umsdos_file_inode_operations;
-extern struct inode_operations umsdos_file_inode_operations_no_bmap;
-extern struct inode_operations umsdos_file_inode_operations_readpage;
 extern struct inode_operations umsdos_symlink_inode_operations;
 extern int init_umsdos_fs (void);
 
diff -u --recursive --new-file v2.3.12/linux/include/linux/yam.h linux/include/linux/yam.h
--- v2.3.12/linux/include/linux/yam.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/yam.h	Thu Aug  5 14:43:32 1999
@@ -0,0 +1,82 @@
+/*****************************************************************************/
+
+/*
+ *	yam.h  -- YAM radio modem driver.
+ *
+ *	Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr)
+ *	Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	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.
+ *
+ *  Please note that the GPL allows you to use the driver, NOT the radio.
+ *  In order to use the radio, you need a license from the communications
+ *  authority of your country.
+ *
+ *
+ */
+
+/*****************************************************************************/
+
+#define SIOCYAMRESERVED	(0)
+#define SIOCYAMSCFG 	(1)	/* Set configuration */
+#define SIOCYAMGCFG 	(2)	/* Get configuration */
+#define SIOCYAMSMCS 	(3)	/* Set mcs data */
+
+#define YAM_IOBASE   (1 << 0)
+#define YAM_IRQ      (1 << 1)
+#define YAM_BITRATE  (1 << 2) /* Bit rate of radio port ->57600 */
+#define YAM_MODE     (1 << 3) /* 0=simplex 1=duplex 2=duplex+tempo */
+#define YAM_HOLDDLY  (1 << 4) /* duplex tempo (sec) */
+#define YAM_TXDELAY  (1 << 5) /* Tx Delay (ms) */
+#define YAM_TXTAIL   (1 << 6) /* Tx Tail  (ms) */
+#define YAM_PERSIST  (1 << 7) /* Persist  (ms) */
+#define YAM_SLOTTIME (1 << 8) /* Slottime (ms) */
+#define YAM_BAUDRATE (1 << 9) /* Baud rate of rs232 port ->115200 */
+
+#define YAM_MAXBITRATE  57600
+#define YAM_MAXBAUDRATE 115200
+#define YAM_MAXMODE     2
+#define YAM_MAXHOLDDLY  99
+#define YAM_MAXTXDELAY  999
+#define YAM_MAXTXTAIL   999
+#define YAM_MAXPERSIST  255
+#define YAM_MAXSLOTTIME 999
+
+#define YAM_FPGA_SIZE	5302
+
+struct yamcfg {
+	unsigned int mask;		/* Mask of commands */
+	unsigned int iobase;	/* IO Base of COM port */
+	unsigned int irq;		/* IRQ of COM port */
+	unsigned int bitrate;	/* Bit rate of radio port */
+	unsigned int baudrate;	/* Baud rate of the RS232 port */
+	unsigned int txdelay;	/* TxDelay */
+	unsigned int txtail;	/* TxTail */
+	unsigned int persist;	/* Persistence */
+	unsigned int slottime;	/* Slottime */
+	unsigned int mode;		/* mode 0 (simp), 1(Dupl), 2(Dupl+delay) */
+	unsigned int holddly;	/* PTT delay in FullDuplex 2 mode */
+};
+
+struct yamdrv_ioctl_cfg {
+	int cmd;
+	struct yamcfg cfg;
+};
+
+struct yamdrv_ioctl_mcs {
+	int cmd;
+	int bitrate;
+	unsigned char bits[YAM_FPGA_SIZE];
+};
diff -u --recursive --new-file v2.3.12/linux/init/main.c linux/init/main.c
--- v2.3.12/linux/init/main.c	Wed Jul 28 14:47:42 1999
+++ linux/init/main.c	Fri Aug  6 10:49:54 1999
@@ -68,9 +68,6 @@
 extern int console_loglevel;
 
 static int init(void *);
-extern int bdflush(void *);
-extern int kswapd(void *);
-extern void kswapd_setup(void);
 
 extern void init_IRQ(void);
 extern void init_modules(void);
@@ -84,8 +81,6 @@
 extern void filescache_init(void);
 extern void signals_init(void);
 
-extern void device_setup(void);
-extern void binfmt_setup(void);
 extern void free_initmem(void);
 extern void filesystem_setup(void);
 
@@ -93,250 +88,6 @@
 extern void ecard_init(void);
 #endif
 
-extern void smp_setup(char *str, int *ints);
-#ifdef __i386__
-extern void ioapic_pirq_setup(char *str, int *ints);
-extern void ioapic_setup(char *str, int *ints);
-#endif
-extern void no_scroll(char *str, int *ints);
-extern void kbd_reset_setup(char *str, int *ints);
-extern void panic_setup(char *str, int *ints);
-extern void bmouse_setup(char *str, int *ints);
-extern void msmouse_setup(char *str, int *ints);
-extern void console_setup(char *str, int *ints);
-#ifdef CONFIG_PRINTER
-extern void lp_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_AMIGA
-extern void js_am_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_ANALOG
-extern void js_an_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_ASSASIN
-extern void js_as_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_CONSOLE
-extern void js_console_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_DB9
-extern void js_db9_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_TURBOGRAFX
-extern void js_tg_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_JOY_LIGHTNING
-extern void js_l4_setup(char *str, int *ints);
-#endif
-extern void eth_setup(char *str, int *ints);
-#ifdef CONFIG_ARCNET_COM20020
-extern void com20020_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ARCNET_RIM_I
-extern void arcrimi_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ARCNET_COM90xxIO
-extern void com90io_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ARCNET_COM90xx
-extern void com90xx_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_DECNET
-extern void decnet_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_BLK_DEV_XD
-extern void xd_setup(char *str, int *ints);
-extern void xd_manual_geo_init(char *str, int *ints);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE
-extern void ide_setup(char *);
-#endif
-#ifdef CONFIG_PARIDE_PD
-extern void pd_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_PARIDE_PF
-extern void pf_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_PARIDE_PT
-extern void pt_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_PARIDE_PG
-extern void pg_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_PARIDE_PCD
-extern void pcd_setup(char *str, int *ints);
-#endif
-extern void floppy_setup(char *str, int *ints);
-extern void st_setup(char *str, int *ints);
-extern void st0x_setup(char *str, int *ints);
-extern void advansys_setup(char *str, int *ints);
-extern void tmc8xx_setup(char *str, int *ints);
-extern void t128_setup(char *str, int *ints);
-extern void pas16_setup(char *str, int *ints);
-extern void generic_NCR5380_setup(char *str, int *intr);
-extern void generic_NCR53C400_setup(char *str, int *intr);
-extern void generic_NCR53C400A_setup(char *str, int *intr);
-extern void generic_DTC3181E_setup(char *str, int *intr);
-extern void aha152x_setup(char *str, int *ints);
-extern void aha1542_setup(char *str, int *ints);
-extern void gdth_setup(char *str, int *ints);
-extern void aic7xxx_setup(char *str, int *ints);
-extern void AM53C974_setup(char *str, int *ints);
-extern void BusLogic_Setup(char *str, int *ints);
-extern void ncr53c8xx_setup(char *str, int *ints);
-extern void sym53c8xx_setup(char *str, int *ints);
-extern void eata2x_setup(char *str, int *ints);
-extern void u14_34f_setup(char *str, int *ints);
-extern void fdomain_setup(char *str, int *ints);
-extern void ibmmca_scsi_setup(char *str, int *ints);
-extern void fd_mcs_setup(char *str, int *ints);
-extern void in2000_setup(char *str, int *ints);
-extern void NCR53c406a_setup(char *str, int *ints);
-extern void sym53c416_setup(char *str, int *ints);
-extern void wd7000_setup(char *str, int *ints);
-extern void dc390_setup(char* str, int *ints);
-extern void scsi_luns_setup(char *str, int *ints);
-extern void scsi_logging_setup(char *str, int *ints);
-extern void sound_setup(char *str, int *ints);
-extern void reboot_setup(char *str, int *ints);
-extern void video_setup(char *str, int *ints);
-#ifdef CONFIG_CDU31A
-extern void cdu31a_setup(char *str, int *ints);
-#endif CONFIG_CDU31A
-#ifdef CONFIG_BLK_DEV_PS2
-extern void ed_setup(char *str, int *ints);
-extern void tp720_setup(char *str, int *ints);
-#endif CONFIG_BLK_DEV_PS2
-#ifdef CONFIG_MCD
-extern void mcd_setup(char *str, int *ints);
-#endif CONFIG_MCD
-#ifdef CONFIG_MCDX
-extern void mcdx_setup(char *str, int *ints);
-#endif CONFIG_MCDX
-#ifdef CONFIG_SBPCD
-extern void sbpcd_setup(char *str, int *ints);
-#endif CONFIG_SBPCD
-#ifdef CONFIG_AZTCD
-extern void aztcd_setup(char *str, int *ints);
-#endif CONFIG_AZTCD
-#ifdef CONFIG_CDU535
-extern void sonycd535_setup(char *str, int *ints);
-#endif CONFIG_CDU535
-#ifdef CONFIG_GSCD
-extern void gscd_setup(char *str, int *ints);
-#endif CONFIG_GSCD
-#ifdef CONFIG_CM206
-extern void cm206_setup(char *str, int *ints);
-#endif CONFIG_CM206
-#ifdef CONFIG_OPTCD
-extern void optcd_setup(char *str, int *ints);
-#endif CONFIG_OPTCD
-#ifdef CONFIG_SJCD
-extern void sjcd_setup(char *str, int *ints);
-#endif CONFIG_SJCD
-#ifdef CONFIG_ISP16_CDI
-extern void isp16_setup(char *str, int *ints);
-#endif CONFIG_ISP16_CDI
-#ifdef CONFIG_BLK_DEV_RAM
-static void ramdisk_start_setup(char *str, int *ints);
-static void load_ramdisk(char *str, int *ints);
-static void prompt_ramdisk(char *str, int *ints);
-static void ramdisk_size(char *str, int *ints);
-#ifdef CONFIG_BLK_DEV_INITRD
-static void no_initrd(char *s,int *ints);
-#endif
-#endif CONFIG_BLK_DEV_RAM
-#ifdef CONFIG_ISDN_DRV_ICN
-extern void icn_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ISDN_DRV_HISAX
-extern void HiSax_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_DIGIEPCA
-extern void epca_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ISDN_DRV_PCBIT
-extern void pcbit_setup(char *str, int *ints);
-#endif
-
-#ifdef CONFIG_ATARIMOUSE
-extern void atari_mouse_setup (char *str, int *ints);
-#endif
-#ifdef CONFIG_DMASOUND
-extern void dmasound_setup (char *str, int *ints);
-#endif
-#ifdef CONFIG_ATARI_SCSI
-extern void atari_scsi_setup (char *str, int *ints);
-#endif
-extern void stram_swap_setup (char *str, int *ints);
-extern void wd33c93_setup (char *str, int *ints);
-extern void gvp11_setup (char *str, int *ints);
-extern void ncr53c7xx_setup (char *str, int *ints);
-#ifdef CONFIG_MAC_SCSI
-extern void mac_scsi_setup (char *str, int *ints);
-#endif
-
-#ifdef CONFIG_CYCLADES
-extern void cy_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_DIGI
-extern void pcxx_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_RISCOM8
-extern void riscom8_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_SPECIALIX
-extern void specialix_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_DMASCC
-extern void dmascc_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_BAYCOM_PAR
-extern void baycom_par_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_BAYCOM_SER_FDX
-extern void baycom_ser_fdx_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_BAYCOM_SER_HDX
-extern void baycom_ser_hdx_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_SOUNDMODEM
-extern void sm_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ADBMOUSE
-extern void adb_mouse_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_WDT
-extern void wdt_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_PARPORT
-extern void parport_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_PLIP
-extern void plip_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_HFMODEM
-extern void hfmodem_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_IP_PNP
-extern void ip_auto_config_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_ROOT_NFS
-extern void nfs_root_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_FTAPE
-extern void ftape_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_MDA_CONSOLE
-extern void mdacon_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_LTPC
-extern void ltpc_setup(char *str, int *ints);
-#endif
-#ifdef CONFIG_BLK_CPQ_DA
-extern void cpqarray_setup(char *str, int *ints);
-#endif
-
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
@@ -344,10 +95,6 @@
 extern void dquot_init_hash(void);
 #endif
 
-#ifdef CONFIG_MD_BOOT
-extern void md_setup(char *str,int *ints) __init;
-#endif
-
 /*
  * Boot command-line arguments
  */
@@ -361,15 +108,9 @@
 
 int rows, cols;
 
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load 2 = dual disk */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_size;		/* Size of the ramdisk(s) */
-extern int rd_image_start;	/* starting block # of image */
 #ifdef CONFIG_BLK_DEV_INITRD
 kdev_t real_root_dev;
 #endif
-#endif
 
 int root_mountflags = MS_RDONLY;
 char *execute_command = NULL;
@@ -377,37 +118,59 @@
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 
-char *get_options(char *str, int *ints)
+/*
+ * Read an int from an option string; if available accept a subsequent
+ * comma as well.
+ *
+ * Return values:
+ * 0 : no int in string
+ * 1 : int found, no subsequent comma
+ * 2 : int found including a subsequent comma
+ */
+int get_option(char **str, int *pint)
 {
-	char *cur = str;
-	int i=1;
+    char *cur = *str;
 
-	while (cur && (*cur=='-' || isdigit(*cur)) && i <= 10) {
-		ints[i++] = simple_strtol(cur,NULL,0);
-		if ((cur = strchr(cur,',')) != NULL)
-			cur++;
-	}
+    if (!cur || !(*cur)) return 0;
+    *pint = simple_strtol(cur,str,0);
+    if (cur==*str) return 0;
+    if (**str==',') {
+        (*str)++;
+        return 2;
+    }
+
+    return 1;
+}
+
+char *get_options(char *str, int nints, int *ints)
+{
+	int res,i=1;
+
+    while (i<nints) {
+        res = get_option(&str, ints+i);
+        if (res==0) break;
+        i++;
+        if (res==1) break;
+    }
 	ints[0] = i-1;
-	return(cur);
+	return(str);
 }
 
-static void __init profile_setup(char *str, int *ints)
+static int __init profile_setup(char *str)
 {
-	if (ints[0] > 0)
-		prof_shift = (unsigned long) ints[1];
-	else
-		prof_shift = 2;
+    int par;
+    if (get_option(&str,&par)) prof_shift = par;
+	return 1;
 }
 
+__setup("profile=", profile_setup);
+
 
 static struct dev_name_struct {
 	const char *name;
 	const int num;
 } root_dev_names[] __initdata = {
-#ifdef CONFIG_ROOT_NFS
 	{ "nfs",     0x00ff },
-#endif
-#ifdef CONFIG_BLK_DEV_IDE
 	{ "hda",     0x0300 },
 	{ "hdb",     0x0340 },
 	{ "hdc",     0x1600 },
@@ -424,8 +187,10 @@
 	{ "hdn",     0x5840 },
 	{ "hdo",     0x5900 },
 	{ "hdp",     0x5940 },
-#endif
-#ifdef CONFIG_BLK_DEV_SD
+	{ "hdq",     0x5A00 },
+	{ "hdr",     0x5A40 },
+	{ "hds",     0x5B00 },
+	{ "hdt",     0x5B40 },
 	{ "sda",     0x0800 },
 	{ "sdb",     0x0810 },
 	{ "sdc",     0x0820 },
@@ -442,71 +207,34 @@
 	{ "sdn",     0x08d0 },
 	{ "sdo",     0x08e0 },
 	{ "sdp",     0x08f0 },
-#endif
-#ifdef CONFIG_ATARI_ACSI
 	{ "ada",     0x1c00 },
 	{ "adb",     0x1c10 },
 	{ "adc",     0x1c20 },
 	{ "add",     0x1c30 },
 	{ "ade",     0x1c40 },
-#endif
-#ifdef CONFIG_BLK_DEV_FD
 	{ "fd",      0x0200 },
-#endif
-#ifdef CONFIG_MD_BOOT
 	{ "md",      0x0900 },	     
-#endif     
-#ifdef CONFIG_BLK_DEV_XD
 	{ "xda",     0x0d00 },
 	{ "xdb",     0x0d40 },
-#endif
-#ifdef CONFIG_BLK_DEV_RAM
 	{ "ram",     0x0100 },
-#endif
-#ifdef CONFIG_BLK_DEV_SR
 	{ "scd",     0x0b00 },
-#endif
-#ifdef CONFIG_MCD
 	{ "mcd",     0x1700 },
-#endif
-#ifdef CONFIG_CDU535
 	{ "cdu535",  0x1800 },
 	{ "sonycd",  0x1800 },
-#endif
-#ifdef CONFIG_AZTCD
 	{ "aztcd",   0x1d00 },
-#endif
-#ifdef CONFIG_CM206
 	{ "cm206cd", 0x2000 },
-#endif
-#ifdef CONFIG_GSCD
 	{ "gscd",    0x1000 },
-#endif
-#ifdef CONFIG_SBPCD
 	{ "sbpcd",   0x1900 },
-#endif
-#ifdef CONFIG_BLK_DEV_PS2
 	{ "eda",     0x2400 },
 	{ "edb",     0x2440 },
-#endif
-#ifdef CONFIG_PARIDE_PD
 	{ "pda",	0x2d00 },
 	{ "pdb",	0x2d10 },
 	{ "pdc",	0x2d20 },
 	{ "pdd",	0x2d30 },
-#endif
-#ifdef CONFIG_PARIDE_PCD
 	{ "pcd",	0x2e00 },
-#endif
-#ifdef CONFIG_PARIDE_PF
 	{ "pf",		0x2f00 },
-#endif
-#if CONFIG_APBLOCK
 	{ "apblock", APBLOCK_MAJOR << 8},
-#endif
-#if CONFIG_DDV
 	{ "ddv", DDV_MAJOR << 8},
-#endif
 	{ NULL, 0 }
 };
 
@@ -529,440 +257,27 @@
 	return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
 }
 
-static void __init root_dev_setup(char *line, int *num)
+static int __init root_dev_setup(char *line)
 {
 	ROOT_DEV = name_to_kdev_t(line);
+	return 1;
 }
 
-/*
- * List of kernel command line parameters. The first table lists parameters
- * which are subject to values parsing (leading numbers are converted to
- * an array of ints and chopped off the string), the second table contains
- * the few exceptions which obey their own syntax rules.
- */
-
-struct kernel_param {
-	const char *str;
-	void (*setup_func)(char *, int *);
-};
-
-static struct kernel_param cooked_params[] __initdata = {
-/* FIXME: make PNP just become reserve_setup */
-#ifndef CONFIG_KERNEL_PNP_RESOURCE
-	{ "reserve=", reserve_setup },
-#else
-	{ "reserve=", pnp_reserve_setup },
-#endif
-	{ "profile=", profile_setup },
-#ifdef __SMP__
-	{ "nosmp", smp_setup },
-	{ "maxcpus=", smp_setup },
-#ifdef CONFIG_X86_IO_APIC
-	{ "noapic", ioapic_setup },
-	{ "pirq=", ioapic_pirq_setup },
-#endif
-#endif
-#ifdef CONFIG_BLK_DEV_RAM
-	{ "ramdisk_start=", ramdisk_start_setup },
-	{ "load_ramdisk=", load_ramdisk },
-	{ "prompt_ramdisk=", prompt_ramdisk },
-	{ "ramdisk=", ramdisk_size },
-	{ "ramdisk_size=", ramdisk_size },
-#ifdef CONFIG_BLK_DEV_INITRD
-	{ "noinitrd", no_initrd },
-#endif
-#endif
-#ifdef CONFIG_FB
-	{ "video=", video_setup },
-#endif
-	{ "panic=", panic_setup },
-	{ "console=", console_setup },
-#ifdef CONFIG_VGA_CONSOLE
-	{ "no-scroll", no_scroll },
-#endif
-#ifdef CONFIG_MDA_CONSOLE
-	{ "mdacon=", mdacon_setup },
-#endif
-#ifdef CONFIG_VT
-	{ "kbd-reset", kbd_reset_setup },
-#endif
-#ifdef CONFIG_BUGi386
-	{ "no-hlt", no_halt },
-	{ "no387", no_387 },
-	{ "reboot=", reboot_setup },
-	{ "mca-pentium", mca_pentium },
-#endif
-#ifdef CONFIG_INET
-	{ "ether=", eth_setup },
-#endif
-#ifdef CONFIG_ARCNET_COM20020
-	{ "com20020=", com20020_setup },
-#endif
-#ifdef CONFIG_ARCNET_RIM_I
-	{ "arcrimi=", arcrimi_setup },
-#endif
-#ifdef CONFIG_ARCNET_COM90xxIO
-	{ "com90io=", com90io_setup },
-#endif
-#ifdef CONFIG_ARCNET_COM90xx
-	{ "com90xx=", com90xx_setup },
-#endif
-#ifdef CONFIG_DECNET
-	{ "decnet=", decnet_setup },
-#endif
-#ifdef CONFIG_PRINTER
-        { "lp=", lp_setup },
-#endif
-#ifdef CONFIG_JOY_AMIGA
-	{ "js_am=", js_am_setup },
-#endif
-#ifdef CONFIG_JOY_ANALOG
-	{ "js_an=", js_an_setup },
-#endif
-#ifdef CONFIG_JOY_ASSASIN
-	{ "js_as=", js_as_setup },
-#endif
-#ifdef CONFIG_JOY_CONSOLE
-	{ "js_console=", js_console_setup },
-	{ "js_console2=", js_console_setup },
-	{ "js_console3=", js_console_setup },
-#endif
-#ifdef CONFIG_JOY_DB9
-	{ "js_db9=", js_db9_setup },
-	{ "js_db9_2=", js_db9_setup },
-	{ "js_db9_3=", js_db9_setup },
-#endif
-#ifdef CONFIG_JOY_TURBOGRAFX
-	{ "js_tg=", js_tg_setup },
-	{ "js_tg_2=", js_tg_setup },
-	{ "js_tg_3=", js_tg_setup },
-#endif
-#ifdef CONFIG_SCSI
-	{ "max_scsi_luns=", scsi_luns_setup },
-	{ "scsi_logging=", scsi_logging_setup },
-#endif
-#ifdef CONFIG_JOY_LIGHTNING
-	{ "js_l4=", js_l4_setup },
-#endif
-#ifdef CONFIG_SCSI_ADVANSYS
-	{ "advansys=", advansys_setup },
-#endif
-#if defined(CONFIG_BLK_DEV_HD)
-	{ "hd=", hd_setup },
-#endif
-#ifdef CONFIG_CHR_DEV_ST
-	{ "st=", st_setup },
-#endif
-#ifdef CONFIG_BUSMOUSE
-	{ "bmouse=", bmouse_setup },
-#endif
-#ifdef CONFIG_MS_BUSMOUSE
-	{ "msmouse=", msmouse_setup },
-#endif
-#ifdef CONFIG_SCSI_SEAGATE
-	{ "st0x=", st0x_setup },
-	{ "tmc8xx=", tmc8xx_setup },
-#endif
-#ifdef CONFIG_SCSI_T128
-	{ "t128=", t128_setup },
-#endif
-#ifdef CONFIG_SCSI_PAS16
-	{ "pas16=", pas16_setup },
-#endif
-#ifdef CONFIG_SCSI_GENERIC_NCR5380
-	{ "ncr5380=", generic_NCR5380_setup },
-	{ "ncr53c400=", generic_NCR53C400_setup },
-	{ "ncr53c400a=", generic_NCR53C400A_setup },
-	{ "dtc3181e=", generic_DTC3181E_setup },
-#endif
-#ifdef CONFIG_SCSI_AHA152X
-	{ "aha152x=", aha152x_setup},
-#endif
-#ifdef CONFIG_SCSI_AHA1542
-	{ "aha1542=", aha1542_setup},
-#endif
-#ifdef CONFIG_SCSI_GDTH
-	{ "gdth=", gdth_setup},
-#endif
-#ifdef CONFIG_SCSI_AIC7XXX
-	{ "aic7xxx=", aic7xxx_setup},
-#endif
-#ifdef CONFIG_SCSI_BUSLOGIC
-	{ "BusLogic=", BusLogic_Setup},
-#endif
-#ifdef CONFIG_SCSI_NCR53C8XX
-	{ "ncr53c8xx=", ncr53c8xx_setup},
-#endif
-#ifdef CONFIG_SCSI_SYM53C8XX
-	{ "sym53c8xx=", sym53c8xx_setup},
-#endif
-#ifdef CONFIG_SCSI_EATA
-	{ "eata=", eata2x_setup},
-#endif
-#ifdef CONFIG_SCSI_U14_34F
-	{ "u14-34f=", u14_34f_setup},
-#endif
-#ifdef CONFIG_SCSI_AM53C974
-        { "AM53C974=", AM53C974_setup},
-#endif
-#ifdef CONFIG_SCSI_NCR53C406A
-	{ "ncr53c406a=", NCR53c406a_setup},
-#endif
-#ifdef CONFIG_SCSI_SYM53C416
-	{ "sym53c416=", sym53c416_setup},
-#endif
-#ifdef CONFIG_SCSI_FUTURE_DOMAIN
-	{ "fdomain=", fdomain_setup},
-#endif
-#ifdef CONFIG_SCSI_IN2000
-	{ "in2000=", in2000_setup},
-#endif
-#ifdef CONFIG_SCSI_7000FASST
-	{ "wd7000=", wd7000_setup},
-#endif
-#ifdef CONFIG_SCSI_IBMMCA
-        { "ibmmcascsi=", ibmmca_scsi_setup },
-#endif
-#ifdef CONFIG_SCSI_FD_MCS
-	{ "fd_mcs=", fd_mcs_setup },
-#endif
-#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP)
-        { "tmscsim=", dc390_setup },
-#endif
-#ifdef CONFIG_BLK_DEV_XD
-	{ "xd=", xd_setup },
-	{ "xd_geo=", xd_manual_geo_init },
-#endif
-#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
-	{ "floppy=", floppy_setup },
-#endif
-#ifdef CONFIG_BLK_DEV_PS2
-	{ "eda=", ed_setup },
-	{ "edb=", ed_setup },
-	{ "tp720=", tp720_setup },
-#endif
-#ifdef CONFIG_CDU31A
-	{ "cdu31a=", cdu31a_setup },
-#endif CONFIG_CDU31A
-#ifdef CONFIG_MCD
-	{ "mcd=", mcd_setup },
-#endif CONFIG_MCD
-#ifdef CONFIG_MCDX
-	{ "mcdx=", mcdx_setup },
-#endif CONFIG_MCDX
-#ifdef CONFIG_SBPCD
-	{ "sbpcd=", sbpcd_setup },
-#endif CONFIG_SBPCD
-#ifdef CONFIG_AZTCD
-	{ "aztcd=", aztcd_setup },
-#endif CONFIG_AZTCD
-#ifdef CONFIG_CDU535
-	{ "sonycd535=", sonycd535_setup },
-#endif CONFIG_CDU535
-#ifdef CONFIG_GSCD
-	{ "gscd=", gscd_setup },
-#endif CONFIG_GSCD
-#ifdef CONFIG_CM206
-	{ "cm206=", cm206_setup },
-#endif CONFIG_CM206
-#ifdef CONFIG_OPTCD
-	{ "optcd=", optcd_setup },
-#endif CONFIG_OPTCD
-#ifdef CONFIG_SJCD
-	{ "sjcd=", sjcd_setup },
-#endif CONFIG_SJCD
-#ifdef CONFIG_ISP16_CDI
-	{ "isp16=", isp16_setup },
-#endif CONFIG_ISP16_CDI
-#ifdef CONFIG_SOUND_OSS
-	{ "sound=", sound_setup },
-#endif
-#ifdef CONFIG_ISDN_DRV_ICN
-	{ "icn=", icn_setup },
-#endif
-#ifdef CONFIG_ISDN_DRV_HISAX
-       { "hisax=", HiSax_setup },
-       { "HiSax=", HiSax_setup },
-#endif
-#ifdef CONFIG_ISDN_DRV_PCBIT
-	{ "pcbit=", pcbit_setup },
-#endif
-#ifdef CONFIG_ATARIMOUSE
-	{ "atamouse=", atari_mouse_setup },
-#endif
-#ifdef CONFIG_DMASOUND
-	{ "dmasound=", dmasound_setup },
-#endif
-#ifdef CONFIG_ATARI_SCSI
-	{ "atascsi=", atari_scsi_setup },
-#endif
-#ifdef CONFIG_STRAM_SWAP
-	{ "stram_swap=", stram_swap_setup },
-#endif
-#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) \
-	    || defined(CONFIG_A4091_SCSI) || defined(CONFIG_MVME16x_SCSI) \
-	    || defined(CONFIG_BVME6000_SCSI) \
-	    || defined(CONFIG_BLZ603EPLUS_SCSI)
-        { "53c7xx=", ncr53c7xx_setup },
-#endif
-#if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
-	    || defined(CONFIG_GVP11_SCSI)
-	{ "wd33c93=", wd33c93_setup },
-#endif
-#if defined(CONFIG_GVP11_SCSI)
-	{ "gvp11=", gvp11_setup },
-#endif
-#ifdef CONFIG_MAC_SCSI
-	{ "mac5380=", mac_scsi_setup },
-#endif
-#ifdef CONFIG_CYCLADES
-	{ "cyclades=", cy_setup },
-#endif
-#ifdef CONFIG_DIGI
-	{ "digi=", pcxx_setup },
-#endif
-#ifdef CONFIG_DIGIEPCA
-	{ "digiepca=", epca_setup },
-#endif
-#ifdef CONFIG_RISCOM8
-	{ "riscom8=", riscom8_setup },
-#endif
-#ifdef CONFIG_DMASCC
-	{ "dmascc=", dmascc_setup },
-#endif
-#ifdef CONFIG_SPECIALIX
-	{ "specialix=", specialix_setup },
-#endif
-#ifdef CONFIG_BAYCOM_PAR
-	{ "baycom_par=", baycom_par_setup },
-#endif
-#ifdef CONFIG_BAYCOM_SER_FDX
-	{ "baycom_ser_fdx=", baycom_ser_fdx_setup },
-#endif
-#ifdef CONFIG_BAYCOM_SER_HDX
-	{ "baycom_ser_hdx=", baycom_ser_hdx_setup },
-#endif
-#ifdef CONFIG_SOUNDMODEM
-	{ "soundmodem=", sm_setup },
-#endif
-#ifdef CONFIG_WDT
-	{ "wdt=", wdt_setup },
-#endif
-#ifdef CONFIG_PARPORT
-	{ "parport=", parport_setup },
-#endif
-#ifdef CONFIG_PLIP
-	{ "plip=", plip_setup },
-#endif
-#ifdef CONFIG_HFMODEM
-	{ "hfmodem=", hfmodem_setup },
-#endif
-#ifdef CONFIG_FTAPE
-	{ "ftape=", ftape_setup},
-#endif
-#ifdef CONFIG_MD_BOOT
-	{ "md=", md_setup},
-#endif
-#ifdef CONFIG_ADBMOUSE
-	{ "adb_buttons=", adb_mouse_setup },
-#endif
-#ifdef CONFIG_LTPC
-	{ "ltpc=", ltpc_setup },
-#endif
-#ifdef CONFIG_BLK_CPQ_DA
-	{ "smart2=", cpqarray_setup },
-#endif
-	{ 0, 0 }
-};
-
-static struct kernel_param raw_params[] __initdata = {
-	{ "root=", root_dev_setup },
-#ifdef CONFIG_ROOT_NFS
-	{ "nfsroot=", nfs_root_setup },
-	{ "nfsaddrs=", ip_auto_config_setup },
-#endif
-#ifdef CONFIG_IP_PNP
-	{ "ip=", ip_auto_config_setup },
-#endif
-#ifdef CONFIG_PCI
-	{ "pci=", pci_setup },
-#endif
-#ifdef CONFIG_PARIDE_PD
-	{ "pd.", pd_setup },
-#endif
-#ifdef CONFIG_PARIDE_PCD
-	{ "pcd.", pcd_setup },
-#endif
-#ifdef CONFIG_PARIDE_PF
-	{ "pf.", pf_setup },
-#endif
-#ifdef CONFIG_PARIDE_PT
-        { "pt.", pt_setup },
-#endif
-#ifdef CONFIG_PARIDE_PG
-        { "pg.", pg_setup },
-#endif
-#ifdef CONFIG_APM
-	{ "apm=", apm_setup },
-#endif
-	{ 0, 0 }
-};
-
-#ifdef CONFIG_BLK_DEV_RAM
-static void __init ramdisk_start_setup(char *str, int *ints)
-{
-   if (ints[0] > 0 && ints[1] >= 0)
-      rd_image_start = ints[1];
-}
-
-static void __init load_ramdisk(char *str, int *ints)
-{
-   if (ints[0] > 0 && ints[1] >= 0)
-      rd_doload = ints[1] & 3;
-}
-
-static void __init prompt_ramdisk(char *str, int *ints)
-{
-   if (ints[0] > 0 && ints[1] >= 0)
-      rd_prompt = ints[1] & 1;
-}
-
-static void __init ramdisk_size(char *str, int *ints)
-{
-	if (ints[0] > 0 && ints[1] >= 0)
-		rd_size = ints[1];
-}
-#endif
+__setup("root=", root_dev_setup);
 
 static int __init checksetup(char *line)
 {
-	int i, ints[11];
+	struct kernel_param *p;
 
-#ifdef CONFIG_BLK_DEV_IDE
-	/* ide driver needs the basic string, rather than pre-processed values */
-	if (!strncmp(line,"ide",3) ||
-#ifdef CONFIG_BLK_DEV_VIA82C586
-	    !strncmp(line,"splitfifo",9) ||
-#endif /* CONFIG_BLK_DEV_VIA82C586 */
-	    (!strncmp(line,"hd",2) && line[2] != '=')) {
-		ide_setup(line);
-		return 1;
-	}
-#endif
-	for (i=0; raw_params[i].str; i++) {
-		int n = strlen(raw_params[i].str);
-		if (!strncmp(line,raw_params[i].str,n)) {
-			raw_params[i].setup_func(line+n, NULL);
-			return 1;
-		}
-	}
-	for (i=0; cooked_params[i].str; i++) {
-		int n = strlen(cooked_params[i].str);
-		if (!strncmp(line,cooked_params[i].str,n)) {
-			cooked_params[i].setup_func(get_options(line+n, ints), ints);
-			return 1;
+	p = &__setup_start;
+	do {
+		int n = strlen(p->str);
+		if (!strncmp(line,p->str,n)) {
+			if (p->setup_func(line+n))
+				return 1;
 		}
-	}
+		p++;
+	} while (p < &__setup_end);
 	return 0;
 }
 
@@ -1018,6 +333,34 @@
 		((loops_per_sec+2500)/5000) % 100);
 }
 
+static int __init readonly(char *str)
+{
+	if (*str)
+		return 0;
+	root_mountflags |= MS_RDONLY;
+	return 1;
+}
+
+static int __init readwrite(char *str)
+{
+	if (*str)
+		return 0;
+	root_mountflags &= ~MS_RDONLY;
+	return 1;
+}
+
+static int __init debug_kernel(char *str)
+{
+	if (*str)
+		return 0;
+	console_loglevel = 10;
+	return 1;
+}
+
+__setup("ro", readonly);
+__setup("rw", readwrite);
+__setup("debug", debug_kernel);
+
 /*
  * This is a simple kernel command line parsing function: it parses
  * the command line, and fills in the arguments/environment to init
@@ -1040,21 +383,6 @@
 	while ((line = next) != NULL) {
 		if ((next = strchr(line,' ')) != NULL)
 			*next++ = 0;
-		/*
-		 * check for kernel options first..
-		 */
-		if (!strcmp(line,"ro")) {
-			root_mountflags |= MS_RDONLY;
-			continue;
-		}
-		if (!strcmp(line,"rw")) {
-			root_mountflags &= ~MS_RDONLY;
-			continue;
-		}
-		if (!strcmp(line,"debug")) {
-			console_loglevel = 10;
-			continue;
-		}
 		if (!strncmp(line,"init=",5)) {
 			line += 5;
 			execute_command = line;
@@ -1089,29 +417,14 @@
 
 
 extern void setup_arch(char **, unsigned long *, unsigned long *);
+extern void cpu_idle(void);
 
 #ifndef __SMP__
 
-/*
- *	Uniprocessor idle thread
- */
- 
-int cpu_idle(void *unused)
-{
-	for(;;)
-		idle();
-}
-
 #define smp_init()	do { } while (0)
 
 #else
 
-/*
- *	Multiprocessor idle thread is in arch/...
- */
- 
-extern int cpu_idle(void * unused);
-
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
@@ -1216,7 +529,7 @@
 	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	unlock_kernel();
 	current->need_resched = 1;
- 	cpu_idle(NULL);
+ 	cpu_idle();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -1232,14 +545,29 @@
 	return execve(shell, argv, envp_init);
 }
 
-static void __init no_initrd(char *s,int *ints)
+static int __init no_initrd(char *s)
 {
 	mount_initrd = 0;
+	return 1;
 }
+
+__setup("noinitrd", no_initrd);
+
 #endif
 
 struct task_struct *child_reaper = &init_task;
 
+static void __init do_initcalls(void)
+{
+	initcall_t *call;
+
+	call = &__initcall_start;
+	do {
+		(*call)();
+		call++;
+	} while (call < &__initcall_end);
+}
+
 /*
  * Ok, the machine is now initialized. None of the devices
  * have been touched yet, but the CPU subsystem is up and
@@ -1308,19 +636,7 @@
 	/* Networking initialization needs a process context */ 
 	sock_init();
 
-	/* Launch bdflush from here, instead of the old syscall way. */
-	kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-	/* Start the background pageout daemon. */
-	kswapd_setup();
-	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
-#if CONFIG_AP1000
-	/* Start the async paging daemon. */
-	{
-	  extern int asyncd(void *);	 
-	  kernel_thread(asyncd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-	}
-#endif
+	do_initcalls();
 
 #ifdef CONFIG_BLK_DEV_INITRD
 
@@ -1329,12 +645,6 @@
 	if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
 	else mount_initrd =0;
 #endif
-
-	/* Set up devices .. */
-	device_setup();
-
-	/* .. executable formats .. */
-	binfmt_setup();
 
 	/* .. filesystems .. */
 	filesystem_setup();
diff -u --recursive --new-file v2.3.12/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.12/linux/ipc/shm.c	Wed Jul 21 15:46:48 1999
+++ linux/ipc/shm.c	Mon Aug  2 10:16:41 1999
@@ -687,9 +687,9 @@
 		--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)));
 	unlock_kernel();
 	current->min_flt++;
-	get_page(mem_map + MAP_NR(pte_page(pte)));
 	return pte_page(pte);
 
 changed:
diff -u --recursive --new-file v2.3.12/linux/kernel/capability.c linux/kernel/capability.c
--- v2.3.12/linux/kernel/capability.c	Fri Nov 20 11:43:19 1998
+++ linux/kernel/capability.c	Thu Aug  5 14:43:32 1999
@@ -17,6 +17,8 @@
  * uninteresting and/or not to be changed.
  */
 
+kernel_cap_t cap_bset = CAP_FULL_SET;
+
 asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
 {
      int error, pid;
diff -u --recursive --new-file v2.3.12/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.12/linux/kernel/exit.c	Wed Jul 28 14:47:42 1999
+++ linux/kernel/exit.c	Thu Jul 29 13:40:13 1999
@@ -255,7 +255,7 @@
 	current->mm = mm;
 	if (mm != active_mm) {
 		current->active_mm = mm;
-		switch_mm(active_mm, mm, current->processor);
+		activate_mm(active_mm, mm);
 	}
 	mmdrop(active_mm);
 }
diff -u --recursive --new-file v2.3.12/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.12/linux/kernel/fork.c	Wed Jul 28 14:47:42 1999
+++ linux/kernel/fork.c	Mon Aug  2 22:07:16 1999
@@ -321,6 +321,7 @@
 {
 	if (mm == &init_mm) BUG();
 	pgd_free(mm->pgd);
+	destroy_context(mm);
 	kmem_cache_free(mm_cachep, mm);
 }
 
diff -u --recursive --new-file v2.3.12/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.12/linux/kernel/ksyms.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/ksyms.c	Mon Aug  9 11:43:49 1999
@@ -39,6 +39,7 @@
 #include <linux/console.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
+#include <linux/capability.h>
 
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
@@ -47,7 +48,6 @@
 #include <linux/kmod.h>
 #endif
 
-extern char *get_options(char *str, int *ints);
 extern void set_device_ro(kdev_t dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
 extern int blkdev_release(struct inode * inode);
@@ -77,6 +77,7 @@
 #ifdef CONFIG_MODULES
 EXPORT_SYMBOL(get_module_symbol);
 #endif
+EXPORT_SYMBOL(get_option);
 EXPORT_SYMBOL(get_options);
 
 /* process memory management */
@@ -94,6 +95,7 @@
 EXPORT_SYMBOL(__free_page);
 EXPORT_SYMBOL(kmem_find_general_cachep);
 EXPORT_SYMBOL(kmem_cache_create);
+EXPORT_SYMBOL(kmem_cache_destroy);
 EXPORT_SYMBOL(kmem_cache_shrink);
 EXPORT_SYMBOL(kmem_cache_alloc);
 EXPORT_SYMBOL(kmem_cache_free);
@@ -109,6 +111,7 @@
 EXPORT_SYMBOL(vmtruncate);
 EXPORT_SYMBOL(find_vma);
 EXPORT_SYMBOL(get_unmapped_area);
+EXPORT_SYMBOL(init_mm);
 
 /* filesystem internal functions */
 EXPORT_SYMBOL(in_group_p);
@@ -167,10 +170,12 @@
 EXPORT_SYMBOL(block_read_full_page);
 EXPORT_SYMBOL(block_write_full_page);
 EXPORT_SYMBOL(block_write_partial_page);
+EXPORT_SYMBOL(block_write_cont_page);
 EXPORT_SYMBOL(block_flushpage);
 EXPORT_SYMBOL(generic_file_read);
 EXPORT_SYMBOL(generic_file_write);
 EXPORT_SYMBOL(generic_file_mmap);
+EXPORT_SYMBOL(generic_buffer_fdatasync);
 EXPORT_SYMBOL(page_hash_bits);
 EXPORT_SYMBOL(page_hash_table);
 EXPORT_SYMBOL(file_lock_table);
@@ -354,6 +359,7 @@
 EXPORT_SYMBOL(secure_tcp_sequence_number);
 EXPORT_SYMBOL(get_random_bytes);
 EXPORT_SYMBOL(securebits);
+EXPORT_SYMBOL(cap_bset);
 
 /* Program loader interfaces */
 EXPORT_SYMBOL(setup_arg_pages);
diff -u --recursive --new-file v2.3.12/linux/kernel/module.c linux/kernel/module.c
--- v2.3.12/linux/kernel/module.c	Sun Dec 27 10:41:41 1998
+++ linux/kernel/module.c	Thu Jul 29 13:37:22 1999
@@ -76,10 +76,6 @@
 	unsigned long page;
 	long retval;
 
-	if ((unsigned long)user_name >= TASK_SIZE
-	    && !segment_eq(get_fs (), KERNEL_DS))
-		return -EFAULT;
-
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
diff -u --recursive --new-file v2.3.12/linux/kernel/panic.c linux/kernel/panic.c
--- v2.3.12/linux/kernel/panic.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/panic.c	Mon Aug  2 16:38:02 1999
@@ -25,11 +25,13 @@
 
 int panic_timeout = 0;
 
-void __init panic_setup(char *str, int *ints)
+static int __init panic_setup(char *str)
 {
-	if (ints[0] == 1)
-		panic_timeout = ints[1];
+	panic_timeout = simple_strtoul(str, NULL, 0);
+	return 1;
 }
+
+__setup("panic=", panic_setup);
 
 NORET_TYPE void panic(const char * fmt, ...)
 {
diff -u --recursive --new-file v2.3.12/linux/kernel/printk.c linux/kernel/printk.c
--- v2.3.12/linux/kernel/printk.c	Tue May 11 14:37:40 1999
+++ linux/kernel/printk.c	Wed Aug  4 15:55:31 1999
@@ -50,7 +50,7 @@
 /*
  *	Setup a list of consoles. Called from init/main.c
  */
-void __init console_setup(char *str, int *ints)
+static int __init console_setup(char *str)
 {
 	struct console_cmdline *c;
 	char name[sizeof(c->name)];
@@ -88,17 +88,19 @@
 		if (strcmp(console_cmdline[i].name, name) == 0 &&
 			  console_cmdline[i].index == idx) {
 				preferred_console = i;
-				return;
+				return 1;
 		}
 	if (i == MAX_CMDLINECONSOLES)
-		return;
+		return 1;
 	preferred_console = i;
 	c = &console_cmdline[i];
 	memcpy(c->name, name, sizeof(c->name));
 	c->options = options;
 	c->index = idx;
+	return 1;
 }
 
+__setup("console=", console_setup);
 
 /*
  * Commands to do_syslog:
diff -u --recursive --new-file v2.3.12/linux/kernel/resource.c linux/kernel/resource.c
--- v2.3.12/linux/kernel/resource.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/resource.c	Sat Aug  7 11:08:54 1999
@@ -12,9 +12,13 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 
+#include <asm/spinlock.h>
+
 struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF };
 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF };
 
+static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
+
 /*
  * This generates reports for /proc/ioports and /proc/memory
  */
@@ -47,25 +51,30 @@
 int get_resource_list(struct resource *root, char *buf, int size)
 {
 	char *fmt;
+	int retval;
 
 	fmt = "        %08lx-%08lx : %s\n";
 	if (root == &ioport_resource)
 		fmt = "        %04lx-%04lx : %s\n";
-	return do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
+	read_lock(&resource_lock);
+	retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
+	read_unlock(&resource_lock);
+	return retval;
 }	
 
-int request_resource(struct resource *root, struct resource *new)
+/* Return the conflict entry if you can't request it */
+static struct resource * __request_resource(struct resource *root, struct resource *new)
 {
 	unsigned long start = new->start;
 	unsigned long end = new->end;
 	struct resource *tmp, **p;
 
 	if (end < start)
-		return -EINVAL;
+		return root;
 	if (start < root->start)
-		return -EINVAL;
+		return root;
 	if (end > root->end)
-		return -EINVAL;
+		return root;
 	p = &root->child;
 	for (;;) {
 		tmp = *p;
@@ -73,15 +82,25 @@
 			new->sibling = tmp;
 			*p = new;
 			new->parent = root;
-			return 0;
+			return NULL;
 		}
 		p = &tmp->sibling;
 		if (tmp->end < start)
 			continue;
-		return -EBUSY;
+		return tmp;
 	}
 }
 
+int request_resource(struct resource *root, struct resource *new)
+{
+	struct resource *conflict;
+
+	write_lock(&resource_lock);
+	conflict = __request_resource(root, new);
+	write_unlock(&resource_lock);
+	return conflict ? -EBUSY : 0;
+}
+
 int release_resource(struct resource *old)
 {
 	struct resource *tmp, **p;
@@ -101,6 +120,18 @@
 	return -EINVAL;
 }
 
+/*
+ * This is compatibility stuff for IO resources.
+ *
+ * Note how this, unlike the above, knows about
+ * the IO flag meanings (busy etc).
+ *
+ * Request-region creates a new busy region.
+ *
+ * Check-region returns non-zero if the area is already busy
+ *
+ * Release-region releases a matching busy region.
+ */
 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 {
 	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
@@ -110,21 +141,33 @@
 		res->name = name;
 		res->start = start;
 		res->end = start + n - 1;
-		if (request_resource(parent, res) != 0) {
+		res->flags = IORESOURCE_BUSY;
+
+		write_lock(&resource_lock);
+
+		for (;;) {
+			struct resource *conflict;
+
+			conflict = __request_resource(parent, res);
+			if (!conflict)
+				break;
+			if (conflict != parent) {
+				parent = conflict;
+				if (!(conflict->flags & IORESOURCE_BUSY))
+					continue;
+			}
+
+			/* Uhhuh, that didn't work out.. */
 			kfree(res);
 			res = NULL;
+			break;
 		}
+		write_unlock(&resource_lock);
 	}
 	return res;
 }
 
 /*
- * Compatibility cruft.
- *
- * Check-region returns non-zero if something already exists.
- *
- * Release-region releases an anonymous region that matches
- * the IO port range.
  */
 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
 {
@@ -152,35 +195,48 @@
 
 		if (!res)
 			break;
-		if (res->start == start && res->end == end) {
+		if (res->start <= start && res->end >= end) {
+			if (!(res->flags & IORESOURCE_BUSY)) {
+				p = &res->child;
+				continue;
+			}
+			if (res->start != start || res->end != end)
+				break;
 			*p = res->sibling;
 			kfree(res);
-			break;
+			return;
 		}
 		p = &res->sibling;
 	}
+	printk("Trying to free nonexistent resource <%04lx-%04lx>\n", start, end);
 }
 
 /*
  * Called from init/main.c to reserve IO ports.
  */
 #define MAXRESERVE 4
-void __init reserve_setup(char *str, int *ints)
+static int __init reserve_setup(char *str)
 {
-	int i;
+	int opt = 2, io_start, io_num;
 	static int reserved = 0;
 	static struct resource reserve[MAXRESERVE];
 
-	for (i = 1; i < ints[0]; i += 2) {
+    while (opt==2) {
 		int x = reserved;
+
+        if (get_option (&str, &io_start) != 2) break;
+        if (get_option (&str, &io_num)   == 0) break;
 		if (x < MAXRESERVE) {
 			struct resource *res = reserve + x;
 			res->name = "reserved";
-			res->start = ints[i];
-			res->end = res->start + ints[i] - 1;
+			res->start = io_start;
+			res->end = io_start + io_num - 1;
 			res->child = NULL;
 			if (request_resource(&ioport_resource, res) == 0)
 				reserved = x+1;
 		}
 	}
+	return 1;
 }
+
+__setup("reserve=", reserve_setup);
diff -u --recursive --new-file v2.3.12/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.12/linux/kernel/sched.c	Wed Jul 28 14:47:42 1999
+++ linux/kernel/sched.c	Tue Aug  3 08:01:29 1999
@@ -779,6 +779,7 @@
 	 * but prev is set to (the just run) 'last' process by switch_to().
 	 * This might sound slightly confusing but makes tons of sense.
 	 */
+	prepare_to_switch();
 	{
 		struct mm_struct *mm = next->mm;
 		struct mm_struct *oldmm = prev->active_mm;
@@ -788,7 +789,7 @@
 			atomic_inc(&oldmm->mm_count);
 		} else {
 			if (next->active_mm != mm) BUG();
-			switch_mm(oldmm, mm, this_cpu);
+			switch_mm(oldmm, mm, next, this_cpu);
 		}
 
 		if (!prev->mm) {
diff -u --recursive --new-file v2.3.12/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.12/linux/kernel/sysctl.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/sysctl.c	Thu Aug  5 14:49:41 1999
@@ -18,8 +18,10 @@
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
+#include <linux/capability.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/sysrq.h>
 
 #include <asm/uaccess.h>
 
@@ -166,6 +168,8 @@
 	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
+	 0600, NULL, &proc_dointvec_bset},
 #ifdef CONFIG_BLK_DEV_INITRD
 	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
 	 0644, NULL, &proc_dointvec},
@@ -208,6 +212,10 @@
 	{KERN_SHMMAX, "shmmax", &shmmax, sizeof (int),
 	 0644, NULL, &proc_dointvec},
 #endif
+#ifdef CONFIG_MAGIC_SYSRQ
+	{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
+	 0644, NULL, &proc_dointvec},
+#endif	 
 	{KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{0}
@@ -682,8 +690,13 @@
 	return r;
 }
 
+#define OP_SET	0
+#define OP_AND	1
+#define OP_OR	2
+#define OP_MAX	3
+#define OP_MIN	4
 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
-		  void *buffer, size_t *lenp, int conv)
+		  void *buffer, size_t *lenp, int conv, int op)
 {
 	int *i, vleft, first=1, len, left, neg, val;
 	#define TMPBUFLEN 20
@@ -734,7 +747,17 @@
 				val = -val;
 			buffer += len;
 			left -= len;
-			*i = val;
+			switch(op) {
+			case OP_SET:	*i = val; break;
+			case OP_AND:	*i &= val; break;
+			case OP_OR:	*i |= val; break;
+			case OP_MAX:	if(*i < val)
+						*i = val;
+					break;
+			case OP_MIN:	if(*i > val)
+						*i = val;
+					break;
+			}
 		} else {
 			p = buf;
 			if (!first)
@@ -776,9 +799,21 @@
 int proc_dointvec(ctl_table *table, int write, struct file *filp,
 		     void *buffer, size_t *lenp)
 {
-    return do_proc_dointvec(table,write,filp,buffer,lenp,1);
+    return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
+}
+
+/*
+ *	init may raise the set.
+ */
+ 
+int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
+			void *buffer, size_t *lenp)
+{
+	return do_proc_dointvec(table,write,filp,buffer,lenp,1,
+		(current->pid == 1) ? OP_SET : OP_AND);
 }
 
+
 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
@@ -881,7 +916,7 @@
 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 			  void *buffer, size_t *lenp)
 {
-    return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
+    return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
 }
 
 #else /* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.3.12/linux/lib/string.c linux/lib/string.c
--- v2.3.12/linux/lib/string.c	Thu Jul  8 15:42:21 1999
+++ linux/lib/string.c	Fri Aug  6 15:25:47 1999
@@ -366,7 +366,7 @@
 #ifndef __HAVE_ARCH_MEMCHR
 void *memchr(const void *s, int c, size_t n)
 {
-	unsigned char *p = s;
+	const unsigned char *p = s;
 	while (n-- != 0) {
         	if ((unsigned char)c == *p++) {
 			return p-1;
diff -u --recursive --new-file v2.3.12/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.12/linux/mm/filemap.c	Wed Jul 21 15:46:48 1999
+++ linux/mm/filemap.c	Mon Aug  9 11:49:24 1999
@@ -212,8 +212,6 @@
 	spin_unlock(&pagecache_lock);
 }
 
-extern atomic_t too_many_dirty_buffers;
-
 int shrink_mmap(int priority, int gfp_mask)
 {
 	static unsigned long clock = 0;
@@ -294,11 +292,15 @@
 
 		/* Is it a buffer page? */
 		if (page->buffers) {
-			int mem = page->inode ? 0 : PAGE_CACHE_SIZE;
 			spin_unlock(&pagecache_lock);
 			if (!try_to_free_buffers(page))
 				goto unlock_continue;
-			atomic_sub(mem, &buffermem);
+			/* page was locked, inode can't go away under us */
+			if (!page->inode)
+			{
+				atomic_sub(PAGE_CACHE_SIZE, &buffermem);
+				goto made_progress;
+			}
 			spin_lock(&pagecache_lock);
 		}
 
@@ -1862,21 +1864,22 @@
 
 		status = write_one_page(file, page, offset, bytes, buf);
 
+		if (status >= 0) {
+			written += status;
+			count -= status;
+			pos += status;
+			buf += status;
+			if (pos > inode->i_size)
+				inode->i_size = pos;
+		}
 		/* Mark it unlocked again and drop the page.. */
 		UnlockPage(page);
 		page_cache_release(page);
 
 		if (status < 0)
 			break;
-
-		written += status;
-		count -= status;
-		pos += status;
-		buf += status;
 	}
 	*ppos = pos;
-	if (pos > inode->i_size)
-		inode->i_size = pos;
 
 	if (page_cache)
 		page_cache_free(page_cache);
diff -u --recursive --new-file v2.3.12/linux/mm/memory.c linux/mm/memory.c
--- v2.3.12/linux/mm/memory.c	Wed Jul 28 14:47:42 1999
+++ linux/mm/memory.c	Mon Aug  9 10:27:50 1999
@@ -986,10 +986,13 @@
 
 	vma->vm_mm->rss++;
 	tsk->min_flt++;
+	lock_kernel();
 	swap_free(entry);
+	unlock_kernel();
 
 	pte = mk_pte(page_address(page), vma->vm_page_prot);
 
+	set_bit(PG_swap_entry, &page->flags);
 	if (write_access && !is_page_shared(page)) {
 		delete_from_swap_cache(page);
 		pte = pte_mkwrite(pte_mkdirty(pte));
diff -u --recursive --new-file v2.3.12/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.3.12/linux/mm/page_alloc.c	Thu Jul  8 15:42:21 1999
+++ linux/mm/page_alloc.c	Mon Aug  9 11:37:05 1999
@@ -194,8 +194,6 @@
 	set_page_count(map, 1); \
 } while (0)
 
-int low_on_memory = 0;
-
 unsigned long __get_free_pages(int gfp_mask, unsigned long order)
 {
 	unsigned long flags;
@@ -221,6 +219,7 @@
 	 */
 	if (!(current->flags & PF_MEMALLOC)) {
 		int freed;
+		static int low_on_memory = 0;
 
 		if (nr_free_pages > freepages.min) {
 			if (!low_on_memory)
diff -u --recursive --new-file v2.3.12/linux/mm/page_io.c linux/mm/page_io.c
--- v2.3.12/linux/mm/page_io.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/page_io.c	Mon Aug  9 11:43:49 1999
@@ -99,44 +99,18 @@
 	} else if (p->swap_file) {
 		struct inode *swapf = p->swap_file->d_inode;
 		int i;
-		if (swapf->i_op->get_block == NULL
-			&& swapf->i_op->smap != NULL){
-			/*
-				With MS-DOS, we use msdos_smap which returns
-				a sector number (not a cluster or block number).
-				It is a patch to enable the UMSDOS project.
-				Other people are working on better solution.
+		int j;
+		unsigned int block = offset
+			<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
 
-				It sounds like ll_rw_swap_file defined
-				its operation size (sector size) based on
-				PAGE_SIZE and the number of blocks to read.
-				So using get_block or smap should work even if
-				smap will require more blocks.
-			*/
-			int j;
-			unsigned int block = offset << 3;
-
-			for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
-				if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
-					printk("rw_swap_page: bad swap file\n");
-					return;
-				}
+		block_size = swapf->i_sb->s_blocksize;
+		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;
 			}
-			block_size = 512;
-		}else{
-			int j;
-			unsigned int block = offset
-				<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
-
-			block_size = swapf->i_sb->s_blocksize;
-			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;
-				}
-			zones_used = i;
-			dev = swapf->i_dev;
-		}
+		zones_used = i;
+		dev = swapf->i_dev;
 	} else {
 		printk(KERN_ERR "rw_swap_page: no swap file or device\n");
 		put_page(page);
diff -u --recursive --new-file v2.3.12/linux/mm/slab.c linux/mm/slab.c
--- v2.3.12/linux/mm/slab.c	Wed Jul 21 15:46:48 1999
+++ linux/mm/slab.c	Sat Aug  7 13:00:25 1999
@@ -3,6 +3,8 @@
  * Written by Mark Hemment, 1996/97.
  * (markhe@nextd.demon.co.uk)
  *
+ * kmem_cache_destroy() + some cleanup - 1999 Andrea Arcangeli
+ *
  * 11 April '97.  Started multi-threading - markhe
  *	The global cache-chain is protected by the semaphore 'cache_chain_sem'.
  *	The sem is only needed when accessing/extending the cache-chain, which
@@ -979,6 +981,59 @@
 	return cachep;
 }
 
+/*
+ * This check if the kmem_cache_t pointer is chained in the cache_cache
+ * list. -arca
+ */
+static int is_chained_kmem_cache(kmem_cache_t * cachep)
+{
+	kmem_cache_t * searchp;
+	int ret = 0;
+
+	/* Find the cache in the chain of caches. */
+	down(&cache_chain_sem);
+	for (searchp = &cache_cache; searchp->c_nextp != &cache_cache;
+	     searchp = searchp->c_nextp)
+	{
+		if (searchp->c_nextp != cachep)
+			continue;
+
+		/* Accessing clock_searchp is safe - we hold the mutex. */
+		if (cachep == clock_searchp)
+			clock_searchp = cachep->c_nextp;
+		ret = 1;
+		break;
+	}
+	up(&cache_chain_sem);
+
+	return ret;
+}
+
+/* returns 0 if every slab is been freed -arca */
+static int __kmem_cache_shrink(kmem_cache_t *cachep)
+{
+	kmem_slab_t	*slabp;
+	int	ret;
+
+	spin_lock_irq(&cachep->c_spinlock);
+
+	/* If the cache is growing, stop shrinking. */
+	while (!cachep->c_growing) {
+		slabp = cachep->c_lastp;
+		if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
+			break;
+		kmem_slab_unlink(slabp);
+		spin_unlock_irq(&cachep->c_spinlock);
+		kmem_slab_destroy(cachep, slabp);
+		spin_lock_irq(&cachep->c_spinlock);
+	}
+	ret = 1;
+	if (cachep->c_lastp == kmem_slab_end(cachep))
+		ret = 0;		/* Cache is empty. */
+	spin_unlock_irq(&cachep->c_spinlock);
+	return ret;
+}
+
 /* Shrink a cache.  Releases as many slabs as possible for a cache.
  * It is expected this function will be called by a module when it is
  * unloaded.  The cache is _not_ removed, this creates too many problems and
@@ -990,10 +1045,6 @@
 int
 kmem_cache_shrink(kmem_cache_t *cachep)
 {
-	kmem_cache_t	*searchp;
-	kmem_slab_t	*slabp;
-	int	ret;
-
 	if (!cachep) {
 		printk(KERN_ERR "kmem_shrink: NULL ptr\n");
 		return 2;
@@ -1003,43 +1054,77 @@
 		return 2;
 	}
 
+	if (!is_chained_kmem_cache(cachep))
+	{
+		printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n",
+		       cachep);
+		return 2;
+	}
+
+	return __kmem_cache_shrink(cachep);
+}
+
+/*
+ * Remove a kmem_cache_t object from the slab cache. When returns 0 it
+ * completed succesfully. -arca
+ */
+int kmem_cache_destroy(kmem_cache_t * cachep)
+{
+	kmem_cache_t * prev;
+	int ret;
+
+	if (!cachep) {
+		printk(KERN_ERR "kmem_destroy: NULL ptr\n");
+		return 1;
+	}
+	if (in_interrupt()) {
+		printk(KERN_ERR "kmem_destroy: Called during int - %s\n",
+		       cachep->c_name);
+		return 1;
+	}
+
+	ret = 0;
 	/* Find the cache in the chain of caches. */
-	down(&cache_chain_sem);		/* Semaphore is needed. */
-	searchp = &cache_cache;
-	for (;searchp->c_nextp != &cache_cache; searchp = searchp->c_nextp) {
-		if (searchp->c_nextp != cachep)
+	down(&cache_chain_sem);
+	for (prev = &cache_cache; prev->c_nextp != &cache_cache;
+	     prev = prev->c_nextp)
+	{
+		if (prev->c_nextp != cachep)
 			continue;
 
 		/* Accessing clock_searchp is safe - we hold the mutex. */
 		if (cachep == clock_searchp)
 			clock_searchp = cachep->c_nextp;
-		goto found;
+
+		/* remove the cachep from the cache_cache list. -arca */
+		prev->c_nextp = cachep->c_nextp;
+
+		ret = 1;
+		break;
 	}
 	up(&cache_chain_sem);
-	printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", cachep);
-	return 2;
-found:
-	/* Release the semaphore before getting the cache-lock.  This could
-	 * mean multiple engines are shrinking the cache, but so what.
-	 */
-	up(&cache_chain_sem);
-	spin_lock_irq(&cachep->c_spinlock);
 
-	/* If the cache is growing, stop shrinking. */
-	while (!cachep->c_growing) {
-		slabp = cachep->c_lastp;
-		if (slabp->s_inuse || slabp == kmem_slab_end(cachep))
-			break;
-		kmem_slab_unlink(slabp);
-		spin_unlock_irq(&cachep->c_spinlock);
-		kmem_slab_destroy(cachep, slabp);
-		spin_lock_irq(&cachep->c_spinlock);
+	if (!ret)
+	{
+		printk(KERN_ERR "kmem_destroy: Invalid cache addr %p\n",
+		       cachep);
+		return 1;
 	}
-	ret = 1;
-	if (cachep->c_lastp == kmem_slab_end(cachep))
-		ret--;		/* Cache is empty. */
-	spin_unlock_irq(&cachep->c_spinlock);
-	return ret;
+
+	if (__kmem_cache_shrink(cachep))
+	{
+		printk(KERN_ERR "kmem_destroy: Can't free all objects %p\n",
+		       cachep);
+		down(&cache_chain_sem);
+		cachep->c_nextp = cache_cache.c_nextp;
+		cache_cache.c_nextp = cachep;
+		up(&cache_chain_sem);
+		return 1;
+	}
+
+	kmem_cache_free(&cache_cache, cachep);
+
+	return 0;
 }
 
 /* Get the memory for a slab management obj. */
diff -u --recursive --new-file v2.3.12/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.3.12/linux/mm/swap_state.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/swap_state.c	Mon Aug  9 10:27:50 1999
@@ -274,6 +274,8 @@
 	}
 	UnlockPage(page);
 	
+	clear_bit(PG_swap_entry, &page->flags);
+
 	__free_page(page);
 }
 
diff -u --recursive --new-file v2.3.12/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.12/linux/mm/swapfile.c	Wed Jul 21 15:46:48 1999
+++ linux/mm/swapfile.c	Mon Aug  9 12:37:35 1999
@@ -126,15 +126,17 @@
 	offset = SWP_OFFSET(entry);
 	if (offset >= p->max)
 		goto bad_offset;
-	if (offset < p->lowest_bit)
-		p->lowest_bit = offset;
-	if (offset > p->highest_bit)
-		p->highest_bit = offset;
 	if (!p->swap_map[offset])
 		goto bad_free;
 	if (p->swap_map[offset] < SWAP_MAP_MAX) {
 		if (!--p->swap_map[offset])
+		{
+			if (offset < p->lowest_bit)
+				p->lowest_bit = offset;
+			if (offset > p->highest_bit)
+				p->highest_bit = offset;
 			nr_swap_pages++;
+		}
 	}
 #ifdef DEBUG_SWAP
 	printk("DebugVM: swap_free(entry %08lx, count now %d)\n",
@@ -157,6 +159,44 @@
 	goto out;
 }
 
+/* needs the big kernel lock */
+unsigned long acquire_swap_entry(struct page *page)
+{
+	struct swap_info_struct * p;
+	unsigned long offset, type;
+	unsigned long 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)
+		goto new_swap_entry;
+	type = SWP_TYPE(entry);
+	if (type & SHM_SWP_TYPE)
+		goto new_swap_entry;
+	if (type >= nr_swapfiles)
+		goto new_swap_entry;
+	p = type + swap_info;
+	if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK)
+		goto new_swap_entry;
+	offset = SWP_OFFSET(entry);
+	if (offset >= p->max)
+		goto new_swap_entry;
+	/* Has it been re-used for something else? */
+	if (p->swap_map[offset])
+		goto new_swap_entry;
+
+	/* We're cool, we can just use the old one */
+	p->swap_map[offset] = 1;
+	nr_swap_pages--;
+	return entry;
+
+new_swap_entry:
+	return get_swap_page();
+}
+
 /*
  * The swap entry has been read in advance, and we return 1 to indicate
  * that the page has been used or is no longer needed.
@@ -495,7 +535,6 @@
 	static int least_priority = 0;
 	union swap_header *swap_header = 0;
 	int swap_header_version;
-	int lock_map_size = PAGE_SIZE;
 	int nr_good_pages = 0;
 	unsigned long maxpages;
 	int swapfilesize;
@@ -664,7 +703,6 @@
 		nr_good_pages = swap_header->info.last_page -
 				swap_header->info.nr_badpages -
 				1 /* header page */;
-		lock_map_size = (p->max + 7) / 8;
 		if (error) 
 			goto bad_swap;
 	}
diff -u --recursive --new-file v2.3.12/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.12/linux/mm/vmscan.c	Wed Jul 21 15:46:48 1999
+++ linux/mm/vmscan.c	Mon Aug  9 11:37:05 1999
@@ -31,8 +31,7 @@
  * using a process that no longer actually exists (it might
  * have died while we slept).
  */
-static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
-	unsigned long address, pte_t * page_table, int gfp_mask)
+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;
@@ -47,7 +46,7 @@
 		goto out_failed;
 
 	page = mem_map + MAP_NR(page_addr);
-	spin_lock(&tsk->mm->page_table_lock);
+	spin_lock(&vma->vm_mm->page_table_lock);
 	if (pte_val(pte) != pte_val(*page_table))
 		goto out_failed_unlock;
 
@@ -55,7 +54,7 @@
 	 * Dont be too eager to get aging right if
 	 * memory is dangerously low.
 	 */
-	if (!low_on_memory && pte_young(pte)) {
+	if (pte_young(pte)) {
 		/*
 		 * Transfer the "accessed" bit from the page
 		 * tables to the global page map.
@@ -136,15 +135,16 @@
 	 */
 	flush_cache_page(vma, address);
 	if (vma->vm_ops && vma->vm_ops->swapout) {
-		pid_t pid = tsk->pid;
+		int error;
 		pte_clear(page_table);
-		spin_unlock(&tsk->mm->page_table_lock);
+		spin_unlock(&vma->vm_mm->page_table_lock);
 		flush_tlb_page(vma, address);
 		vma->vm_mm->rss--;
-		
-		if (vma->vm_ops->swapout(vma, page))
-			kill_proc(pid, SIGBUS, 1);
-		goto out_free_success;
+		error = vma->vm_ops->swapout(vma, page);
+		if (!error)
+			goto out_free_success;
+		__free_page(page);
+		return error;
 	}
 
 	/*
@@ -153,14 +153,13 @@
 	 * we have the swap cache set up to associate the
 	 * page with that swap entry.
 	 */
-	entry = get_swap_page();
+	entry = acquire_swap_entry(page);
 	if (!entry)
-		goto out_failed; /* No swap space left */
+		goto out_failed_unlock; /* No swap space left */
 		
 	vma->vm_mm->rss--;
-	tsk->nswap++;
 	set_pte(page_table, __pte(entry));
-	spin_unlock(&tsk->mm->page_table_lock);
+	spin_unlock(&vma->vm_mm->page_table_lock);
 
 	flush_tlb_page(vma, address);
 	swap_duplicate(entry);	/* One for the process, one for the swap cache */
@@ -175,7 +174,7 @@
 	__free_page(page);
 	return 1;
 out_failed_unlock:
-	spin_unlock(&tsk->mm->page_table_lock);
+	spin_unlock(&vma->vm_mm->page_table_lock);
 out_failed:
 	return 0;
 }
@@ -194,8 +193,7 @@
  * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de
  */
 
-static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
-	pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
+static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
 {
 	pte_t * pte;
 	unsigned long pmd_end;
@@ -216,8 +214,8 @@
 
 	do {
 		int result;
-		tsk->mm->swap_address = address + PAGE_SIZE;
-		result = try_to_swap_out(tsk, vma, address, pte, gfp_mask);
+		vma->vm_mm->swap_address = address + PAGE_SIZE;
+		result = try_to_swap_out(vma, address, pte, gfp_mask);
 		if (result)
 			return result;
 		address += PAGE_SIZE;
@@ -226,8 +224,7 @@
 	return 0;
 }
 
-static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
-	pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
+static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int gfp_mask)
 {
 	pmd_t * pmd;
 	unsigned long pgd_end;
@@ -247,7 +244,7 @@
 		end = pgd_end;
 	
 	do {
-		int result = swap_out_pmd(tsk, vma, pmd, address, end, gfp_mask);
+		int result = swap_out_pmd(vma, pmd, address, end, gfp_mask);
 		if (result)
 			return result;
 		address = (address + PMD_SIZE) & PMD_MASK;
@@ -256,8 +253,7 @@
 	return 0;
 }
 
-static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
-	unsigned long address, int gfp_mask)
+static int swap_out_vma(struct vm_area_struct * vma, unsigned long address, int gfp_mask)
 {
 	pgd_t *pgdir;
 	unsigned long end;
@@ -266,11 +262,11 @@
 	if (vma->vm_flags & VM_LOCKED)
 		return 0;
 
-	pgdir = pgd_offset(tsk->mm, address);
+	pgdir = pgd_offset(vma->vm_mm, address);
 
 	end = vma->vm_end;
 	while (address < end) {
-		int result = swap_out_pgd(tsk, vma, pgdir, address, end, gfp_mask);
+		int result = swap_out_pgd(vma, pgdir, address, end, gfp_mask);
 		if (result)
 			return result;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -279,7 +275,7 @@
 	return 0;
 }
 
-static int swap_out_process(struct task_struct * p, int gfp_mask)
+static int swap_out_mm(struct mm_struct * mm, int gfp_mask)
 {
 	unsigned long address;
 	struct vm_area_struct* vma;
@@ -287,18 +283,18 @@
 	/*
 	 * Go through process' page directory.
 	 */
-	address = p->mm->swap_address;
+	address = mm->swap_address;
 
 	/*
 	 * Find the proper vm-area
 	 */
-	vma = find_vma(p->mm, address);
+	vma = find_vma(mm, address);
 	if (vma) {
 		if (address < vma->vm_start)
 			address = vma->vm_start;
 
 		for (;;) {
-			int result = swap_out_vma(p, vma, address, gfp_mask);
+			int result = swap_out_vma(vma, address, gfp_mask);
 			if (result)
 				return result;
 			vma = vma->vm_next;
@@ -309,8 +305,8 @@
 	}
 
 	/* We didn't find anything for the process */
-	p->mm->swap_cnt = 0;
-	p->mm->swap_address = 0;
+	mm->swap_cnt = 0;
+	mm->swap_address = 0;
 	return 0;
 }
 
@@ -321,8 +317,8 @@
  */
 static int swap_out(unsigned int priority, int gfp_mask)
 {
-	struct task_struct * p, * pbest;
-	int counter, assign, max_cnt;
+	struct task_struct * p;
+	int counter;
 
 	/* 
 	 * We make one or two passes through the task list, indexed by 
@@ -345,36 +341,49 @@
 		counter = nr_threads;
 
 	for (; counter >= 0; counter--) {
-		assign = 0;
-		max_cnt = 0;
-		pbest = NULL;
+		int assign = 0;
+		int max_cnt = 0;
+		struct mm_struct *best = NULL;
+		int pid = 0;
 	select:
 		read_lock(&tasklist_lock);
 		p = init_task.next_task;
 		for (; p != &init_task; p = p->next_task) {
-			if (!p->swappable || !p->mm)
+			struct mm_struct *mm = p->mm;
+			if (!p->swappable || !mm)
 				continue;
-	 		if (p->mm->rss <= 0)
+	 		if (mm->rss <= 0)
 				continue;
 			/* Refresh swap_cnt? */
 			if (assign)
-				p->mm->swap_cnt = p->mm->rss;
-			if (p->mm->swap_cnt > max_cnt) {
-				max_cnt = p->mm->swap_cnt;
-				pbest = p;
+				mm->swap_cnt = mm->rss;
+			if (mm->swap_cnt > max_cnt) {
+				max_cnt = mm->swap_cnt;
+				best = mm;
+				pid = p->pid;
 			}
 		}
 		read_unlock(&tasklist_lock);
-		if (!pbest) {
+		if (!best) {
 			if (!assign) {
 				assign = 1;
 				goto select;
 			}
 			goto out;
-		}
+		} else {
+			int ret;
+
+			atomic_inc(&best->mm_count);
+			ret = swap_out_mm(best, gfp_mask);
+			mmdrop(best);
+
+			if (!ret)
+				continue;
 
-		if (swap_out_process(pbest, gfp_mask))
+			if (ret < 0)
+				kill_proc(pid, SIGBUS, 1);
 			return 1;
+		}
 	}
 out:
 	return 0;
@@ -428,27 +437,6 @@
 	return priority >= 0;
 }
 
-/*
- * Before we start the kernel thread, print out the 
- * kswapd initialization message (otherwise the init message 
- * may be printed in the middle of another driver's init 
- * message).  It looks very bad when that happens.
- */
-void __init kswapd_setup(void)
-{
-       int i;
-       char *revision="$Revision: 1.5 $", *s, *e;
-
-       swap_setup();
-       
-       if ((s = strchr(revision, ':')) &&
-           (e = strchr(s, '$')))
-               s++, i = e - s;
-       else
-               s = revision, i = -1;
-       printk ("Starting kswapd v%.*s\n", i, s);
-}
-
 static struct task_struct *kswapd_process;
 
 /*
@@ -535,4 +523,13 @@
 		retval = do_try_to_free_pages(gfp_mask);
 	return retval;
 }
-	
+
+static int __init kswapd_init(void)
+{
+	printk("Starting kswapd v1.6\n");
+	swap_setup();
+	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	return 0;
+}
+
+module_init(kswapd_init)
diff -u --recursive --new-file v2.3.12/linux/net/ax25/Config.in linux/net/ax25/Config.in
--- v2.3.12/linux/net/ax25/Config.in	Mon Feb  2 15:18:16 1998
+++ linux/net/ax25/Config.in	Wed Aug  4 09:27:34 1999
@@ -26,7 +26,6 @@
     fi
   fi
 
-  source drivers/char/hfmodem/Config.in
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.12/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.12/linux/net/core/dev.c	Wed Jun  9 14:45:36 1999
+++ linux/net/core/dev.c	Wed Aug  4 09:27:34 1999
@@ -1856,11 +1856,6 @@
 extern void sdla_setup(void);
 extern void dlci_setup(void);
 extern int dmascc_init(void);
-extern int sm_init(void);
-
-extern int baycom_ser_fdx_init(void);
-extern int baycom_ser_hdx_init(void);
-extern int baycom_par_init(void);
 
 extern int lapbeth_init(void);
 extern void arcnet_init(void);
@@ -1931,18 +1926,6 @@
 #endif
 #if defined(CONFIG_SDLA)
 	sdla_setup();
-#endif
-#if defined(CONFIG_BAYCOM_PAR)
-	baycom_par_init();
-#endif
-#if defined(CONFIG_BAYCOM_SER_FDX)
-	baycom_ser_fdx_init();
-#endif
-#if defined(CONFIG_BAYCOM_SER_HDX)
-	baycom_ser_hdx_init();
-#endif
-#if defined(CONFIG_SOUNDMODEM)
-	sm_init();
 #endif
 #if defined(CONFIG_LAPBETHER)
 	lapbeth_init();
diff -u --recursive --new-file v2.3.12/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.3.12/linux/net/ethernet/eth.c	Wed Jun  9 14:45:36 1999
+++ linux/net/ethernet/eth.c	Fri Aug  6 11:43:09 1999
@@ -60,13 +60,15 @@
 #include <asm/system.h>
 #include <asm/checksum.h>
 
-
-__initfunc(void eth_setup(char *str, int *ints))
+static int __init eth_setup(char *str)
 {
+	int ints[5];
 	struct device *d;
 
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
 	if (!str || !*str)
-		return;
+		return 0;
 
 	d = dev_base;
 	while (d) 
@@ -85,8 +87,10 @@
 		}
 		d=d->next;
 	}
+	return 1;
 }
 
+__setup("ether=", eth_setup);
 
 /*
  *	 Create the Ethernet MAC header for an arbitrary protocol layer 
diff -u --recursive --new-file v2.3.12/linux/scripts/MAKEDEV.ide linux/scripts/MAKEDEV.ide
--- v2.3.12/linux/scripts/MAKEDEV.ide	Wed Nov  6 04:49:33 1996
+++ linux/scripts/MAKEDEV.ide	Thu Aug  5 18:48:45 1999
@@ -29,6 +29,18 @@
 makedevs hdf 33 64
 makedevs hdg 34 0
 makedevs hdh 34 64
+makedevs hdi 56 0
+makedevs hdj 56 64
+makedevs hdk 57 0
+makedevs hdl 57 64
+makedevs hdm 88 0
+makedevs hdn 88 64
+makedevs hdo 89 0
+makedevs hdp 89 64
+makedevs hdq 90 0
+makedevs hdr 90 64
+makedevs hds 91 0
+makedevs hdt 91 64
 
 for tape in 0 1 2 3 4 5 6 7
 do
diff -u --recursive --new-file v2.3.12/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.3.12/linux/scripts/mkdep.c	Fri Jan  8 11:10:11 1999
+++ linux/scripts/mkdep.c	Thu Aug  5 14:43:32 1999
@@ -66,7 +66,7 @@
 	while (len_config + len > size_config) {
 		str_config = realloc(str_config, size_config *= 2);
 		if (str_config == NULL)
-			{ perror("malloc"); exit(1); }
+			{ perror("malloc config"); exit(1); }
 	}
 }
 
@@ -127,6 +127,55 @@
 
 
 /*
+ * This records all the precious .h filenames.  No need for a hash,
+ * it's a long string of values enclosed in tab and newline.
+ */
+char * str_precious  = NULL;
+int    size_precious = 0;
+int    len_precious  = 0;
+
+
+
+/*
+ * Grow the precious string to a desired length.
+ * Usually the first growth is plenty.
+ */
+void grow_precious(int len)
+{
+	if (str_precious == NULL) {
+		len_precious  = 0;
+		size_precious = 4096;
+		str_precious  = malloc(4096);
+		if (str_precious == NULL)
+			{ perror("malloc precious"); exit(1); }
+	}
+
+	while (len_precious + len > size_precious) {
+		str_precious = realloc(str_precious, size_precious *= 2);
+		if (str_precious == NULL)
+			{ perror("malloc"); exit(1); }
+	}
+}
+
+
+
+/*
+ * Add a new value to the precious string.
+ */
+void define_precious(const char * filename)
+{
+	int len = strlen(filename);
+	grow_precious(len + 4);
+	*(str_precious+len_precious++) = '\t';
+	memcpy(str_precious+len_precious, filename, len);
+	len_precious += len;
+	memcpy(str_precious+len_precious, " \\\n", 3);
+	len_precious += 3;
+}
+
+
+
+/*
  * Handle an #include line.
  */
 void handle_include(int type, const char * name, int len)
@@ -193,7 +242,7 @@
  * Thus, there is one memory access per sizeof(unsigned long) characters.
  */
 
-#if defined(__alpha__) || defined(__i386__) || defined(__arm__)
+#if defined(__alpha__) || defined(__i386__) || defined(__MIPSEL__) || defined(__arm__)
 #define LE_MACHINE
 #endif
 
@@ -458,8 +507,11 @@
 	hasdep = 0;
 	clear_config();
 	state_machine(map, map+st.st_size);
-	if (hasdep)
+	if (hasdep) {
 		puts(command);
+		if (*command)
+			define_precious(filename);
+	}
 
 	munmap(map, mapsize);
 	close(fd);
@@ -500,6 +552,10 @@
 			}
 		}
 		do_depend(filename, command);
+	}
+	if (len_precious) {
+		*(str_precious+len_precious) = '\0';
+		printf(".PRECIOUS:%s\n", str_precious);
 	}
 	return 0;
 }
